List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:November 6 2009 4:34pm
Subject:bzr commit into mysql-pe branch (alik:3667)
View as plain text  
#At file:///mnt/raid/alik/MySQL/bzr/mysql-pe/ based on revid:dao-gang.qu@strippedo8mt69oppzs9o9g9

 3667 Alexander Nozdrin	2009-11-06 [merge]
      Manual merge from mysql-6.0-codebase.

    removed:
      dbug/remove_function_from_trace.pl
      dbug/tests-t.pl
      dbug/tests.c
      include/mysql/service_my_snprintf.h
      include/mysql/service_thd_alloc.h
      include/mysql/services.h
      include/service_versions.h
      libservices/
      libservices/CMakeLists.txt
      libservices/Makefile.am
      libservices/my_snprintf_service.c
      libservices/thd_alloc_service.c
      mysql-test/t/debug_sync.test
      sql/sql_plugin_services.h
    added:
      dbug/remove_function_from_trace.pl
      dbug/tests-t.pl
      dbug/tests.c
      include/mysql/service_my_snprintf.h
      include/mysql/service_thd_alloc.h
      include/mysql/services.h
      include/service_versions.h
      libservices/
      libservices/CMakeLists.txt
      libservices/HOWTO
      libservices/Makefile.am
      libservices/my_snprintf_service.c
      libservices/thd_alloc_service.c
      mysql-test/r/partition_column.result
      mysql-test/r/partition_column_prune.result
      mysql-test/r/partition_utf8.result
      mysql-test/t/partition_column.test
      mysql-test/t/partition_column_prune.test
      mysql-test/t/partition_utf8.test
      sql/sql_plugin_services.h
      unittest/mysys/my_vsnprintf-t.c
    modified:
      BUILD/build_mccge.sh
      client/mysqlbackup.cc
      client/mysqltest.cc
      dbug/dbug.c
      include/my_dbug.h
      include/my_global.h
      include/my_sys.h
      include/mysql/plugin.h
      include/mysql/plugin.h.pp
      libmysql/libmysql.c
      mysql-test/r/partition.result
      mysql-test/r/partition_datatype.result
      mysql-test/r/partition_error.result
      mysql-test/r/partition_innodb.result
      mysql-test/r/partition_list.result
      mysql-test/r/partition_mgm_err.result
      mysql-test/r/partition_pruning.result
      mysql-test/r/partition_range.result
      mysql-test/r/type_decimal.result
      mysql-test/suite/funcs_1/r/is_columns_is.result
      mysql-test/suite/parts/inc/partition_key_32col.inc
      mysql-test/suite/parts/inc/partition_syntax.inc
      mysql-test/suite/parts/r/partition_special_innodb.result
      mysql-test/suite/parts/r/partition_special_myisam.result
      mysql-test/suite/parts/r/partition_syntax_innodb.result
      mysql-test/suite/parts/r/partition_syntax_myisam.result
      mysql-test/t/partition.test
      mysql-test/t/partition_datatype.test
      mysql-test/t/partition_error.test
      mysql-test/t/partition_innodb.test
      mysql-test/t/partition_list.test
      mysql-test/t/partition_mgm_err.test
      mysql-test/t/partition_pruning.test
      mysql-test/t/partition_range.test
      mysql-test/t/type_decimal.test
      mysys/mf_pack.c
      mysys/my_malloc.c
      mysys/my_static.c
      mysys/my_thr_init.c
      mysys/safemalloc.c
      sql/CMakeLists.txt*
      sql/backup/be_default.cc
      sql/debug_sync.cc
      sql/field.cc
      sql/ha_ndbcluster.cc
      sql/ha_ndbcluster_binlog.cc
      sql/ha_partition.cc
      sql/ha_partition.h
      sql/item_create.cc
      sql/item_timefunc.cc
      sql/item_timefunc.h
      sql/log_event.cc
      sql/mysql_priv.h
      sql/opt_range.cc
      sql/partition_element.h
      sql/partition_info.cc
      sql/partition_info.h
      sql/replication.h
      sql/share/errmsg-utf8.txt
      sql/share/errmsg.txt
      sql/slave.cc
      sql/sql_class.h
      sql/sql_lex.cc
      sql/sql_lex.h
      sql/sql_partition.cc
      sql/sql_partition.h
      sql/sql_select.cc
      sql/sql_show.cc
      sql/sql_table.cc
      sql/sql_yacc.yy
      storage/mysql_storage_engine.cmake
      strings/my_vsnprintf.c
      unittest/mysys/Makefile.am
=== modified file 'BUILD/build_mccge.sh'
--- a/BUILD/build_mccge.sh	2009-09-29 09:36:22 +0000
+++ b/BUILD/build_mccge.sh	2009-11-03 11:26:54 +0000
@@ -556,7 +556,7 @@ parse_package()
       package="pro"
       ;;
     extended )
-      package=""
+      package="extended"
       ;;
     cge )
       package="cge"
@@ -1274,7 +1274,7 @@ set_bsd_configs()
   if test "x$fast_flag" != "xno" ; then
     compiler_flags="$compiler_flags -O3"
   else
-    compiler_flags="$compiler_flags -O"
+    compiler_flags="$compiler_flags -O0"
   fi
   set_cc_and_cxx_for_gcc
 }
@@ -1305,7 +1305,7 @@ set_linux_configs()
     if test "x$fast_flag" != "xno" ; then
       compiler_flags="$compiler_flags -O2"
     else
-      compiler_flags="$compiler_flags -O"
+      compiler_flags="$compiler_flags -O0"
     fi
 # configure will set proper compiler flags for gcc on Linux
   elif test "x$compiler" = "xicc" ; then
@@ -1375,8 +1375,8 @@ set_solaris_configs()
         LDFLAGS="$LDFLAGS -O2"
         compiler_flags="$compiler_flags -O2"
       else
-        LDFLAGS="$LDFLAGS -O"
-        compiler_flags="$compiler_flags -O"
+        LDFLAGS="$LDFLAGS -O0"
+        compiler_flags="$compiler_flags -O0"
       fi
     fi
   else
@@ -1407,7 +1407,7 @@ set_solaris_configs()
       elif test "x$fast_flag" = "xgeneric" ; then
         compiler_flags="$compiler_flags -xO2"
       else
-        compiler_flags="$compiler_flags -xO"
+        compiler_flags="$compiler_flags -xO0"
       fi
     else
 #Using SPARC cpu with SunStudio (Forte) compiler
@@ -1421,7 +1421,7 @@ set_solaris_configs()
       elif test "x$fast_flag" = "xgeneric" ; then
         compiler_flags="$compiler_flags -xO2"
       else
-        compiler_flags="$compiler_flags -xO"
+        compiler_flags="$compiler_flags -xO0"
       fi
     fi
   fi
@@ -1452,7 +1452,7 @@ set_macosx_configs()
   if test "x$fast_flag" != "xno" ; then
     compiler_flags="$compiler_flags -Os"
   else
-    compiler_flags="$compiler_flags -O"
+    compiler_flags="$compiler_flags -O0"
   fi
   set_cc_and_cxx_for_gcc
 }

=== modified file 'client/mysqlbackup.cc'
--- a/client/mysqlbackup.cc	2009-10-12 09:08:34 +0000
+++ b/client/mysqlbackup.cc	2009-11-05 08:44:22 +0000
@@ -1113,7 +1113,9 @@ print_item(uint indent, struct st_bstrea
   print_item_metadata(what, type_s, name, db_name, mdata,
                       indent, &space_printed);
 
-  IF_DBUG(fflush(stdout));
+#ifndef DBUG_OFF
+  fflush(stdout);
+#endif
   DBUG_VOID_RETURN;
 }
 

=== modified file 'client/mysqltest.cc'
--- a/client/mysqltest.cc	2009-11-03 10:27:17 +0000
+++ b/client/mysqltest.cc	2009-11-06 16:34:09 +0000
@@ -1164,7 +1164,6 @@ void free_used_memory()
     mysql_server_end();
 
   /* Don't use DBUG after mysql_server_end() */
-  DBUG_VIOLATION_HELPER_LEAVE;
   return;
 }
 

=== modified file 'dbug/dbug.c'
--- a/dbug/dbug.c	2009-10-26 14:02:26 +0000
+++ b/dbug/dbug.c	2009-11-05 08:44:22 +0000
@@ -324,7 +324,7 @@ static void Indent(CODE_STATE *cs, int i
 static void DbugFlush(CODE_STATE *);
 static void DbugExit(const char *why);
 static const char *DbugStrTok(const char *s);
-static void DbugFprintf(FILE *stream, const char* format, va_list args);
+static void DbugVfprintf(FILE *stream, const char* format, va_list args);
 
 #ifndef THREAD
         /* Open profile output stream */
@@ -339,7 +339,7 @@ static unsigned long Clock(void);
  *      Miscellaneous printf format strings.
  */
 
-#define ERR_MISSING_RETURN "%s: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
+#define ERR_MISSING_RETURN "missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
 #define ERR_OPEN "%s: can't open debug output stream \"%s\": "
 #define ERR_CLOSE "%s: can't close debug file: "
 #define ERR_ABORT "%s: debugger aborting because %s\n"
@@ -1228,7 +1228,6 @@ void _db_enter_(const char *_func_, cons
  *
  */
 
-/* helper macro */
 void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
 {
   int save_errno=errno;
@@ -1236,34 +1235,29 @@ void _db_return_(uint _line_, struct _db
   CODE_STATE *cs;
   get_code_state_or_return;
 
-  if (cs->level != _slevel_)
+  if (cs->framep != _stack_frame_)
   {
-    if (!cs->locked)
-      pthread_mutex_lock(&THR_LOCK_dbug);
-    (void) fprintf(cs->stack->out_file, ERR_MISSING_RETURN, cs->process,
-                   cs->func);
-    DbugFlush(cs);
+    char buf[512];
+    my_snprintf(buf, sizeof(buf), ERR_MISSING_RETURN, cs->func);
+    DbugExit(buf);
   }
-  else
-  {
 #ifndef THREAD
-    if (DoProfile(cs))
-      (void) fprintf(cs->stack->prof_file, PROF_XFMT, Clock(), cs->func);
+  if (DoProfile(cs))
+    (void) fprintf(cs->stack->prof_file, PROF_XFMT, Clock(), cs->func);
 #endif
-    if (DoTrace(cs) & DO_TRACE)
+  if (DoTrace(cs) & DO_TRACE)
+  {
+    if ((cs->stack->flags & SANITY_CHECK_ON) &&
+        _sanity(_stack_frame_->file,_line_))
+      cs->stack->flags &= ~SANITY_CHECK_ON;
+    if (TRACING)
     {
-      if ((cs->stack->flags & SANITY_CHECK_ON) &&
-          _sanity(_stack_frame_->file,_line_))
-        cs->stack->flags &= ~SANITY_CHECK_ON;
-      if (TRACING)
-      {
-        if (!cs->locked)
-          pthread_mutex_lock(&THR_LOCK_dbug);
-        DoPrefix(cs, _line_);
-        Indent(cs, cs->level);
-        (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
-        DbugFlush(cs);
-      }
+      if (!cs->locked)
+        pthread_mutex_lock(&THR_LOCK_dbug);
+      DoPrefix(cs, _line_);
+      Indent(cs, cs->level);
+      (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
+      DbugFlush(cs);
     }
   }
   /*
@@ -1353,7 +1347,7 @@ void _db_doprnt_(const char *format,...)
     else
       (void) fprintf(cs->stack->out_file, "%s: ", cs->func);
     (void) fprintf(cs->stack->out_file, "%s: ", cs->u_keyword);
-    DbugFprintf(cs->stack->out_file, format, args);
+    DbugVfprintf(cs->stack->out_file, format, args);
     DbugFlush(cs);
     errno=save_errno;
   }
@@ -1361,10 +1355,10 @@ void _db_doprnt_(const char *format,...)
 }
 
 /*
- * fprintf clone with consistent, platform independent output for 
+ * vfprintf clone with consistent, platform independent output for 
  * problematic formats like %p, %zd and %lld.
  */
-static void DbugFprintf(FILE *stream, const char* format, va_list args)
+static void DbugVfprintf(FILE *stream, const char* format, va_list args)
 {
   char cvtbuf[1024];
   size_t len;
@@ -1388,14 +1382,13 @@ static void DbugFprintf(FILE *stream, co
  *
  *  DESCRIPTION
  *  Dump N characters in a binary array.
- *  Is used to examine corrputed memory or arrays.
+ *  Is used to examine corrupted memory or arrays.
  */
 
 void _db_dump_(uint _line_, const char *keyword,
                const unsigned char *memory, size_t length)
 {
   int pos;
-  char dbuff[90];
   CODE_STATE *cs;
   get_code_state_or_return;
 
@@ -1413,9 +1406,8 @@ void _db_dump_(uint _line_, const char *
     {
       fprintf(cs->stack->out_file, "%s: ", cs->func);
     }
-    sprintf(dbuff,"%s: Memory: 0x%lx  Bytes: (%ld)\n",
+    (void) fprintf(cs->stack->out_file, "%s: Memory: 0x%lx  Bytes: (%ld)\n",

             keyword, (ulong) memory, (long) length);
-    (void) fputs(dbuff,cs->stack->out_file);
 
     pos=0;
     while (length-- > 0)
@@ -1836,27 +1828,6 @@ BOOLEAN _db_keyword_(CODE_STATE *cs, con
 /*
  *  FUNCTION
  *
- *      _db_keywords_    test keyword formed by a set of strings for member
- *                       of keyword list
- *
- *  DESCRIPTION
- *
- *      This function is similar to _db_keyword but receives a set of strings to
- *      be concatenated in order to make the keyword to be compared.
- */
-
-BOOLEAN _db_keywords_(CODE_STATE *cs, int strict, const char *function, const char *type)
-{
-  char dest[_DBUG_MAX_FUNC_NAME_ + 1];
-
-  strxnmov(dest, _DBUG_MAX_FUNC_NAME_, function, type, NULL);
-
-  return _db_keyword_(cs, dest, strict);
-}
-
-/*
- *  FUNCTION
- *
  *      Indent    indent a line to the given indentation level
  *
  *  SYNOPSIS
@@ -2176,7 +2147,7 @@ static void DbugExit(const char *why)
   CODE_STATE *cs=code_state();
   (void) fprintf(stderr, ERR_ABORT, cs ? cs->process : "(null)", why);
   (void) fflush(stderr);
-  exit(1);
+  DBUG_ABORT();
 }
 
 

=== added file 'dbug/remove_function_from_trace.pl'
--- a/dbug/remove_function_from_trace.pl	1970-01-01 00:00:00 +0000
+++ b/dbug/remove_function_from_trace.pl	2009-10-30 18:13:58 +0000
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+
+
+die <<EEE unless @ARGV;
+Usage: $0 func1 [func2 [ ...] ]
+
+This filter (stdin->stdout) removes lines from dbug trace that were generated
+by specified functions and all functions down the call stack. Produces the
+same effect as if the original source had DBUG_PUSH(""); right after
+DBUG_ENTER() and DBUG_POP(); right before DBUG_RETURN in every such a function.
+EEE
+
+$re=join('|', @ARGV);
+$skip='';
+
+while(<STDIN>) {
+  print unless $skip;
+  next unless /^(?:.*: )*((?:\| )*)([<>])($re)\n/o;
+  if ($2 eq '>') {
+    $skip=$1.$3 unless $skip;
+    next;
+  }
+  next if $skip ne $1.$3;
+  $skip='';
+  print;
+}

=== removed file 'dbug/remove_function_from_trace.pl'
--- a/dbug/remove_function_from_trace.pl	2007-12-30 18:47:36 +0000
+++ b/dbug/remove_function_from_trace.pl	1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
-#!/usr/bin/perl
-
-
-die <<EEE unless @ARGV;
-Usage: $0 func1 [func2 [ ...] ]
-
-This filter (stdin->stdout) removes lines from dbug trace that were generated
-by specified functions and all functions down the call stack. Produces the
-same effect as if the original source had DBUG_PUSH(""); right after
-DBUG_ENTER() and DBUG_POP(); right before DBUG_RETURN in every such a function.
-EEE
-
-$re=join('|', @ARGV);
-$skip='';
-
-while(<STDIN>) {
-  print unless $skip;
-  next unless /^(?:.*: )*((?:\| )*)([<>])($re)\n/o;
-  if ($2 eq '>') {
-    $skip=$1.$3 unless $skip;
-    next;
-  }
-  next if $skip ne $1.$3;
-  $skip='';
-  print;
-}

=== added file 'dbug/tests-t.pl'
--- a/dbug/tests-t.pl	1970-01-01 00:00:00 +0000
+++ b/dbug/tests-t.pl	2009-10-30 18:13:58 +0000
@@ -0,0 +1,496 @@
+#!/usr/bin/env perl
+
+#
+#  A driver program to test DBUG features - runs tests (shell commands)
+#  from the end of file to invoke tests.c, which does the real dbug work.
+#
+
+use Test::More;
+
+$exe=$0;
+
+die unless $exe =~ s/(tests)-t(\.exe)?$/$1$2 /;
+
+# load tests
+@tests=();
+while (<DATA>) {
+  if (/^% \.\/tests /) {
+    push @tests, [ $' ]
+  } elsif (/^#/) {
+    next;
+  } else {
+    push @{$tests[$#tests]}, $_
+  }
+}
+
+plan skip_all => "because dbug is disabled" if system $exe;
+
+plan tests => scalar(@tests);
+
+for (@tests) {
+  $t=$exe . shift @$_;
+  chomp($t);
+  open F, '-|',  $t or die "open($t|): $!";
+  local $";
+  $out=join($", <F>); close(F);
+  # special cases are handled here:
+  $out =~ s/Memory: 0x[0-9A-Fa-f]+/Memory: 0x####/g if $t =~ /dump/;
+  # compare ("\n" at the beginning makes better output in case of errors)
+  is("\n$out","\n@$_", $t);
+}
+
+__DATA__
+% ./tests -#d
+func2: info: s=ok
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d
+func2: info: s=ok
+% ./tests d,ret3
+=> evaluate: OFF
+=> evaluate_if: OFF
+#
+## Testing negative lists
+#
+% ./tests d:-d,ret3
+func2: info: s=ko
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,ret3
+func2: info: s=ko
+% ./tests t:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+% ./tests t:d,info:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests t:d,info:-d,ret3:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d,info:-d,ret3:-f,func2 d,evaluate
+=> evaluate: ON
+=> evaluate_if: OFF
+% ./tests t:d,info:-d,ret3:-f,func2 d,evaluate_if
+=> evaluate: OFF
+=> evaluate_if: ON
+% ./tests t:d:-d,ret3:-f,func2 d,evaluate_if
+=> evaluate: OFF
+=> evaluate_if: ON
+% ./tests t:d:-d,ret3:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:f:-f,func2:t
+| | >func3
+| | <func3
+<main
+#
+## Adding incremental settings to the brew
+#
+% ./tests t:d:-d,ret3:-f,func2 +d,evaluate_if
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> evaluate: OFF
+=> evaluate_if: ON
+| | >func3
+| | <func3
+<main
+#
+## DBUG_DUMP
+#
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x####  Bytes: (27)
+64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A 
+74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x####  Bytes: (27)
+64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A 
+74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2:+d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x####  Bytes: (27)
+64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A 
+74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x####  Bytes: (35)
+64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 
+66 2C 66 75 6E 63 32 3A 74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+| explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:t
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P
+dbug: >main
+dbug-tests: | >func1
+dbug-tests: | | | >func3
+dbug-tests: | | | <func3

+dbug-tests: | <func1
+dbug-tests: | dump: Memory: 0x####  Bytes: (37)
+64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 
+66 2C 66 75 6E 63 32 3A 50 3A 74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+dbug-tests: | explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:P:t
+dbug-tests: | | >func3
+dbug-tests: | | <func3
+dbug-tests: <main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P:F
+dbug:        tests.c: >main
+dbug-tests:        tests.c: | >func1
+dbug-tests:        tests.c: | | | >func3
+dbug-tests:        tests.c: | | | <func3
+dbug-tests:        tests.c: | <func1
+dbug-tests:        tests.c: | dump: Memory: 0x####  Bytes: (39)
+64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 
+66 2C 66 75 6E 63 32 3A 46 3A 50 3A 74 
+=> evaluate: OFF
+=> evaluate_if: OFF
+dbug-tests:        tests.c: | explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:F:P:t
+dbug-tests:        tests.c: | | >func3
+dbug-tests:        tests.c: | | <func3
+dbug-tests:        tests.c: <main
+#
+## DBUG_EXPLAIN, DBUG_PUSH, DBUG_POP, DBUG_SET
+#
+% ./tests t:d:-d,ret3:f:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:f:-f,func2:t
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:t
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests d,info:-d,ret3:d,push
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests d,info:-d,ret3:d,push,explain
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| explain: dbug explained: d,info,push,explain:-d,ret3:t
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main

+% ./tests d,info:-d,ret3:d,explain
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain:-d,ret3
+func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,pop
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+% ./tests d,info:-d,ret3:d,explain t:d,pop
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain:-d,ret3
+func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,pop +t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain,pop:-d,ret3
+func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,set
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+       tests.c: main: explain: dbug explained: d,info,explain,set:-d,ret3:F
+       tests.c: func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,set:t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+       tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
+       tests.c: | >func2
+       tests.c: | | >func3
+       tests.c: | | <func3
+       tests.c: | | info: s=ko
+       tests.c: | <func2
+       tests.c: <main
+% ./tests t d,info:-d,ret3:d,explain,set:t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+       tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
+       tests.c: | >func2
+       tests.c: | | >func3
+       tests.c: | | <func3
+       tests.c: | | info: s=ko
+       tests.c: | <func2
+       tests.c: <main
+% ./tests t d,info:-d,ret3:d,explain,set,pop
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+% ./tests t:f,func2
+| | >func2
+| | <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| <func2
+#
+## Testing SUBDIR rules
+#
+% ./tests t:-f,func2/:d
+>main
+| >func1
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:f:-f,func2/:t
+<main
+% ./tests t:f,func1/:d
+| >func1
+| | >func2

+| | | >func3
+| | | <func3
+| | | info: s=ok
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+% ./tests t:f,main/:d,pop
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+% ./tests f,main/:d,push
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+#
+## Testing FixTraceFlags() - when we need to traverse the call stack
+# (these tests fail with FixTraceFlags() disabled)
+#
+# delete the INCLUDE rule up the stack
+% ./tests t:f,func1/ --push1=t:f,func3/
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+=> push1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+# delete the EXCLUDE rule up the stack
+% ./tests t:-f,func1/ --push1=t
+>main
+=> push1
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+# add the INCLUDE rule up the stack
+% ./tests t:f,func3 --push1=t:f,main/
+| | | >func3
+| | | <func3
+=> push1
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+# add the EXCLUDE rule up the stack
+% ./tests t --push1=t:-f,main/
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+=> push1
+=> evaluate: OFF
+=> evaluate_if: OFF
+# change the defaults
+% ./tests t:f,func3 --push1=t
+| | | >func3
+| | | <func3
+=> push1
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+# repeated keyword
+% ./tests d:-d,info,info
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,info
+% ./tests d:-d,info/,info
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,info/

=== removed file 'dbug/tests-t.pl'
--- a/dbug/tests-t.pl	2009-02-10 18:13:24 +0000
+++ b/dbug/tests-t.pl	1970-01-01 00:00:00 +0000
@@ -1,496 +0,0 @@
-#!/usr/bin/env perl
-
-#
-#  A driver program to test DBUG features - runs tests (shell commands)
-#  from the end of file to invoke tests.c, which does the real dbug work.
-#
-
-use Test::More;
-
-$exe=$0;
-
-die unless $exe =~ s/(tests)-t(\.exe)?$/$1$2 /;
-
-# load tests
-@tests=();
-while (<DATA>) {
-  if (/^% \.\/tests /) {
-    push @tests, [ $' ]
-  } elsif (/^#/) {
-    next;
-  } else {
-    push @{$tests[$#tests]}, $_
-  }
-}
-
-plan skip_all => "because dbug is disabled" if system $exe;
-
-plan tests => scalar(@tests);
-
-for (@tests) {
-  $t=$exe . shift @$_;
-  chomp($t);
-  open F, '-|',  $t or die "open($t|): $!";
-  local $";
-  $out=join($", <F>); close(F);
-  # special cases are handled here:
-  $out =~ s/Memory: 0x[0-9A-Fa-f]+/Memory: 0x####/g if $t =~ /dump/;
-  # compare ("\n" at the beginning makes better output in case of errors)
-  is("\n$out","\n@$_", $t);
-}
-
-__DATA__
-% ./tests -#d
-func2: info: s=ok
-=> execute
-=> evaluate: ON
-=> evaluate_if: OFF
-main: explain: dbug explained: d
-func2: info: s=ok
-% ./tests d,ret3
-=> evaluate: OFF
-=> evaluate_if: OFF
-#
-## Testing negative lists
-#
-% ./tests d:-d,ret3
-func2: info: s=ko
-=> execute
-=> evaluate: ON
-=> evaluate_if: OFF
-main: explain: dbug explained: d:-d,ret3
-func2: info: s=ko
-% ./tests t:-d,ret3
->main
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | <func2
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-| >func2
-| | >func3
-| | <func3
-| <func2
-<main
-% ./tests t:d,info:-d,ret3
->main
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | | info: s=ko
-| | <func2
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-| >func2
-| | >func3
-| | <func3
-| | info: s=ko
-| <func2
-<main
-% ./tests t:d,info:-d,ret3:-f,func2
->main
-| >func1
-| | | >func3
-| | | <func3
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-| | >func3
-| | <func3
-<main
-% ./tests t:d,info:-d,ret3:-f,func2 d,evaluate
-=> evaluate: ON
-=> evaluate_if: OFF
-% ./tests t:d,info:-d,ret3:-f,func2 d,evaluate_if
-=> evaluate: OFF
-=> evaluate_if: ON
-% ./tests t:d:-d,ret3:-f,func2 d,evaluate_if
-=> evaluate: OFF
-=> evaluate_if: ON
-% ./tests t:d:-d,ret3:-f,func2
->main
-| >func1
-| | | >func3
-| | | <func3
-| <func1
-=> execute
-=> evaluate: ON
-=> evaluate_if: OFF
-| explain: dbug explained: d:-d,ret3:f:-f,func2:t
-| | >func3
-| | <func3
-<main
-#
-## Adding incremental settings to the brew
-#
-% ./tests t:d:-d,ret3:-f,func2 +d,evaluate_if
->main
-| >func1
-| | | >func3
-| | | <func3
-| <func1
-=> evaluate: OFF
-=> evaluate_if: ON
-| | >func3
-| | <func3
-<main
-#
-## DBUG_DUMP
-#
-% ./tests t:d:-d,ret3:f:-f,func2 +d,dump
->main
-| >func1
-| | | >func3
-| | | <func3
-| <func1
-| dump: Memory: 0x####  Bytes: (27)
-64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A 
-74 
-=> evaluate: OFF
-=> evaluate_if: OFF
-| | >func3
-| | <func3
-<main
-% ./tests t:d:-d,ret3:f:-f,func2 +d,dump
->main
-| >func1
-| | | >func3
-| | | <func3
-| <func1
-| dump: Memory: 0x####  Bytes: (27)
-64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A 
-74 
-=> evaluate: OFF
-=> evaluate_if: OFF
-| | >func3
-| | <func3
-<main
-% ./tests t:d:-d,ret3:f:-f,func2:+d,dump
->main
-| >func1
-| | | >func3
-| | | <func3
-| <func1
-| dump: Memory: 0x####  Bytes: (27)
-64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A 
-74 
-=> evaluate: OFF
-=> evaluate_if: OFF
-| | >func3
-| | <func3
-<main
-% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain
->main
-| >func1
-| | | >func3
-| | | <func3
-| <func1
-| dump: Memory: 0x####  Bytes: (35)
-64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 
-66 2C 66 75 6E 63 32 3A 74 
-=> evaluate: OFF
-=> evaluate_if: OFF
-| explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:t
-| | >func3
-| | <func3
-<main
-% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P
-dbug: >main
-dbug-tests: | >func1
-dbug-tests: | | | >func3
-dbug-tests: | | | <func3
-dbug-tests: | <func1
-dbug-tests: | dump: Memory: 0x####  Bytes: (37)
-64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 
-66 2C 66 75 6E 63 32 3A 50 3A 74 
-=> evaluate: OFF
-=> evaluate_if: OFF
-dbug-tests: | explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:P:t
-dbug-tests: | | >func3
-dbug-tests: | | <func3
-dbug-tests: <main
-% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P:F
-dbug:        tests.c: >main
-dbug-tests:        tests.c: | >func1
-dbug-tests:        tests.c: | | | >func3
-dbug-tests:        tests.c: | | | <func3
-dbug-tests:        tests.c: | <func1
-dbug-tests:        tests.c: | dump: Memory: 0x####  Bytes: (39)
-64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 
-66 2C 66 75 6E 63 32 3A 46 3A 50 3A 74 
-=> evaluate: OFF
-=> evaluate_if: OFF
-dbug-tests:        tests.c: | explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:F:P:t
-dbug-tests:        tests.c: | | >func3
-dbug-tests:        tests.c: | | <func3
-dbug-tests:        tests.c: <main
-#
-## DBUG_EXPLAIN, DBUG_PUSH, DBUG_POP, DBUG_SET
-#
-% ./tests t:d:-d,ret3:f:-f,func2
->main
-| >func1
-| | | >func3
-| | | <func3
-| <func1
-=> execute
-=> evaluate: ON
-=> evaluate_if: OFF
-| explain: dbug explained: d:-d,ret3:f:-f,func2:t
-| | >func3
-| | <func3
-<main
-% ./tests t:d:-d,ret3
->main
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | | info: s=ko
-| | <func2
-| <func1
-=> execute
-=> evaluate: ON
-=> evaluate_if: OFF
-| explain: dbug explained: d:-d,ret3:t
-| >func2
-| | >func3
-| | <func3
-| | info: s=ko
-| <func2
-<main
-% ./tests d,info:-d,ret3:d,push
-func2: info: s=ko
-=> evaluate: OFF
-=> evaluate_if: OFF
-| >func2
-| | >func3
-| | <func3
-| | info: s=ko
-| <func2

-<main
-% ./tests d,info:-d,ret3:d,push,explain
-func2: info: s=ko
-=> evaluate: OFF
-=> evaluate_if: OFF
-| explain: dbug explained: d,info,push,explain:-d,ret3:t
-| >func2
-| | >func3
-| | <func3
-| | info: s=ko
-| <func2
-<main
-% ./tests d,info:-d,ret3:d,explain
-func2: info: s=ko
-=> evaluate: OFF
-=> evaluate_if: OFF
-main: explain: dbug explained: d,info,explain:-d,ret3
-func2: info: s=ko
-% ./tests d,info:-d,ret3:d,explain,pop
-func2: info: s=ko
-=> evaluate: OFF
-=> evaluate_if: OFF
-% ./tests d,info:-d,ret3:d,explain t:d,pop
->main
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | <func2
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-main: explain: dbug explained: d,info,explain:-d,ret3
-func2: info: s=ko
-% ./tests d,info:-d,ret3:d,explain,pop +t
->main
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | | info: s=ko
-| | <func2
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-main: explain: dbug explained: d,info,explain,pop:-d,ret3
-func2: info: s=ko
-% ./tests d,info:-d,ret3:d,explain,set
-func2: info: s=ko
-=> evaluate: OFF
-=> evaluate_if: OFF
-       tests.c: main: explain: dbug explained: d,info,explain,set:-d,ret3:F
-       tests.c: func2: info: s=ko
-% ./tests d,info:-d,ret3:d,explain,set:t
->main
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | | info: s=ko
-| | <func2
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-       tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
-       tests.c: | >func2
-       tests.c: | | >func3
-       tests.c: | | <func3
-       tests.c: | | info: s=ko
-       tests.c: | <func2
-       tests.c: <main
-% ./tests t d,info:-d,ret3:d,explain,set:t
->main
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | | info: s=ko
-| | <func2
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-       tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
-       tests.c: | >func2
-       tests.c: | | >func3
-       tests.c: | | <func3
-       tests.c: | | info: s=ko
-       tests.c: | <func2
-       tests.c: <main
-% ./tests t d,info:-d,ret3:d,explain,set,pop
-func2: info: s=ko
-=> evaluate: OFF
-=> evaluate_if: OFF
-| >func2
-| | >func3
-| | <func3
-| <func2
-<main
-% ./tests t:f,func2
-| | >func2
-| | <func2
-=> evaluate: OFF
-=> evaluate_if: OFF
-| >func2
-| <func2
-#
-## Testing SUBDIR rules
-#
-% ./tests t:-f,func2/:d
->main
-| >func1
-| <func1
-=> execute
-=> evaluate: ON
-=> evaluate_if: OFF
-| explain: dbug explained: d:f:-f,func2/:t
-<main
-% ./tests t:f,func1/:d
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | | info: s=ok
-| | <func2
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-% ./tests t:f,main/:d,pop
->main
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | <func2
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-% ./tests f,main/:d,push
-=> evaluate: OFF
-=> evaluate_if: OFF
-| >func2
-| | >func3
-| | <func3
-| <func2
-<main
-#
-## Testing FixTraceFlags() - when we need to traverse the call stack
-# (these tests fail with FixTraceFlags() disabled)
-#
-# delete the INCLUDE rule up the stack
-% ./tests t:f,func1/ --push1=t:f,func3/
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | <func2
-=> push1
-=> evaluate: OFF
-=> evaluate_if: OFF
-| | >func3
-| | <func3
-# delete the EXCLUDE rule up the stack
-% ./tests t:-f,func1/ --push1=t
->main
-=> push1
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-| >func2
-| | >func3
-| | <func3
-| <func2
-<main
-# add the INCLUDE rule up the stack
-% ./tests t:f,func3 --push1=t:f,main/
-| | | >func3
-| | | <func3
-=> push1
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-| >func2
-| | >func3
-| | <func3
-| <func2
-<main
-# add the EXCLUDE rule up the stack
-% ./tests t --push1=t:-f,main/
->main
-| >func1
-| | >func2
-| | | >func3
-| | | <func3
-| | <func2
-=> push1
-=> evaluate: OFF
-=> evaluate_if: OFF
-# change the defaults
-% ./tests t:f,func3 --push1=t
-| | | >func3
-| | | <func3
-=> push1
-| <func1
-=> evaluate: OFF
-=> evaluate_if: OFF
-| >func2
-| | >func3
-| | <func3
-| <func2
-<main
-# repeated keyword
-% ./tests d:-d,info,info
-=> execute
-=> evaluate: ON
-=> evaluate_if: OFF
-main: explain: dbug explained: d:-d,info
-% ./tests d:-d,info/,info
-=> execute
-=> evaluate: ON
-=> evaluate_if: OFF
-main: explain: dbug explained: d:-d,info/

=== added file 'dbug/tests.c'
--- a/dbug/tests.c	1970-01-01 00:00:00 +0000
+++ b/dbug/tests.c	2009-10-30 18:13:58 +0000
@@ -0,0 +1,87 @@
+/*
+  A program to test DBUG features. Used by tests-t.pl
+*/
+
+char *push1=0;
+
+#include <my_global.h>  /* This includes dbug.h */
+#include <my_pthread.h>
+#include <string.h>
+
+const char *func3()
+{
+  DBUG_ENTER("func3");
+  DBUG_RETURN(DBUG_EVALUATE("ret3", "ok", "ko"));
+}
+
+void func2()
+{
+  const char *s;
+  DBUG_ENTER("func2");
+  s=func3();
+  DBUG_PRINT("info", ("s=%s", s));
+  DBUG_VOID_RETURN;
+}
+
+int func1()
+{
+  DBUG_ENTER("func1");
+  func2();
+  if (push1)
+  {
+    DBUG_PUSH(push1);
+    fprintf(DBUG_FILE, "=> push1\n");
+  }
+  DBUG_RETURN(10);
+}
+
+int main (int argc, char *argv[])
+{
+  int i;
+#ifdef DBUG_OFF
+  return 1;
+#endif
+  if (argc == 1)
+    return 0;
+
+#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
+  pthread_init();                       /* Must be called before DBUG_ENTER */
+#endif
+#ifdef THREAD
+  my_thread_global_init();
+#endif
+  dup2(1, 2);
+  for (i = 1; i < argc; i++)
+  {
+    if (strncmp(argv[i], "--push1=", 8) == 0)
+      push1=argv[i]+8;
+    else
+      DBUG_PUSH (argv[i]);
+  }
+  {
+    DBUG_ENTER ("main");
+    DBUG_PROCESS ("dbug-tests");
+    func1();
+    DBUG_EXECUTE_IF("dump",
+    {
+      char s[1000];
+      DBUG_EXPLAIN(s, sizeof(s)-1);
+      DBUG_DUMP("dump", (uchar*)s, strlen(s));
+    });
+    DBUG_EXECUTE_IF("push",  DBUG_PUSH("+t"); );
+    DBUG_EXECUTE("execute", fprintf(DBUG_FILE, "=> execute\n"); );
+    DBUG_EXECUTE_IF("set",  DBUG_SET("+F"); );
+    fprintf(DBUG_FILE, "=> evaluate: %s\n",
+            DBUG_EVALUATE("evaluate", "ON", "OFF"));
+    fprintf(DBUG_FILE, "=> evaluate_if: %s\n",
+            DBUG_EVALUATE_IF("evaluate_if", "ON", "OFF"));
+    DBUG_EXECUTE_IF("pop",  DBUG_POP(); );
+    {
+      char s[1000] __attribute__((unused));
+      DBUG_EXPLAIN(s, sizeof(s)-1);
+      DBUG_PRINT("explain", ("dbug explained: %s", s));
+    }
+    func2();
+    DBUG_RETURN (0);
+  }
+}

=== removed file 'dbug/tests.c'
--- a/dbug/tests.c	2008-02-13 19:29:29 +0000
+++ b/dbug/tests.c	1970-01-01 00:00:00 +0000
@@ -1,87 +0,0 @@
-/*
-  A program to test DBUG features. Used by tests-t.pl
-*/
-
-char *push1=0;
-
-#include <my_global.h>  /* This includes dbug.h */
-#include <my_pthread.h>
-#include <string.h>
-
-const char *func3()
-{
-  DBUG_ENTER("func3");
-  DBUG_RETURN(DBUG_EVALUATE("ret3", "ok", "ko"));
-}
-
-void func2()
-{
-  const char *s;
-  DBUG_ENTER("func2");
-  s=func3();
-  DBUG_PRINT("info", ("s=%s", s));
-  DBUG_VOID_RETURN;
-}
-
-int func1()
-{
-  DBUG_ENTER("func1");
-  func2();
-  if (push1)
-  {
-    DBUG_PUSH(push1);
-    fprintf(DBUG_FILE, "=> push1\n");
-  }
-  DBUG_RETURN(10);
-}
-
-int main (int argc, char *argv[])
-{
-  int i;
-#ifdef DBUG_OFF
-  return 1;
-#endif
-  if (argc == 1)
-    return 0;
-
-#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
-  pthread_init();                       /* Must be called before DBUG_ENTER */
-#endif
-#ifdef THREAD
-  my_thread_global_init();
-#endif
-  dup2(1, 2);
-  for (i = 1; i < argc; i++)
-  {
-    if (strncmp(argv[i], "--push1=", 8) == 0)
-      push1=argv[i]+8;
-    else
-      DBUG_PUSH (argv[i]);
-  }
-  {
-    DBUG_ENTER ("main");
-    DBUG_PROCESS ("dbug-tests");
-    func1();
-    DBUG_EXECUTE_IF("dump",
-    {
-      char s[1000];
-      DBUG_EXPLAIN(s, sizeof(s)-1);
-      DBUG_DUMP("dump", (uchar*)s, strlen(s));
-    });
-    DBUG_EXECUTE_IF("push",  DBUG_PUSH("+t"); );
-    DBUG_EXECUTE("execute", fprintf(DBUG_FILE, "=> execute\n"); );
-    DBUG_EXECUTE_IF("set",  DBUG_SET("+F"); );
-    fprintf(DBUG_FILE, "=> evaluate: %s\n",
-            DBUG_EVALUATE("evaluate", "ON", "OFF"));
-    fprintf(DBUG_FILE, "=> evaluate_if: %s\n",
-            DBUG_EVALUATE_IF("evaluate_if", "ON", "OFF"));
-    DBUG_EXECUTE_IF("pop",  DBUG_POP(); );
-    {
-      char s[1000] __attribute__((unused));
-      DBUG_EXPLAIN(s, sizeof(s)-1);
-      DBUG_PRINT("explain", ("dbug explained: %s", s));
-    }
-    func2();
-    DBUG_RETURN (0);
-  }
-}

=== modified file 'include/my_dbug.h'
--- a/include/my_dbug.h	2009-10-26 14:02:26 +0000
+++ b/include/my_dbug.h	2009-11-05 08:44:22 +0000
@@ -16,29 +16,6 @@
 #ifndef _dbug_h
 #define _dbug_h
 
-#if defined(__cplusplus) && !defined(DBUG_OFF)
-class Dbug_violation_helper
-{
-public:
-  inline Dbug_violation_helper() :
-    _entered(TRUE)
-  { }
-
-  inline ~Dbug_violation_helper()
-  {
-    assert(!_entered);
-  }
-
-  inline void leave()
-  {
-    _entered= FALSE;
-  }
-
-private:
-  bool _entered;
-};
-#endif /* C++ */
-
 #ifdef  __cplusplus
 extern "C" {
 #endif
@@ -54,8 +31,6 @@ struct _db_stack_frame_ {
 struct  _db_code_state_;
 extern  my_bool _dbug_on_;
 extern  my_bool _db_keyword_(struct _db_code_state_ *, const char *, int);
-extern  my_bool _db_keywords_(struct _db_code_state_ *, int, const char *,
-                              const char *);
 extern  int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len);
 extern  int _db_explain_init_(char *buf, size_t len);
 extern	int _db_is_pushed_(void);
@@ -81,28 +56,9 @@ extern  FILE *_db_fp_(void);
 extern  void _db_flush_();
 extern  const char* _db_get_func_(void);
 
-#ifdef __cplusplus
-
-#define DBUG_ENTER(a) \
-        struct _db_stack_frame_ _db_stack_frame_; \
-        Dbug_violation_helper dbug_violation_helper; \
+#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \
         _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_)
-#define DBUG_VIOLATION_HELPER_LEAVE \
-        dbug_violation_helper.leave()
-
-#else /* C */
-
-#define DBUG_ENTER(a) \
-        struct _db_stack_frame_ _db_stack_frame_; \
-        _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_)
-#define DBUG_VIOLATION_HELPER_LEAVE \
-        do { } while (0)
-
-#endif /* C++ */
-
-#define DBUG_LEAVE \
-        DBUG_VIOLATION_HELPER_LEAVE; \
-        _db_return_ (__LINE__, &_db_stack_frame_)
+#define DBUG_LEAVE _db_return_ (__LINE__, &_db_stack_frame_)
 #define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0)
 #define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0)
 #define DBUG_EXECUTE(keyword,a1) \
@@ -132,7 +88,6 @@ extern  const char* _db_get_func_(void);
 #define DBUG_EXPLAIN_INITIAL(buf,len) _db_explain_init_((buf),(len))
 #define DEBUGGER_OFF                    do { _dbug_on_= 0; } while(0)
 #define DEBUGGER_ON                     do { _dbug_on_= 1; } while(0)
-#define IF_DBUG(A) A
 #ifndef __WIN__
 #define DBUG_ABORT()                    (_db_flush_(), abort())
 #else
@@ -146,26 +101,20 @@ extern  const char* _db_get_func_(void);
                      (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR),\
                      _exit(3))
 #endif
-#define _DBUG_MAX_FUNC_NAME_ 255
 #define DBUG_CHECK_CRASH(func, op) \
-        do { \
-          if (_db_keywords_(0, 1, (func), (op))) \
-            { (_db_flush_(), abort()); } \
-        } while (0)
+  do { char _dbuf_[255]; strxnmov(_dbuf_, sizeof(_dbuf_)-1, (func), (op)); \
+    DBUG_EXECUTE_IF(_dbuf_, DBUG_ABORT()); } while(0)
 #define DBUG_CRASH_ENTER(func) \
   DBUG_ENTER(func); DBUG_CHECK_CRASH(func, "_crash_enter")
 #define DBUG_CRASH_RETURN(val) \
-  do {DBUG_CHECK_CRASH(_db_get_func_(), "_crash_return"); \
-    DBUG_RETURN(val);} while(0)
+  DBUG_CHECK_CRASH(_db_get_func_(), "_crash_return")
 #define DBUG_CRASH_VOID_RETURN \
-  do {DBUG_CHECK_CRASH (_db_get_func_(), "_crash_return"); \
-    DBUG_VOID_RETURN;} while(0)
+  DBUG_CHECK_CRASH (_db_get_func_(), "_crash_return")
 
 #else                                           /* No debugger */
 
 #define DBUG_ENTER(a1)
 #define DBUG_LEAVE
-#define DBUG_VIOLATION_HELPER_LEAVE
 #define DBUG_RETURN(a1)                 do { return(a1); } while(0)
 #define DBUG_VOID_RETURN                do { return; } while(0)
 #define DBUG_EXECUTE(keyword,a1)        do { } while(0)
@@ -190,7 +139,6 @@ extern  const char* _db_get_func_(void);
 #define DBUG_EXPLAIN_INITIAL(buf,len)
 #define DEBUGGER_OFF                    do { } while(0)
 #define DEBUGGER_ON                     do { } while(0)
-#define IF_DBUG(A)
 #define DBUG_ABORT()                    abort()
 #define DBUG_CRASH_ENTER(func)
 #define DBUG_CRASH_RETURN(val)          do { return(val); } while(0)

=== modified file 'include/my_global.h'
--- a/include/my_global.h	2009-10-23 06:24:37 +0000
+++ b/include/my_global.h	2009-11-05 08:44:22 +0000
@@ -648,7 +648,6 @@ C_MODE_END
 #endif
 
 typedef char		my_bool; /* Small bool */
-#include <my_dbug.h>
 
 #define MIN_ARRAY_SIZE	0	/* Zero or One. Gcc allows zero*/
 #define ASCII_BITS_USED 8	/* Bit char used */
@@ -1162,6 +1161,8 @@ typedef char		bool;	/* Ordinary boolean 
 #define reg16 register
 #endif
 
+#include <my_dbug.h>
+
 /*
   Sometimes we want to make sure that the variable is not put into
   a register in debugging mode so we can see its value in the core

=== modified file 'include/my_sys.h'
--- a/include/my_sys.h	2009-10-30 15:36:45 +0000
+++ b/include/my_sys.h	2009-11-06 16:34:09 +0000
@@ -197,7 +197,7 @@ extern char *my_strndup(const char *from
   client/backup_stream.c and backup_client_coverage.test.
   The global variable is defined in my_static.c.
 */
-IF_DBUG(extern int my_malloc_error_inject);
+extern int my_malloc_error_inject;
 
 #ifdef HAVE_LARGE_PAGES
 extern uint my_get_large_page_size(void);

=== modified file 'include/mysql/plugin.h'
--- a/include/mysql/plugin.h	2009-10-26 14:02:26 +0000
+++ b/include/mysql/plugin.h	2009-11-05 08:44:22 +0000
@@ -56,7 +56,7 @@ typedef struct st_mysql_xid MYSQL_XID;
   Plugin API. Common for all plugin types.
 */
 
-#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0100
+#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0101
 
 /*
   The allowable types of plugins
@@ -581,64 +581,6 @@ void mysql_query_cache_invalidate4(MYSQL
                                    const char *key, unsigned int key_length,
                                    int using_trx);
 
-/**
-   Get the value of user variable as an integer.
-
-   This function will return the value of variable @a name as an
-   integer. If the original value of the variable is not an integer,
-   the value will be converted into an integer.
-
-   @param name     user variable name
-   @param value    pointer to return the value
-   @param null_value if not NULL, the function will set it to true if
-   the value of variable is null, set to false if not
-
-   @retval 0 Success
-   @retval 1 Variable not found
-*/
-int get_user_var_int(const char *name,
-                     long long int *value, int *null_value);
-
-/**
-   Get the value of user variable as a double precision float number.
-
-   This function will return the value of variable @a name as real
-   number. If the original value of the variable is not a real number,
-   the value will be converted into a real number.
-
-   @param name     user variable name
-   @param value    pointer to return the value
-   @param null_value if not NULL, the function will set it to true if
-   the value of variable is null, set to false if not
-
-   @retval 0 Success
-   @retval 1 Variable not found
-*/
-int get_user_var_real(const char *name,
-                      double *value, int *null_value);
-
-/**
-   Get the value of user variable as a string.
-
-   This function will return the value of variable @a name as
-   string. If the original value of the variable is not a string,
-   the value will be converted into a string.
-
-   @param name     user variable name
-   @param value    pointer to the value buffer
-   @param len      length of the value buffer
-   @param precision precision of the value if it is a float number
-   @param null_value if not NULL, the function will set it to true if
-   the value of variable is null, set to false if not
-
-   @retval 0 Success
-   @retval 1 Variable not found
-*/
-int get_user_var_str(const char *name,
-                     char *value, unsigned long len,
-                     unsigned int precision, int *null_value);
-
-  
 #ifdef __cplusplus
 }
 #endif

=== modified file 'include/mysql/plugin.h.pp'
--- a/include/mysql/plugin.h.pp	2009-10-26 14:02:26 +0000
+++ b/include/mysql/plugin.h.pp	2009-11-05 08:44:22 +0000
@@ -165,10 +165,3 @@ void thd_get_xid(const void* thd, MYSQL_
 void mysql_query_cache_invalidate4(void* thd,
                                    const char *key, unsigned int key_length,
                                    int using_trx);
-int get_user_var_int(const char *name,
-                     long long int *value, int *null_value);
-int get_user_var_real(const char *name,
-                      double *value, int *null_value);
-int get_user_var_str(const char *name,
-                     char *value, unsigned long len,
-                     unsigned int precision, int *null_value);

=== added file 'include/mysql/service_my_snprintf.h'
--- a/include/mysql/service_my_snprintf.h	1970-01-01 00:00:00 +0000
+++ b/include/mysql/service_my_snprintf.h	2009-11-05 08:44:22 +0000
@@ -0,0 +1,98 @@
+#ifndef MYSQL_SERVICE_MY_SNPRINTF_INCLUDED
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file
+  my_snprintf service
+
+  Portable and limited vsnprintf() implementation.
+
+  This is a portable, limited vsnprintf() implementation, with some
+  extra features. "Portable" means that it'll produce identical result
+  on all platforms (for example, on Windows and Linux system printf %e
+  formats the exponent differently, on different systems %p either
+  prints leading 0x or not, %s may accept null pointer or crash on
+  it). "Limited" means that it does not support all the C89 features.
+  But it supports few extensions, not in any standard.
+
+  my_vsnprintf(to, n, fmt, ap)
+
+  @param[out] to     A buffer to store the result in
+  @param[in]  n      Store up to n-1 characters, followed by an end 0
+  @param[in]  fmt    printf-like format string
+  @param[in]  ap     Arguments
+
+  @return a number of bytes written to a buffer *excluding* terminating '\0'
+
+  @post
+  The syntax of a format string is generally the same:
+  % <flag> <width> <precision> <length modifier> <format>
+  where everithing but the format is optional.
+
+  Three one-character flags are recognized:
+    '0' has the standard zero-padding semantics;
+    '-' is parsed, but silently ignored;
+    '`' (backtick) is only supported for strings (%s) and means that the
+        string will be quoted according to MySQL identifier quoting rules.
+
+  Both <width> and <precision> can be specified as numbers or '*'.
+
+  <length modifier> can be 'l', 'll', or 'z'.
+
+  Supported formats are 's' (null pointer is accepted, printed as
+  "(null)"), 'b' (extension, see below), 'c', 'd', 'u', 'x',
+  'X', 'p' (works as 0x%x), 'f', 'g'.
+
+  Standard syntax for positional arguments $n is supported.
+
+  Extensions:
+
+  Flag '`' (backtick): see above.
+
+  Format 'b': binary buffer, prints exactly <precision> bytes from the
+  argument, without stopping at '\0'.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+extern struct my_snprintf_service_st {
+  size_t (*my_snprintf_type)(char*, size_t, const char*, ...);
+  size_t (*my_vsnprintf_type)(char *, size_t, const char*, va_list);
+} *my_snprintf_service;
+
+#ifdef MYSQL_DYNAMIC_PLUGIN
+
+#define my_vsnprintf my_snprintf_service->my_vsnprintf_type
+#define my_snprintf my_snprintf_service->my_snprintf_type
+
+#else
+
+size_t my_snprintf(char* to, size_t n, const char* fmt, ...);
+size_t my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#define MYSQL_SERVICE_MY_SNPRINTF_INCLUDED
+#endif
+

=== removed file 'include/mysql/service_my_snprintf.h'
--- a/include/mysql/service_my_snprintf.h	2009-10-12 09:08:34 +0000
+++ b/include/mysql/service_my_snprintf.h	1970-01-01 00:00:00 +0000
@@ -1,83 +0,0 @@
-#ifndef SERVICE_MY_SNPRINTF_INCLUDED
-#define SERVICE_MY_SNPRINTF_INCLUDED
-
-/* Copyright (C) 2009 Sun Microsystems, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-/**
-  @file
-  my_snprintf service
-
-  Portable and limited vsnprintf() implementation.
-
-  This is a portable, limited vsnprintf() implementation, with some
-  extra features. "Portable" means that it'll produce identical result
-  on all platforms (for example, on Windows and Linux %e formats the
-  exponent differently, on different systems %p either prints leading
-  0x or not, %s may accept null pointer or crash on it). "Limited"
-  means that it does not support all the C89 features. But it supports
-  few extensions, not in any standard.
-
-  my_vsnprintf(to, n, fmt, ap)
-
-  @param[out] to     A buffer to store the result in
-  @param[in]  n      Store up to n-1 characters, followed by an end 0
-  @param[in]  fmt    printf-like format string
-  @param[in]  ap     Arguments
-
-  @return a number of bytes written to a buffer
-
-  @post
-  The syntax of a format string is generally the same:
-  % <flag> <width> <precision> <length modifier> <format>
-  where everithing but the format is optional.
-
-  The only possible <flag> is '0'. It has the standard zero-padding semantics.
-  Both <width> and <precision> can be specified as numbers or '*'.
-
-  <length modifier> can be 'l', 'll', or 'z'.
-
-  Supported formats are 's' (null pointer is accepted, printed as
-  "(null)"), 'b' (extension, see below), 'c', 'f', 'g', 'd', 'u', 'x',
-  'X', 'p' (works as 0x%x).
-
-  Extensions:
-
-  Format 'b': binary buffer, prints exactly <precision> bytes from the
-  argument, without stopping at '\0'.
-
-  More to come (identifier quoting, escaping, see WL#751).
-*/
-
-#include <stdarg.h>
-#include <stdlib.h>
-extern struct my_snprintf_service_st {
-  size_t (*my_snprintf_type)(char*, size_t, const char*, ...);
-  size_t (*my_vsnprintf_type)(char *, size_t, const char*, va_list);
-} *my_snprintf_service;
-
-#ifdef MYSQL_DYNAMIC_PLUGIN
-
-#define my_vsnprintf my_snprintf_service->my_vsnprintf_type
-#define my_snprintf my_snprintf_service->my_snprintf_type
-
-#else
-
-size_t my_snprintf(char* to, size_t n, const char* fmt, ...);
-size_t my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap);
-
-#endif
-
-#endif /* SERVICE_MY_SNPRINTF_INCLUDED */

=== added file 'include/mysql/service_thd_alloc.h'
--- a/include/mysql/service_thd_alloc.h	1970-01-01 00:00:00 +0000
+++ b/include/mysql/service_thd_alloc.h	2009-11-02 20:05:42 +0000
@@ -0,0 +1,128 @@
+#ifndef MYSQL_SERVICE_THD_ALLOC_INCLUDED
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/**
+  @file
+  This service provdes functions to allocate memory in a connection local
+  memory pool. The memory allocated there will be automatically freed at the
+  end of the statement, don't use it for allocations that should live longer
+  than that. For short living allocations this is more efficient than
+  using my_malloc and friends, and automatic "garbage collection" allows not
+  to think about memory leaks.
+
+  The pool is best for small to medium objects, don't use it for large
+  allocations - they are better served with my_malloc.
+*/
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct st_mysql_lex_string
+{
+  char *str;
+  size_t length;
+};
+typedef struct st_mysql_lex_string MYSQL_LEX_STRING;
+
+extern struct thd_alloc_service_st {
+  void *(*thd_alloc_func)(MYSQL_THD, unsigned int);
+  void *(*thd_calloc_func)(MYSQL_THD, unsigned int);
+  char *(*thd_strdup_func)(MYSQL_THD, const char *);
+  char *(*thd_strmake_func)(MYSQL_THD, const char *, unsigned int);
+  void *(*thd_memdup_func)(MYSQL_THD, const void*, unsigned int);
+  MYSQL_LEX_STRING *(*thd_make_lex_string_func)(MYSQL_THD, MYSQL_LEX_STRING *,
+                                        const char *, unsigned int, int);
+} *thd_alloc_service;
+
+#ifdef MYSQL_DYNAMIC_PLUGIN
+
+#define thd_alloc(thd,size) (thd_alloc_service->thd_alloc_func((thd), (size)))
+
+#define thd_calloc(thd,size) (thd_alloc_service->thd_calloc_func((thd), (size)))
+
+#define thd_strdup(thd,str) (thd_alloc_service->thd_strdup_func((thd), (str)))
+
+#define thd_strmake(thd,str,size) \
+  (thd_alloc_service->thd_strmake_func((thd), (str), (size)))
+
+#define thd_memdup(thd,str,size) \
+  (thd_alloc_service->thd_memdup_func((thd), (str), (size)))
+
+#define thd_make_lex_string(thd, lex_str, str, size, allocate_lex_string) \
+  (thd_alloc_service->thd_make_lex_string_func((thd), (lex_str), (str), \
+                                               (size), (allocate_lex_string)))
+
+#else
+
+/**
+  Allocate memory in the connection's local memory pool
+
+  @details
+  When properly used in place of @c my_malloc(), this can significantly
+  improve concurrency. Don't use this or related functions to allocate
+  large chunks of memory. Use for temporary storage only. The memory
+  will be freed automatically at the end of the statement; no explicit
+  code is required to prevent memory leaks.
+
+  @see alloc_root()
+*/
+void *thd_alloc(MYSQL_THD thd, unsigned int size);
+/**
+  @see thd_alloc()
+*/
+void *thd_calloc(MYSQL_THD thd, unsigned int size);
+/**
+  @see thd_alloc()
+*/
+char *thd_strdup(MYSQL_THD thd, const char *str);
+/**
+  @see thd_alloc()
+*/
+char *thd_strmake(MYSQL_THD thd, const char *str, unsigned int size);
+/**
+  @see thd_alloc()
+*/
+void *thd_memdup(MYSQL_THD thd, const void* str, unsigned int size);
+
+/**
+  Create a LEX_STRING in this connection's local memory pool
+
+  @param thd      user thread connection handle
+  @param lex_str  pointer to LEX_STRING object to be initialized
+  @param str      initializer to be copied into lex_str
+  @param size     length of str, in bytes
+  @param allocate_lex_string  flag: if TRUE, allocate new LEX_STRING object,
+                              instead of using lex_str value
+  @return  NULL on failure, or pointer to the LEX_STRING object
+
+  @see thd_alloc()
+*/
+MYSQL_LEX_STRING *thd_make_lex_string(MYSQL_THD thd, MYSQL_LEX_STRING *lex_str,
+                                      const char *str, unsigned int size,
+                                      int allocate_lex_string);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#define MYSQL_SERVICE_THD_ALLOC_INCLUDED
+#endif
+

=== removed file 'include/mysql/service_thd_alloc.h'
--- a/include/mysql/service_thd_alloc.h	2009-10-12 09:08:34 +0000
+++ b/include/mysql/service_thd_alloc.h	1970-01-01 00:00:00 +0000
@@ -1,120 +0,0 @@
-#ifndef SERVICE_THD_ALLOC_INCLUDED
-#define SERVICE_THD_ALLOC_INCLUDED
-
-/* Copyright (C) 2009 Sun Microsystems, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-/**
-  @file
-  This service provdes functions to allocate memory in a connection local
-  memory pool. The memory allocated there will be automatically freed at the
-  end of the statement, don't use it for allocations that should live longer
-  than that. For short living allocations this is more efficient than
-  using my_malloc and friends, and automatic "garbage collection" allows not
-  to think about memory leaks.
-
-  The pool is best for small to medium objects, don't use it for large
-  allocations - they are better served with my_malloc.
-*/
-
-#include <stdlib.h>
-
-struct st_mysql_lex_string
-{
-  char *str;
-  size_t length;
-};
-typedef struct st_mysql_lex_string MYSQL_LEX_STRING;
-
-extern struct thd_alloc_service_st {
-  void *(*thd_alloc_func)(MYSQL_THD, unsigned int);
-  void *(*thd_calloc_func)(MYSQL_THD, unsigned int);
-  char *(*thd_strdup_func)(MYSQL_THD, const char *);
-  char *(*thd_strmake_func)(MYSQL_THD, const char *, unsigned int);
-  void *(*thd_memdup_func)(MYSQL_THD, const void*, unsigned int);
-  MYSQL_LEX_STRING *(*thd_make_lex_string_func)(MYSQL_THD, MYSQL_LEX_STRING *,
-                                        const char *, unsigned int, int);
-} *thd_alloc_service;
-
-#ifdef MYSQL_DYNAMIC_PLUGIN
-
-#define thd_alloc(thd,size) (thd_alloc_service->thd_alloc_func((thd), (size)))
-
-#define thd_calloc(thd,size) (thd_alloc_service->thd_calloc_func((thd), (size)))
-
-#define thd_strdup(thd,str) (thd_alloc_service->thd_strdup_func((thd), (str)))
-
-#define thd_strmake(thd,str,size) \
-  (thd_alloc_service->thd_strmake_func((thd), (str), (size)))
-
-#define thd_memdup(thd,str,size) \
-  (thd_alloc_service->thd_memdup_func((thd), (str), (size)))
-
-#define thd_make_lex_string(thd, lex_str, str, size, allocate_lex_string) \
-  (thd_alloc_service->thd_make_lex_string_func((thd), (lex_str), (str), \
-                                               (size), (allocate_lex_string)))
-
-#else
-
-/**
-  Allocate memory in the connection's local memory pool
-
-  @details
-  When properly used in place of @c my_malloc(), this can significantly
-  improve concurrency. Don't use this or related functions to allocate
-  large chunks of memory. Use for temporary storage only. The memory
-  will be freed automatically at the end of the statement; no explicit
-  code is required to prevent memory leaks.
-
-  @see alloc_root()
-*/
-void *thd_alloc(MYSQL_THD thd, unsigned int size);
-/**
-  @see thd_alloc()
-*/
-void *thd_calloc(MYSQL_THD thd, unsigned int size);
-/**
-  @see thd_alloc()
-*/
-char *thd_strdup(MYSQL_THD thd, const char *str);
-/**
-  @see thd_alloc()
-*/
-char *thd_strmake(MYSQL_THD thd, const char *str, unsigned int size);
-/**
-  @see thd_alloc()
-*/
-void *thd_memdup(MYSQL_THD thd, const void* str, unsigned int size);
-
-/**
-  Create a LEX_STRING in this connection's local memory pool
-
-  @param thd      user thread connection handle
-  @param lex_str  pointer to LEX_STRING object to be initialized
-  @param str      initializer to be copied into lex_str
-  @param size     length of str, in bytes
-  @param allocate_lex_string  flag: if TRUE, allocate new LEX_STRING object,
-                              instead of using lex_str value
-  @return  NULL on failure, or pointer to the LEX_STRING object
-
-  @see thd_alloc()
-*/
-MYSQL_LEX_STRING *thd_make_lex_string(MYSQL_THD thd, MYSQL_LEX_STRING *lex_str,
-                                      const char *str, unsigned int size,
-                                      int allocate_lex_string);
-
-#endif
-
-#endif /* SERVICE_THD_ALLOC_INCLUDED */

=== added file 'include/mysql/services.h'
--- a/include/mysql/services.h	1970-01-01 00:00:00 +0000
+++ b/include/mysql/services.h	2009-11-02 20:05:42 +0000
@@ -0,0 +1,30 @@
+#ifndef MYSQL_SERVICES_INCLUDED
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <mysql/service_my_snprintf.h>
+#include <mysql/service_thd_alloc.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#define MYSQL_SERVICES_INCLUDED
+#endif
+

=== removed file 'include/mysql/services.h'
--- a/include/mysql/services.h	2009-10-12 09:08:34 +0000
+++ b/include/mysql/services.h	1970-01-01 00:00:00 +0000
@@ -1,31 +0,0 @@
-#ifndef MYSQL_SERVICES_INCLUDED
-#define MYSQL_SERVICES_INCLUDED
-
-/* Copyright (C) 2009 Sun Microsystems, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <mysql/service_my_snprintf.h>
-#include <mysql/service_thd_alloc.h>
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-

=== added file 'include/service_versions.h'
--- a/include/service_versions.h	1970-01-01 00:00:00 +0000
+++ b/include/service_versions.h	2009-11-05 08:44:22 +0000
@@ -0,0 +1,24 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifdef _WIN32
+#define SERVICE_VERSION __declspec(dllexport) void *
+#else
+#define SERVICE_VERSION void *
+#endif
+
+#define VERSION_my_snprintf     0x0101
+#define VERSION_thd_alloc       0x0100
+

=== removed file 'include/service_versions.h'
--- a/include/service_versions.h	2009-10-12 09:08:34 +0000
+++ b/include/service_versions.h	1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
-#ifndef SERVICE_VERSIONS_INCLUDED
-#define SERVICE_VERSIONS_INCLUDED
-
-/* Copyright (C) 2009 Sun Microsystems, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-#ifdef _WIN32
-#define SERVICE_VERSION __declspec(dllexport) void *
-#else
-#define SERVICE_VERSION void *
-#endif
-
-#define VERSION_my_snprintf     0x0100
-#define VERSION_thd_alloc       0x0100
-
-#endif /* SERVICE_VERSIONS_INCLUDED */

=== modified file 'libmysql/libmysql.c'
--- a/libmysql/libmysql.c	2009-11-03 18:24:59 +0000
+++ b/libmysql/libmysql.c	2009-11-06 16:34:09 +0000
@@ -131,7 +131,7 @@ int STDCALL mysql_server_init(int argc _
       mysql_port = MYSQL_PORT;
 #ifndef MSDOS
       {
-	struct servent *serv_ptr;
+	struct servent *serv_ptr __attribute__((unused));
 	char	*env;
 
         /*

=== added directory 'libservices'
=== removed directory 'libservices'
=== added file 'libservices/CMakeLists.txt'
--- a/libservices/CMakeLists.txt	1970-01-01 00:00:00 +0000
+++ b/libservices/CMakeLists.txt	2009-11-02 20:05:42 +0000
@@ -0,0 +1,20 @@
+# Copyright (C) 2006 MySQL AB
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+
+SET(MYSQLSERVICES_SOURCES my_snprintf_service.c thd_alloc_service.c)
+
+ADD_LIBRARY(mysqlservices ${MYSQLSERVICES_SOURCES})

=== removed file 'libservices/CMakeLists.txt'
--- a/libservices/CMakeLists.txt	2009-05-05 18:58:20 +0000
+++ b/libservices/CMakeLists.txt	1970-01-01 00:00:00 +0000
@@ -1,20 +0,0 @@
-# Copyright (C) 2006 MySQL AB
-# 
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 2 of the License.
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
-
-SET(LIBSERVICES_SOURCES my_snprintf_service.c thd_alloc_service.c)
-
-ADD_LIBRARY(libservices ${LIBSERVICES_SOURCES})

=== added file 'libservices/HOWTO'
--- a/libservices/HOWTO	1970-01-01 00:00:00 +0000
+++ b/libservices/HOWTO	2009-11-02 20:05:42 +0000
@@ -0,0 +1,100 @@
+How to create a new service
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A "service" is a set of C functions in a structure that a
+service dynamic linker uses when a dynamic plugin is loaded.
+
+If you want to export C++ class you need to provide an
+extern "C" function that will create a new instance of your class,
+and put it in a service.
+
+Data structures are not part of the service structure, but they are part
+of the API you create and usually need to be declared in the same
+service_*.h file.
+
+To turn a set of functions (foo_func1, foo_func2)
+into a service "foo" you need to
+
+1. create a new file include/mysql/service_foo.h
+
+2. the template is
+==================================================================
+  #ifndef MYSQL_SERVICE_FOO_INCLUDED
+  /* standard GPL header */
+
+  /**
+    @file
+    *exhaustive* description of the interface you provide.
+    This file is the main user documentation of the new service
+  */
+  #ifdef __cplusplus
+  extern "C" {
+  #endif
+
+  extern struct foo_service_st {
+    int (*foo_func1_type)(...);  /* fix the prototype as appropriate */
+    void (*foo_func2_type)(...); /* fix the prototype as appropriate */
+  } *foo_service;
+
+  #ifdef MYSQL_DYNAMIC_PLUGIN
+
+  #define foo_func1(...) foo_service->foo_func1_type(...)
+  #define foo_func2(...) foo_service->foo_func2_type(...)
+
+  #else
+
+  int foo_func1_type(...);  /* fix the prototype as appropriate */
+  void foo_func2_type(...); /* fix the prototype as appropriate */
+
+  #endif
+
+  #ifdef __cplusplus
+  }
+  #endif
+
+  #define MYSQL_SERVICE_FOO_INCLUDED
+  #endif
+==================================================================
+
+the service_foo.h file should be self-contained, if it needs system headers -
+include them in it, e.g. if you use size_t - #include <stdlib.h>
+
+it should also declare all the accompanying data structures, as necessary
+(e.g. thd_alloc_service declares MYSQL_LEX_STRING).
+
+3. add the new file to include/Makefile.am (pkginclude_HEADERS)
+4. add the new file to include/mysql/services.h
+5. increase the minor plugin ABI version in include/mysql/plugin.h
+   (MYSQL_PLUGIN_INTERFACE_VERSION = MYSQL_PLUGIN_INTERFACE_VERSION+1)
+6. add the version of your service to include/service_versions.h:
+==================================================================
+    #define VERSION_foo 0x0100
+==================================================================
+
+7. create a new file libservices/foo_service.h using the following template:
+==================================================================
+  /* GPL header */
+  #include <service_versions.h>
+  SERVICE_VERSION *foo_service= (void*)VERSION_foo;
+==================================================================
+
+8. add the new file to libservices/CMakeLists.txt (MYSQLSERVICES_SOURCES)
+9. add the new file to libservices/Makefile.am (libmysqlservices_a_SOURCES)
+10. and finally, register your service for dynamic linking in
+    sql/sql_plugin_services.h
+10.1 fill in the service structure:
+==================================================================
+  static struct foo_service_st foo_handler = {
+    foo_func1,
+    foo_func2
+  }
+==================================================================
+
+10.2 and add it to the list of services
+
+==================================================================
+    { "foo_service", VERSION_foo, &foo_handler }
+==================================================================
+
+that's all.
+

=== added file 'libservices/Makefile.am'
--- a/libservices/Makefile.am	1970-01-01 00:00:00 +0000
+++ b/libservices/Makefile.am	2009-11-02 20:05:42 +0000
@@ -0,0 +1,19 @@
+# Copyright 2009 Sun Microsystems, Inc.
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+AM_CPPFLAGS =		-I$(top_srcdir)/include
+pkglib_LIBRARIES =	libmysqlservices.a
+libmysqlservices_a_SOURCES =  my_snprintf_service.c thd_alloc_service.c
+EXTRA_DIST = CMakeLists.txt

=== removed file 'libservices/Makefile.am'
--- a/libservices/Makefile.am	2009-05-06 10:55:56 +0000
+++ b/libservices/Makefile.am	1970-01-01 00:00:00 +0000
@@ -1,19 +0,0 @@
-# Copyright 2009 Sun Microsystems, Inc.
-# 
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 2 of the License.
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-AM_CPPFLAGS =		-I$(top_srcdir)/include
-pkglib_LIBRARIES =	libmysqlservices.a
-libmysqlservices_a_SOURCES =  my_snprintf_service.c thd_alloc_service.c
-EXTRA_DIST = CMakeLists.txt

=== added file 'libservices/my_snprintf_service.c'
--- a/libservices/my_snprintf_service.c	1970-01-01 00:00:00 +0000
+++ b/libservices/my_snprintf_service.c	2009-11-02 20:05:42 +0000
@@ -0,0 +1,17 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include <service_versions.h>
+SERVICE_VERSION my_snprintf_service= (void*)VERSION_my_snprintf;

=== removed file 'libservices/my_snprintf_service.c'
--- a/libservices/my_snprintf_service.c	2009-05-06 18:17:49 +0000
+++ b/libservices/my_snprintf_service.c	1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
-/* Copyright (C) 2009 Sun Microsystems, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-#include <service_versions.h>
-SERVICE_VERSION my_snprintf_service= (void*)VERSION_my_snprintf;

=== added file 'libservices/thd_alloc_service.c'
--- a/libservices/thd_alloc_service.c	1970-01-01 00:00:00 +0000
+++ b/libservices/thd_alloc_service.c	2009-11-05 08:44:22 +0000
@@ -0,0 +1,17 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include <service_versions.h>
+SERVICE_VERSION thd_alloc_service= (void*)VERSION_thd_alloc;

=== removed file 'libservices/thd_alloc_service.c'
--- a/libservices/thd_alloc_service.c	2009-05-24 17:43:19 +0000
+++ b/libservices/thd_alloc_service.c	1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
-/* Copyright (C) 2009 Sun Microsystems, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-#include <service_versions.h>
-SERVICE_VERSION thd_alloc_service= (void*)VERSION_thd_alloc;

=== modified file 'mysql-test/r/partition.result'
--- a/mysql-test/r/partition.result	2009-10-23 06:24:37 +0000
+++ b/mysql-test/r/partition.result	2009-10-30 16:34:50 +0000
@@ -489,14 +489,12 @@ create table t1 (a bigint)
 partition by range (a)
 (partition p0 values less than (0xFFFFFFFFFFFFFFFF),
 partition p1 values less than (10));
-ERROR 42000: VALUES value must be of same type as partition function near '),
-partition p1 values less than (10))' at line 3
+ERROR HY000: VALUES value must be of same type as partition function
 create table t1 (a bigint)
 partition by list (a)
 (partition p0 values in (0xFFFFFFFFFFFFFFFF),
 partition p1 values in (10));
-ERROR 42000: VALUES value must be of same type as partition function near '),
-partition p1 values in (10))' at line 3
+ERROR HY000: VALUES value must be of same type as partition function
 create table t1 (a bigint unsigned)
 partition by range (a)
 (partition p0 values less than (100),
@@ -1490,7 +1488,7 @@ DROP TABLE t1;
 CREATE TABLE t1 (a int)
 PARTITION BY RANGE(a)
 (PARTITION p0 VALUES LESS THAN (NULL));
-ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '))' at line 3
+ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN
 create table t1 (s1 int auto_increment primary key)
 partition by list (s1)
 (partition p1 values in (1),

=== added file 'mysql-test/r/partition_column.result'
--- a/mysql-test/r/partition_column.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/partition_column.result	2009-11-03 11:26:54 +0000
@@ -0,0 +1,518 @@
+drop table if exists t1;
+create table t1 (a varchar(5))
+partition by list columns(a)
+( partition p0 values in ('\''),
+  partition p1 values in ('\\'),
+  partition p2 values in ('\0'));
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` varchar(5) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST  COLUMNS(a)
+(PARTITION p0 VALUES IN ('''') ENGINE = MyISAM,
+ PARTITION p1 VALUES IN ('\\') ENGINE = MyISAM,
+ PARTITION p2 VALUES IN ('\0') ENGINE = MyISAM) */
+drop table t1;
+set @@sql_mode=allow_invalid_dates;
+create table t1 (a char, b char, c date)
+partition by range columns (a,b,c)
+( partition p0 values less than (0,0,to_days('3000-11-31')));
+ERROR HY000: Partition column values of incorrect type
+create table t1 (a char, b char, c date)
+partition by range columns (a,b,c)
+( partition p0 values less than (0,0,'3000-11-31'));
+ERROR HY000: Partition column values of incorrect type
+set @@sql_mode='';
+create table t1 (a int, b char(10), c varchar(25), d datetime)
+partition by range columns(a,b,c,d)
+subpartition by hash (to_seconds(d))
+subpartitions 4
+( partition p0 values less than (1, 0, MAXVALUE, '1900-01-01'),
+partition p1 values less than (1, 'a', MAXVALUE, '1999-01-01'),
+partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE),
+partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE));
+ERROR HY000: Partition column values of incorrect type
+create table t1 (a int, b char(10), c varchar(25), d datetime)
+partition by range columns(a,b,c,d)
+subpartition by hash (to_seconds(d))
+subpartitions 4
+( partition p0 values less than (1, '0', MAXVALUE, '1900-01-01'),
+partition p1 values less than (1, 'a', MAXVALUE, '1999-01-01'),
+partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE),
+partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE));
+select partition_method, partition_expression, partition_description
+from information_schema.partitions where table_name = "t1";
+partition_method	partition_expression	partition_description
+RANGE COLUMNS	a,b,c,d	1,'0',MAXVALUE,'1900-01-01'
+RANGE COLUMNS	a,b,c,d	1,'0',MAXVALUE,'1900-01-01'
+RANGE COLUMNS	a,b,c,d	1,'0',MAXVALUE,'1900-01-01'
+RANGE COLUMNS	a,b,c,d	1,'0',MAXVALUE,'1900-01-01'
+RANGE COLUMNS	a,b,c,d	1,'a',MAXVALUE,'1999-01-01'
+RANGE COLUMNS	a,b,c,d	1,'a',MAXVALUE,'1999-01-01'
+RANGE COLUMNS	a,b,c,d	1,'a',MAXVALUE,'1999-01-01'
+RANGE COLUMNS	a,b,c,d	1,'a',MAXVALUE,'1999-01-01'
+RANGE COLUMNS	a,b,c,d	1,'a',MAXVALUE,MAXVALUE
+RANGE COLUMNS	a,b,c,d	1,'a',MAXVALUE,MAXVALUE
+RANGE COLUMNS	a,b,c,d	1,'a',MAXVALUE,MAXVALUE
+RANGE COLUMNS	a,b,c,d	1,'a',MAXVALUE,MAXVALUE
+RANGE COLUMNS	a,b,c,d	1,MAXVALUE,MAXVALUE,MAXVALUE
+RANGE COLUMNS	a,b,c,d	1,MAXVALUE,MAXVALUE,MAXVALUE
+RANGE COLUMNS	a,b,c,d	1,MAXVALUE,MAXVALUE,MAXVALUE
+RANGE COLUMNS	a,b,c,d	1,MAXVALUE,MAXVALUE,MAXVALUE
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL,
+  `b` char(10) DEFAULT NULL,
+  `c` varchar(25) DEFAULT NULL,
+  `d` datetime DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE  COLUMNS(a,b,c,d)
+SUBPARTITION BY HASH (to_seconds(d))
+SUBPARTITIONS 4
+(PARTITION p0 VALUES LESS THAN (1,'0',MAXVALUE,'1900-01-01') ENGINE = MyISAM,
+ PARTITION p1 VALUES LESS THAN (1,'a',MAXVALUE,'1999-01-01') ENGINE = MyISAM,
+ PARTITION p2 VALUES LESS THAN (1,'a',MAXVALUE,MAXVALUE) ENGINE = MyISAM,
+ PARTITION p3 VALUES LESS THAN (1,MAXVALUE,MAXVALUE,MAXVALUE) ENGINE = MyISAM) */
+drop table t1;
+create table t1 (a int, b int)
+partition by range columns (a,b)
+(partition p0 values less than (NULL, maxvalue));
+ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN
+create table t1 (a int, b int)
+partition by list columns(a,b)
+( partition p0 values in ((maxvalue, 0)));
+Got one of the listed errors
+create table t1 (a int, b int)
+partition by list columns (a,b)
+( partition p0 values in ((0,0)));
+alter table t1 add partition
+(partition p1 values in (maxvalue, maxvalue));
+Got one of the listed errors
+drop table t1;
+create table t1 (a int, b int)
+partition by key (a,a);
+ERROR HY000: Duplicate partition field name 'a'
+create table t1 (a int, b int)
+partition by list columns(a,a)
+( partition p values in ((1,1)));
+ERROR HY000: Duplicate partition field name 'a'
+create table t1 (a int signed)
+partition by list (a)
+( partition p0 values in (1, 3, 5, 7, 9, NULL),
+partition p1 values in (2, 4, 6, 8, 0));
+insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8);
+select * from t1 where NULL <= a;
+a
+select * from t1 where a is null;
+a
+NULL
+explain partitions select * from t1 where a is null;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	ALL	NULL	NULL	NULL	NULL	10	Using where
+select * from t1 where a <= 1;
+a
+1
+0
+drop table t1;
+create table t1 (a int signed)
+partition by list columns(a)
+( partition p0 values in (1, 3, 5, 7, 9, NULL),
+partition p1 values in (2, 4, 6, 8, 0));
+insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8);
+select * from t1 where a <= NULL;
+a
+select * from t1 where a is null;
+a
+NULL
+explain partitions select * from t1 where a is null;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	ALL	NULL	NULL	NULL	NULL	2	Using where
+select * from t1 where a <= 1;
+a
+1
+0
+drop table t1;
+create table t1 (a int, b int)
+partition by list columns(a,b)
+( partition p0 values in ((1, NULL), (2, NULL), (NULL, NULL)),
+partition p1 values in ((1,1), (2,2)),
+partition p2 values in ((3, NULL), (NULL, 1)));
+select partition_method, partition_expression, partition_description
+from information_schema.partitions where table_name = "t1";
+partition_method	partition_expression	partition_description
+LIST COLUMNS	a,b	(1,NULL),(2,NULL),(NULL,NULL)
+LIST COLUMNS	a,b	(1,1),(2,2)
+LIST COLUMNS	a,b	(3,NULL),(NULL,1)
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL,
+  `b` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST  COLUMNS(a,b)
+(PARTITION p0 VALUES IN ((1,NULL),(2,NULL),(NULL,NULL)) ENGINE = MyISAM,
+ PARTITION p1 VALUES IN ((1,1),(2,2)) ENGINE = MyISAM,
+ PARTITION p2 VALUES IN ((3,NULL),(NULL,1)) ENGINE = MyISAM) */
+insert into t1 values (3, NULL);
+insert into t1 values (NULL, 1);
+insert into t1 values (NULL, NULL);
+insert into t1 values (1, NULL);
+insert into t1 values (2, NULL);
+insert into t1 values (1,1);
+insert into t1 values (2,2);
+select * from t1 where a = 1;
+a	b
+1	NULL
+1	1
+select * from t1 where a = 2;
+a	b
+2	NULL
+2	2
+select * from t1 where a > 8;
+a	b
+select * from t1 where a not between 8 and 8;
+a	b
+2	NULL
+2	2
+3	NULL
+1	NULL
+1	1
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL,
+  `b` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST  COLUMNS(a,b)
+(PARTITION p0 VALUES IN ((1,NULL),(2,NULL),(NULL,NULL)) ENGINE = MyISAM,
+ PARTITION p1 VALUES IN ((1,1),(2,2)) ENGINE = MyISAM,
+ PARTITION p2 VALUES IN ((3,NULL),(NULL,1)) ENGINE = MyISAM) */
+drop table t1;
+create table t1 (a int)
+partition by list (a)
+( partition p0 values in (1),
+partition p1 values in (1));
+ERROR HY000: Multiple definition of same constant in list partitioning
+create table t1 (a int)
+partition by list (a)
+( partition p0 values in (2, 1),
+partition p1 values in (4, NULL, 3));
+select partition_method, partition_expression, partition_description
+from information_schema.partitions where table_name = "t1";
+partition_method	partition_expression	partition_description
+LIST	a	2,1
+LIST	a	NULL,4,3
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (a)
+(PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM,
+ PARTITION p1 VALUES IN (NULL,4,3) ENGINE = MyISAM) */
+insert into t1 values (1);
+insert into t1 values (2);
+insert into t1 values (3);
+insert into t1 values (4);
+insert into t1 values (NULL);
+insert into t1 values (5);
+ERROR HY000: Table has no partition for value 5
+drop table t1;
+create table t1 (a int)
+partition by list columns(a)
+( partition p0 values in (2, 1),
+partition p1 values in ((4), (NULL), (3)));
+ERROR 42000: Row expressions in VALUES IN only allowed for multi-field column partitioning near '))' at line 4
+create table t1 (a int)
+partition by list columns(a)
+( partition p0 values in (2, 1),
+partition p1 values in (4, NULL, 3));
+select partition_method, partition_expression, partition_description
+from information_schema.partitions where table_name = "t1";
+partition_method	partition_expression	partition_description
+LIST COLUMNS	a	2,1
+LIST COLUMNS	a	4,NULL,3
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST  COLUMNS(a)
+(PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM,
+ PARTITION p1 VALUES IN (4,NULL,3) ENGINE = MyISAM) */
+insert into t1 values (1);
+insert into t1 values (2);
+insert into t1 values (3);
+insert into t1 values (4);
+insert into t1 values (NULL);
+insert into t1 values (5);
+ERROR HY000: Table has no partition for value from column_list
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST  COLUMNS(a)
+(PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM,
+ PARTITION p1 VALUES IN (4,NULL,3) ENGINE = MyISAM) */
+drop table t1;
+create table t1 (a int, b char(10), c varchar(5), d int)
+partition by range columns(a,b,c)
+subpartition by key (c,d)
+subpartitions 3
+( partition p0 values less than (1,'abc','abc'),
+partition p1 values less than (2,'abc','abc'),
+partition p2 values less than (3,'abc','abc'),
+partition p3 values less than (4,'abc','abc'));
+select partition_method, partition_expression, partition_description
+from information_schema.partitions where table_name = "t1";
+partition_method	partition_expression	partition_description
+RANGE COLUMNS	a,b,c	1,'abc','abc'
+RANGE COLUMNS	a,b,c	1,'abc','abc'
+RANGE COLUMNS	a,b,c	1,'abc','abc'
+RANGE COLUMNS	a,b,c	2,'abc','abc'
+RANGE COLUMNS	a,b,c	2,'abc','abc'
+RANGE COLUMNS	a,b,c	2,'abc','abc'
+RANGE COLUMNS	a,b,c	3,'abc','abc'
+RANGE COLUMNS	a,b,c	3,'abc','abc'
+RANGE COLUMNS	a,b,c	3,'abc','abc'
+RANGE COLUMNS	a,b,c	4,'abc','abc'
+RANGE COLUMNS	a,b,c	4,'abc','abc'
+RANGE COLUMNS	a,b,c	4,'abc','abc'
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL,
+  `b` char(10) DEFAULT NULL,
+  `c` varchar(5) DEFAULT NULL,
+  `d` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE  COLUMNS(a,b,c)
+SUBPARTITION BY KEY (c,d)
+SUBPARTITIONS 3
+(PARTITION p0 VALUES LESS THAN (1,'abc','abc') ENGINE = MyISAM,
+ PARTITION p1 VALUES LESS THAN (2,'abc','abc') ENGINE = MyISAM,
+ PARTITION p2 VALUES LESS THAN (3,'abc','abc') ENGINE = MyISAM,
+ PARTITION p3 VALUES LESS THAN (4,'abc','abc') ENGINE = MyISAM) */
+insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3);
+insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3);
+insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3);
+insert into t1 values (1,'d','e',1),(2,'d','e',2),(3,'d','e',3);
+select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) OR
+(a = 1 AND b >= 'a' AND (c = 'c' OR (c = 'd' AND d = 2))));
+a	b	c	d
+1	a	b	1
+1	b	c	1
+drop table t1;
+create table t1 (a int, b varchar(2), c int)
+partition by range columns (a, b, c)
+(partition p0 values less than (1, 'A', 1),
+partition p1 values less than (1, 'B', 1));
+select partition_method, partition_expression, partition_description
+from information_schema.partitions where table_name = "t1";
+partition_method	partition_expression	partition_description
+RANGE COLUMNS	a,b,c	1,'A',1
+RANGE COLUMNS	a,b,c	1,'B',1
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL,
+  `b` varchar(2) DEFAULT NULL,
+  `c` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE  COLUMNS(a,b,c)
+(PARTITION p0 VALUES LESS THAN (1,'A',1) ENGINE = MyISAM,
+ PARTITION p1 VALUES LESS THAN (1,'B',1) ENGINE = MyISAM) */
+insert into t1 values (1, 'A', 1);
+explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0,p1	system	NULL	NULL	NULL	NULL	1	
+select * from t1 where a = 1 AND b <= 'A' and c = 1;
+a	b	c
+1	A	1
+drop table t1;
+create table t1 (a char, b char, c char)
+partition by list columns(a)
+( partition p0 values in ('a'));
+insert into t1 (a) values ('a');
+select * from t1 where a = 'a';
+a	b	c
+a	NULL	NULL
+drop table t1;
+create table t1 (d time)
+partition by range columns(d)
+( partition p0 values less than ('2000-01-01'),
+partition p1 values less than ('2040-01-01'));
+ERROR HY000: Partition column values of incorrect type
+create table t1 (d timestamp)
+partition by range columns(d)
+( partition p0 values less than ('2000-01-01'),
+partition p1 values less than ('2040-01-01'));
+ERROR HY000: Field 'd' is of a not allowed type for this type of partitioning
+create table t1 (d bit(1))
+partition by range columns(d)
+( partition p0 values less than (0),
+partition p1 values less than (1));
+ERROR HY000: Field 'd' is of a not allowed type for this type of partitioning
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (maxvalue, 10));
+drop table t1;
+create table t1 (d date)
+partition by range columns(d)
+( partition p0 values less than ('2000-01-01'),
+partition p1 values less than ('2009-01-01'));
+drop table t1;
+create table t1 (d date)
+partition by range columns(d)
+( partition p0 values less than ('1999-01-01'),
+partition p1 values less than ('2000-01-01'));
+drop table t1;
+create table t1 (d date)
+partition by range columns(d)
+( partition p0 values less than ('2000-01-01'),
+partition p1 values less than ('3000-01-01'));
+drop table t1;
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p2 values less than (99,99),
+partition p1 values less than (99,999));
+insert into t1 values (99,998);
+select * from t1 where b = 998;
+a	b
+99	998
+drop table t1;
+create table t1 as select to_seconds(null) as to_seconds;
+select data_type from information_schema.columns
+where column_name='to_seconds';
+data_type
+int
+drop table t1;
+create table t1 (a int, b int)
+partition by list columns(a,b)
+(partition p0 values in ((maxvalue,maxvalue)));
+ERROR 42000: Cannot use MAXVALUE as value in VALUES IN near 'maxvalue,maxvalue)))' at line 3
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (maxvalue,maxvalue));
+drop table t1;
+create table t1 (a int)
+partition by list columns(a)
+(partition p0 values in (0));
+select partition_method from information_schema.partitions where table_name='t1';
+partition_method
+LIST COLUMNS
+drop table t1;
+create table t1 (a char(6))
+partition by range columns(a)
+(partition p0 values less than ('H23456'),
+partition p1 values less than ('M23456'));
+insert into t1 values ('F23456');
+select * from t1;
+a
+F23456
+drop table t1;
+create table t1 (a char(6))
+partition by range columns(a)
+(partition p0 values less than (H23456),
+partition p1 values less than (M23456));
+ERROR 42S22: Unknown column 'H23456' in 'field list'
+create table t1 (a char(6))
+partition by range columns(a)
+(partition p0 values less than (23456),
+partition p1 values less than (23456));
+ERROR HY000: Partition column values of incorrect type
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (10));
+ERROR 42000: Inconsistency in usage of column lists for partitioning near '))' at line 3
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (1,1,1);
+ERROR HY000: Inconsistency in usage of column lists for partitioning
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (1, 0),
+partition p1 values less than (2, maxvalue),
+partition p2 values less than (3, 3),
+partition p3 values less than (10, maxvalue));
+insert into t1 values (11,0);
+ERROR HY000: Table has no partition for value from column_list
+insert into t1 values (0,1),(1,1),(2,1),(3,1),(3,4),(4,9),(9,1);
+select * from t1;
+a	b
+0	1
+1	1
+2	1
+3	1
+3	4
+4	9
+9	1
+alter table t1
+partition by range columns(b,a)
+(partition p0 values less than (1,2),
+partition p1 values less than (3,3),
+partition p2 values less than (9,5));
+explain partitions select * from t1 where b < 2;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0,p1	ALL	NULL	NULL	NULL	NULL	7	Using where
+select * from t1 where b < 2;
+a	b
+0	1
+1	1
+2	1
+3	1
+9	1
+explain partitions select * from t1 where b < 4;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0,p1,p2	ALL	NULL	NULL	NULL	NULL	7	Using where
+select * from t1 where b < 4;
+a	b
+0	1
+1	1
+2	1
+3	1
+9	1
+alter table t1 reorganize partition p1 into
+(partition p11 values less than (2,2),
+partition p12 values less than (3,3));
+alter table t1 reorganize partition p0 into
+(partition p01 values less than (0,3),
+partition p02 values less than (1,1));
+ERROR HY000: Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range
+alter table t1 reorganize partition p2 into
+(partition p2 values less than(9,6,1));
+ERROR HY000: Inconsistency in usage of column lists for partitioning
+alter table t1 reorganize partition p2 into
+(partition p2 values less than (10));
+ERROR HY000: Inconsistency in usage of column lists for partitioning
+alter table t1 reorganize partition p2 into
+(partition p21 values less than (4,7),
+partition p22 values less than (9,5));
+explain partitions select * from t1 where b < 4;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0,p11,p12,p21	ALL	NULL	NULL	NULL	NULL	7	Using where
+select * from t1 where b < 4;
+a	b
+0	1
+1	1
+2	1
+3	1
+9	1
+drop table t1;
+create table t1 (a int, b int)
+partition by list columns(a,b)
+subpartition by hash (b)
+subpartitions 2
+(partition p0 values in ((0,0), (1,1)),
+partition p1 values in ((1000,1000)));
+insert into t1 values (1000,1000);
+drop table t1;
+create table t1 (a char, b char, c char)
+partition by range columns(a,b,c)
+( partition p0 values less than ('a','b','c'));
+alter table t1 add partition
+(partition p1 values less than ('b','c','d'));
+drop table t1;

=== added file 'mysql-test/r/partition_column_prune.result'
--- a/mysql-test/r/partition_column_prune.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/partition_column_prune.result	2009-10-30 20:43:49 +0000
@@ -0,0 +1,66 @@
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+create table t1 (a char, b char, c char)
+partition by range columns(a,b,c)
+( partition p0 values less than ('a','b','c'));
+insert into t1 values ('a', NULL, 'd');
+explain partitions select * from t1 where a = 'a' AND c = 'd';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	system	NULL	NULL	NULL	NULL	1	
+select * from t1 where a = 'a' AND c = 'd';
+a	b	c
+a	NULL	d
+drop table t1;
+create table t1 (a int not null) partition by range columns(a) (
+partition p0 values less than (10),
+partition p1 values less than (20),
+partition p2 values less than (30),
+partition p3 values less than (40),
+partition p4 values less than (50),
+partition p5 values less than (60),
+partition p6 values less than (70)
+);
+insert into t1 values (5),(15),(25),(35),(45),(55),(65);
+insert into t1 values (5),(15),(25),(35),(45),(55),(65);
+create table t2 (a int not null) partition by range(a) (
+partition p0 values less than (10),
+partition p1 values less than (20),
+partition p2 values less than (30),
+partition p3 values less than (40),
+partition p4 values less than (50),
+partition p5 values less than (60),
+partition p6 values less than (70)
+);
+insert into t2 values (5),(15),(25),(35),(45),(55),(65);
+insert into t2 values (5),(15),(25),(35),(45),(55),(65);
+explain partitions select * from t1 where a > 35 and a < 45;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p3,p4	ALL	NULL	NULL	NULL	NULL	4	Using where
+explain partitions select * from t2 where a > 35 and a < 45;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t2	p3,p4	ALL	NULL	NULL	NULL	NULL	4	Using where
+drop table t1, t2;
+create table t1 (a int not null, b int not null ) 
+partition by range columns(a,b) (
+partition p01 values less than (2,10),
+partition p02 values less than (2,20),
+partition p03 values less than (2,30),
+partition p11 values less than (4,10),
+partition p12 values less than (4,20),
+partition p13 values less than (4,30),
+partition p21 values less than (6,10),
+partition p22 values less than (6,20),
+partition p23 values less than (6,30)
+);
+insert into t1 values (2,5), (2,15), (2,25),
+(4,5), (4,15), (4,25), (6,5), (6,15), (6,25);
+insert into t1 select * from t1;
+explain partitions select * from t1 where a=2;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p01,p02,p03,p11	ALL	NULL	NULL	NULL	NULL	8	Using where
+explain partitions select * from t1 where a=4;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p11,p12,p13,p21	ALL	NULL	NULL	NULL	NULL	14	Using where
+explain partitions select * from t1 where a=2 and b < 22;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p01,p02,p03	ALL	NULL	NULL	NULL	NULL	14	Using where
+drop table t1;

=== modified file 'mysql-test/r/partition_datatype.result'
--- a/mysql-test/r/partition_datatype.result	2008-12-09 11:16:39 +0000
+++ b/mysql-test/r/partition_datatype.result	2009-10-30 20:43:49 +0000
@@ -273,7 +273,7 @@ select * from t1 where a = 'y';
 a
 y
 drop table t1;
-create table t1 (a varchar(65531)) partition by key (a);
+create table t1 (a varchar(4092)) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
@@ -286,7 +286,7 @@ select * from t1 where a = 'bbbb';
 a
 bbbb
 drop table t1;
-create table t1 (a varchar(65532)) partition by key (a);
+create table t1 (a varchar(4093)) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
@@ -299,7 +299,7 @@ select * from t1 where a = 'bbbb';
 a
 bbbb
 drop table t1;
-create table t1 (a varchar(65533) not null) partition by key (a);
+create table t1 (a varchar(4094) not null) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
@@ -312,6 +312,8 @@ select * from t1 where a = 'bbbb';
 a
 bbbb
 drop table t1;
+create table t1 (a varchar(4094)) partition by key (a);
+ERROR HY000: The total length of the partitioning fields is too large
 create table t1 (a varchar(65533)) partition by key (a);
 ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs
 create table t1 (a varchar(65534) not null) partition by key (a);

=== modified file 'mysql-test/r/partition_error.result'
--- a/mysql-test/r/partition_error.result	2009-07-23 15:41:27 +0000
+++ b/mysql-test/r/partition_error.result	2009-10-30 16:34:50 +0000
@@ -366,8 +366,7 @@ partition by range (a)
 partitions 2

 (partition x1 values less than (4.0) tablespace ts1,
 partition x2 values less than (8) tablespace ts2);
-ERROR 42000: VALUES value must be of same type as partition function near ') tablespace ts1,
-partition x2 values less than (8) tablespace ts2)' at line 8
+ERROR HY000: VALUES value must be of same type as partition function
 CREATE TABLE t1 (
 a int not null,
 b int not null,
@@ -417,8 +416,7 @@ partition by list (a)
 partitions 2
 (partition x1 values less than 4,
 partition x2 values less than (5));
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '4,
-partition x2 values less than (5))' at line 8
+ERROR HY000: Only RANGE PARTITIONING can use VALUES LESS THAN in partition definition
 CREATE TABLE t1 (
 a int not null,
 b int not null,
@@ -428,7 +426,7 @@ partition by range (a)
 partitions 2
 (partition x1 values less than maxvalue,
 partition x2 values less than (5));
-ERROR 42000: MAXVALUE can only be used in last partition definition near '))' at line 9
+ERROR HY000: MAXVALUE can only be used in last partition definition
 CREATE TABLE t1 (
 a int not null,
 b int not null,
@@ -438,7 +436,7 @@ partition by range (a)
 partitions 2
 (partition x1 values less than maxvalue,
 partition x2 values less than maxvalue);
-ERROR 42000: MAXVALUE can only be used in last partition definition near 'maxvalue)' at line 9
+ERROR HY000: MAXVALUE can only be used in last partition definition
 CREATE TABLE t1 (
 a int not null,
 b int not null,
@@ -607,8 +605,7 @@ partition by list (a)
 partitions 2
 (partition x1 values in (4.0, 12+8),
 partition x2 values in (3, 21));
-ERROR 42000: VALUES value must be of same type as partition function near ' 12+8),
-partition x2 values in (3, 21))' at line 8
+ERROR HY000: VALUES value must be of same type as partition function
 CREATE TABLE t1 (
 a int not null,
 b int not null,

=== modified file 'mysql-test/r/partition_innodb.result'
--- a/mysql-test/r/partition_innodb.result	2009-09-16 08:23:16 +0000
+++ b/mysql-test/r/partition_innodb.result	2009-10-30 16:34:50 +0000
@@ -1,4 +1,28 @@
 drop table if exists t1;
+create table t1 (a varchar(5))
+engine=memory
+partition by range columns(a)
+( partition p0 values less than ('m'),
+partition p1 values less than ('za'));
+insert into t1 values  ('j');
+update t1 set a = 'z' where (a >= 'j');
+drop table t1;
+create table t1 (a varchar(5))
+engine=myisam
+partition by range columns(a)
+( partition p0 values less than ('m'),
+partition p1 values less than ('za'));
+insert into t1 values  ('j');
+update t1 set a = 'z' where (a >= 'j');
+drop table t1;
+create table t1 (a varchar(5))
+engine=innodb
+partition by range columns(a)
+( partition p0 values less than ('m'),
+partition p1 values less than ('za'));
+insert into t1 values  ('j');
+update t1 set a = 'z' where (a >= 'j');
+drop table t1;
 create table t1 (a int not null,
 b datetime not null,
 primary key (a,b))

=== modified file 'mysql-test/r/partition_list.result'
--- a/mysql-test/r/partition_list.result	2007-04-20 16:35:16 +0000
+++ b/mysql-test/r/partition_list.result	2009-10-21 18:04:34 +0000
@@ -54,6 +54,17 @@ subpartitions 2
 partition p1 values in (1),
 partition pnull values in (null, 2),
 partition p3 values in (3));
+select partition_method, partition_expression, partition_description
+from information_schema.partitions where table_name = "t1";
+partition_method	partition_expression	partition_description
+LIST	a	0
+LIST	a	0
+LIST	a	1
+LIST	a	1
+LIST	a	NULL,2
+LIST	a	NULL,2
+LIST	a	3
+LIST	a	3
 insert into t1 values (0,0),(0,1),(1,0),(1,1),(null,0),(null,1);
 insert into t1 values (2,0),(2,1),(3,0),(3,1);
 explain partitions select * from t1 where a is null;

=== modified file 'mysql-test/r/partition_mgm_err.result'
--- a/mysql-test/r/partition_mgm_err.result	2009-02-20 12:37:37 +0000
+++ b/mysql-test/r/partition_mgm_err.result	2009-10-30 16:34:50 +0000
@@ -41,7 +41,7 @@ ERROR HY000: Reorganize of range partiti
 ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO
 (PARTITION x01 VALUES LESS THAN (4),
 PARTITION x11 VALUES LESS THAN (2));
-ERROR HY000: Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range
+ERROR HY000: VALUES LESS THAN value must be strictly increasing for each partition
 ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO
 (PARTITION x01 VALUES LESS THAN (6),
 PARTITION x11 VALUES LESS THAN (4));

=== modified file 'mysql-test/r/partition_pruning.result'
--- a/mysql-test/r/partition_pruning.result	2009-10-30 15:36:45 +0000
+++ b/mysql-test/r/partition_pruning.result	2009-11-06 16:34:09 +0000
@@ -656,6 +656,335 @@ EXPLAIN PARTITIONS SELECT * FROM t1 WHER
 id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	p0001-01-01,pNULL,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
 DROP TABLE t1;
+# TO_SECONDS, test of LIST and index
+CREATE TABLE t1 (a DATE, KEY(a))
+PARTITION BY LIST (TO_SECONDS(a))
+(PARTITION `p0001-01-01` VALUES IN (TO_SECONDS('0001-01-01')),
+PARTITION `p2001-01-01` VALUES IN (TO_SECONDS('2001-01-01')),
+PARTITION `pNULL` VALUES IN (NULL),
+PARTITION `p0000-01-02` VALUES IN (TO_SECONDS('0000-01-02')),
+PARTITION `p1001-01-01` VALUES IN (TO_SECONDS('1001-01-01')));
+INSERT INTO t1 VALUES ('0000-00-00'), ('0000-01-02'), ('0001-01-01'),
+('1001-00-00'), ('1001-01-01'), ('1002-00-00'), ('2001-01-01');
+SELECT * FROM t1 WHERE a < '1001-01-01';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+SELECT * FROM t1 WHERE a <= '1001-01-01';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+SELECT * FROM t1 WHERE a >= '1001-01-01';
+a
+1001-01-01
+1002-00-00
+2001-01-01
+SELECT * FROM t1 WHERE a > '1001-01-01';
+a
+1002-00-00
+2001-01-01
+SELECT * FROM t1 WHERE a = '1001-01-01';
+a
+1001-01-01
+SELECT * FROM t1 WHERE a < '1001-00-00';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+SELECT * FROM t1 WHERE a <= '1001-00-00';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+SELECT * FROM t1 WHERE a >= '1001-00-00';
+a
+1001-00-00
+1001-01-01
+1002-00-00
+2001-01-01
+SELECT * FROM t1 WHERE a > '1001-00-00';
+a
+1001-01-01
+1002-00-00
+2001-01-01
+SELECT * FROM t1 WHERE a = '1001-00-00';
+a
+1001-00-00
+# Disabling warnings for the invalid date
+SELECT * FROM t1 WHERE a < '1999-02-31';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+1002-00-00
+SELECT * FROM t1 WHERE a <= '1999-02-31';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+1002-00-00
+SELECT * FROM t1 WHERE a >= '1999-02-31';
+a
+2001-01-01
+SELECT * FROM t1 WHERE a > '1999-02-31';
+a
+2001-01-01
+SELECT * FROM t1 WHERE a = '1999-02-31';
+a
+SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+1002-00-00
+SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1001-01-01';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+SELECT * FROM t1 WHERE a BETWEEN '0001-01-02' AND '1002-00-00';
+a
+1001-00-00
+1001-01-01
+1002-00-00
+SELECT * FROM t1 WHERE a BETWEEN '0001-01-01' AND '1001-01-01';
+a
+0001-01-01
+1001-00-00
+1001-01-01
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02	range	a	a	4	NULL	3	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	range	a	a	4	NULL	4	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL,p1001-01-01	range	a	a	4	NULL	4	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL	range	a	a	4	NULL	3	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p1001-01-01	system	a	NULL	NULL	NULL	1	
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02	range	a	a	4	NULL	3	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02	range	a	a	4	NULL	3	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL,p1001-01-01	range	a	a	4	NULL	4	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL,p1001-01-01	range	a	a	4	NULL	4	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	pNULL	ref	a	a	4	const	1	Using index
+# Disabling warnings for the invalid date
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	range	a	a	4	NULL	5	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	range	a	a	4	NULL	5	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL	range	a	a	4	NULL	2	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL	range	a	a	4	NULL	2	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	pNULL	ref	a	a	4	const	1	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	range	a	a	4	NULL	5	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	range	a	a	4	NULL	4	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0001-01-02' AND '1002-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	pNULL,p1001-01-01	range	a	a	4	NULL	2	Using where; Using index
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0001-01-01' AND '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p1001-01-01	range	a	a	4	NULL	3	Using where; Using index
+# test without index
+ALTER TABLE t1 DROP KEY a;
+SELECT * FROM t1 WHERE a < '1001-01-01';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+SELECT * FROM t1 WHERE a <= '1001-01-01';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+SELECT * FROM t1 WHERE a >= '1001-01-01';
+a
+1001-01-01
+1002-00-00
+2001-01-01
+SELECT * FROM t1 WHERE a > '1001-01-01';
+a
+1002-00-00
+2001-01-01
+SELECT * FROM t1 WHERE a = '1001-01-01';
+a
+1001-01-01
+SELECT * FROM t1 WHERE a < '1001-00-00';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+SELECT * FROM t1 WHERE a <= '1001-00-00';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+SELECT * FROM t1 WHERE a >= '1001-00-00';
+a
+1001-00-00
+1001-01-01
+1002-00-00
+2001-01-01
+SELECT * FROM t1 WHERE a > '1001-00-00';
+a
+1001-01-01
+1002-00-00
+2001-01-01
+SELECT * FROM t1 WHERE a = '1001-00-00';
+a
+1001-00-00
+# Disabling warnings for the invalid date
+SELECT * FROM t1 WHERE a < '1999-02-31';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+1002-00-00
+SELECT * FROM t1 WHERE a <= '1999-02-31';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+1002-00-00
+SELECT * FROM t1 WHERE a >= '1999-02-31';
+a
+2001-01-01
+SELECT * FROM t1 WHERE a > '1999-02-31';
+a
+2001-01-01
+SELECT * FROM t1 WHERE a = '1999-02-31';
+a
+SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+1002-00-00
+SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1001-01-01';
+a
+0000-00-00
+0000-01-02
+0001-01-01
+1001-00-00
+1001-01-01
+SELECT * FROM t1 WHERE a BETWEEN '0001-01-02' AND '1002-00-00';
+a
+1001-00-00
+1001-01-01
+1002-00-00
+SELECT * FROM t1 WHERE a BETWEEN '0001-01-01' AND '1001-01-01';
+a
+0001-01-01
+1001-00-00
+1001-01-01
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p1001-01-01	system	NULL	NULL	NULL	NULL	1	
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1001-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	pNULL	ALL	NULL	NULL	NULL	NULL	7	Using where
+# Disabling warnings for the invalid date
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2001-01-01,pNULL	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1999-02-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	pNULL	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p0000-01-02,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0001-01-02' AND '1002-00-00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	pNULL,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0001-01-01' AND '1001-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0001-01-01,pNULL,p1001-01-01	ALL	NULL	NULL	NULL	NULL	7	Using where
+DROP TABLE t1;
 # Test with DATETIME column NOT NULL
 CREATE TABLE t1 (
 a int(10) unsigned NOT NULL,

=== modified file 'mysql-test/r/partition_range.result'
--- a/mysql-test/r/partition_range.result	2009-08-28 11:56:31 +0000
+++ b/mysql-test/r/partition_range.result	2009-10-30 16:34:50 +0000
@@ -1,6 +1,99 @@
 drop table if exists t1, t2;
 create table t1 (a int)
 partition by range (a)
+( partition p0 values less than (NULL),
+partition p1 values less than (MAXVALUE));
+ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN
+create table t1 (a datetime not null)
+partition by range (TO_SECONDS(a))
+( partition p0 VALUES LESS THAN (TO_SECONDS('2007-03-08 00:00:00')),
+partition p1 VALUES LESS THAN (TO_SECONDS('2007-04-01 00:00:00')));
+select partition_method, partition_expression, partition_description
+from information_schema.partitions where table_name = "t1";
+partition_method	partition_expression	partition_description
+RANGE	TO_SECONDS(a)	63340531200
+RANGE	TO_SECONDS(a)	63342604800
+INSERT INTO t1 VALUES ('2007-03-01 12:00:00'), ('2007-03-07 12:00:00');
+INSERT INTO t1 VALUES ('2007-03-08 12:00:00'), ('2007-03-15 12:00:00');
+explain partitions select * from t1 where a < '2007-03-08 00:00:00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	ALL	NULL	NULL	NULL	NULL	2	Using where
+explain partitions select * from t1 where a < '2007-03-08 00:00:01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0,p1	ALL	NULL	NULL	NULL	NULL	4	Using where
+explain partitions select * from t1 where a <= '2007-03-08 00:00:00';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0,p1	ALL	NULL	NULL	NULL	NULL	4	Using where
+explain partitions select * from t1 where a <= '2007-03-07 23:59:59';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	ALL	NULL	NULL	NULL	NULL	4	Using where
+explain partitions select * from t1 where a < '2007-03-07 23:59:59';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	ALL	NULL	NULL	NULL	NULL	4	Using where
+drop table t1;
+create table t1 (a date)
+partition by range(to_seconds(a))
+(partition p0 values less than (to_seconds('2004-01-01')),
+partition p1 values less than (to_seconds('2005-01-01')));
+insert into t1 values ('2003-12-30'),('2004-12-31');
+select * from t1;
+a
+2003-12-30
+2004-12-31
+explain partitions select * from t1 where a <= '2003-12-31';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	system	NULL	NULL	NULL	NULL	1	
+select * from t1 where a <= '2003-12-31';
+a
+2003-12-30
+explain partitions select * from t1 where a <= '2005-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0,p1	ALL	NULL	NULL	NULL	NULL	2	Using where
+select * from t1 where a <= '2005-01-01';
+a
+2003-12-30
+2004-12-31
+drop table t1;
+create table t1 (a datetime)
+partition by range(to_seconds(a))
+(partition p0 values less than (to_seconds('2004-01-01 12:00:00')),
+partition p1 values less than (to_seconds('2005-01-01 12:00:00')));
+insert into t1 values ('2004-01-01 11:59:29'),('2005-01-01 11:59:59');
+select * from t1;
+a
+2004-01-01 11:59:29
+2005-01-01 11:59:59
+explain partitions select * from t1 where a <= '2004-01-01 11:59.59';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	system	NULL	NULL	NULL	NULL	1	
+select * from t1 where a <= '2004-01-01 11:59:59';
+a
+2004-01-01 11:59:29
+explain partitions select * from t1 where a <= '2005-01-01';
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0,p1	ALL	NULL	NULL	NULL	NULL	2	Using where
+select * from t1 where a <= '2005-01-01';
+a
+2004-01-01 11:59:29
+drop table t1;
+create table t1 (a int, b char(20))
+partition by range columns(a,b)
+(partition p0 values less than (1));
+ERROR 42000: Inconsistency in usage of column lists for partitioning near '))' at line 3
+create table t1 (a int, b char(20))
+partition by range(a)
+(partition p0 values less than (1,"b"));
+ERROR HY000: Cannot have more than one value for this type of RANGE partitioning
+create table t1 (a int, b char(20))
+partition by range(a)
+(partition p0 values less than (1,"b"));
+ERROR HY000: Cannot have more than one value for this type of RANGE partitioning
+create table t1 (a int, b char(20))
+partition by range columns(b)
+(partition p0 values less than ("b"));
+drop table t1;
+create table t1 (a int)
+partition by range (a)
 ( partition p0 values less than (maxvalue));
 alter table t1 add partition (partition p1 values less than (100000));
 ERROR HY000: MAXVALUE can only be used in last partition definition

=== added file 'mysql-test/r/partition_utf8.result'
--- a/mysql-test/r/partition_utf8.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/partition_utf8.result	2009-11-03 11:37:39 +0000
@@ -0,0 +1,53 @@
+set names utf8;
+create table t1 (a varchar(2) character set cp1250)
+partition by list columns (a)
+( partition p0 values in (0x81));
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` varchar(2) CHARACTER SET cp1250 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST  COLUMNS(a)
+(PARTITION p0 VALUES IN (_cp1250 0x81) ENGINE = MyISAM) */
+drop table t1;
+create table t1 (a varchar(2) character set cp1250)
+partition by list columns (a)
+( partition p0 values in (0x80));
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` varchar(2) CHARACTER SET cp1250 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST  COLUMNS(a)
+(PARTITION p0 VALUES IN ('€') ENGINE = MyISAM) */
+drop table t1;
+create table t1 (a varchar(2000), b varchar(2094))
+partition by list columns(a,b)
+( partition p0 values in (('a','b')));
+ERROR HY000: The total length of the partitioning fields is too large
+create table t1 (a varchar(1023) character set utf8 collate utf8_spanish2_ci)
+partition by range columns(a)
+( partition p0 values less than ('CZ'),
+partition p1 values less than ('CH'),
+partition p2 values less than ('D'));
+insert into t1 values ('czz'),('chi'),('ci'),('cg');
+select * from t1 where a between 'cg' AND 'ci';
+a
+ci
+cg
+drop table t1;
+create table t1 (a varchar(2) character set ucs2)
+partition by list columns (a)
+(partition p0 values in (0x2020),
+partition p1 values in (''));
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` varchar(2) CHARACTER SET ucs2 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST  COLUMNS(a)
+(PARTITION p0 VALUES IN ('†') ENGINE = MyISAM,
+ PARTITION p1 VALUES IN ('') ENGINE = MyISAM) */
+insert into t1 values ('');
+insert into t1 values (_ucs2 0x2020);
+drop table t1;

=== modified file 'mysql-test/r/type_decimal.result'
--- a/mysql-test/r/type_decimal.result	2008-04-28 18:14:22 +0000
+++ b/mysql-test/r/type_decimal.result	2009-10-31 09:49:47 +0000
@@ -3,13 +3,13 @@ SET SQL_WARNINGS=1;
 CREATE TABLE t1 (
 id int(11) NOT NULL auto_increment,
 datatype_id int(11) DEFAULT '0' NOT NULL,
-minvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
-maxvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
+min_value decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
+max_value decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
 valuename varchar(20),
 forecolor int(11),
 backcolor int(11),
 PRIMARY KEY (id),
-UNIQUE datatype_id (datatype_id, minvalue, maxvalue)
+UNIQUE datatype_id (datatype_id, min_value, max_value)
 );
 INSERT INTO t1 VALUES ( '1', '4', '0.0000000000', '0.0000000000', 'Ei saja', '0', '16776960');
 INSERT INTO t1 VALUES ( '2', '4', '1.0000000000', '1.0000000000', 'Sajab', '16777215', '255');
@@ -143,12 +143,12 @@ INSERT INTO t1 VALUES ( '139', '21', '32
 INSERT INTO t1 VALUES ( '143', '16', '-4.9000000000', '-0.1000000000', '', NULL, '15774720');
 INSERT INTO t1 VALUES ( '145', '15', '0.0000000000', '1.9000000000', '', '0', '16769024');
 INSERT INTO t1 VALUES ( '146', '16', '0.0000000000', '1.9000000000', '', '0', '16769024');
-select * from t1 where minvalue<=1 and maxvalue>=-1 and datatype_id=16;
-id	datatype_id	minvalue	maxvalue	valuename	forecolor	backcolor
+select * from t1 where min_value<=1 and max_value>=-1 and datatype_id=16;
+id	datatype_id	min_value	max_value	valuename	forecolor	backcolor
 143	16	-4.9000000000	-0.1000000000		NULL	15774720
 146	16	0.0000000000	1.9000000000		0	16769024
-select * from t1 where minvalue<=-1 and maxvalue>=-1 and datatype_id=16;
-id	datatype_id	minvalue	maxvalue	valuename	forecolor	backcolor
+select * from t1 where min_value<=-1 and max_value>=-1 and datatype_id=16;
+id	datatype_id	min_value	max_value	valuename	forecolor	backcolor
 143	16	-4.9000000000	-0.1000000000		NULL	15774720
 drop table t1;
 create table t1 (a decimal(10,2));

=== modified file 'mysql-test/suite/funcs_1/r/is_columns_is.result'
--- a/mysql-test/suite/funcs_1/r/is_columns_is.result	2009-11-02 15:16:58 +0000
+++ b/mysql-test/suite/funcs_1/r/is_columns_is.result	2009-11-04 09:02:10 +0000
@@ -154,7 +154,7 @@ def	information_schema	PARTITIONS	NODEGR
 def	information_schema	PARTITIONS	PARTITION_COMMENT	23		NO	varchar	80	240	NULL	NULL	utf8	utf8_general_ci	varchar(80)			select		Default	Default
 def	information_schema	PARTITIONS	PARTITION_DESCRIPTION	12	NULL	YES	longtext	4294967295	4294967295	NULL	NULL	utf8	utf8_general_ci	longtext			select		Default	Default
 def	information_schema	PARTITIONS	PARTITION_EXPRESSION	10	NULL	YES	longtext	4294967295	4294967295	NULL	NULL	utf8	utf8_general_ci	longtext			select		Default	Default
-def	information_schema	PARTITIONS	PARTITION_METHOD	8	NULL	YES	varchar	12	36	NULL	NULL	utf8	utf8_general_ci	varchar(12)			select		Default	Default
+def	information_schema	PARTITIONS	PARTITION_METHOD	8	NULL	YES	varchar	18	54	NULL	NULL	utf8	utf8_general_ci	varchar(18)			select		Default	Default
 def	information_schema	PARTITIONS	PARTITION_NAME	4	NULL	YES	varchar	64	192	NULL	NULL	utf8	utf8_general_ci	varchar(64)			select		Default	Default
 def	information_schema	PARTITIONS	PARTITION_ORDINAL_POSITION	6	NULL	YES	bigint	NULL	NULL	19	0	NULL	NULL	bigint(21) unsigned			select		Default	Default
 def	information_schema	PARTITIONS	SUBPARTITION_EXPRESSION	11	NULL	YES	longtext	4294967295	4294967295	NULL	NULL	utf8	utf8_general_ci	longtext			select		Default	Default
@@ -539,7 +539,7 @@ NULL	information_schema	PARAMETERS	NUMER
 3.0000	information_schema	PARTITIONS	SUBPARTITION_NAME	varchar	64	192	utf8	utf8_general_ci	varchar(64)
 NULL	information_schema	PARTITIONS	PARTITION_ORDINAL_POSITION	bigint	NULL	NULL	NULL	NULL	bigint(21) unsigned
 NULL	information_schema	PARTITIONS	SUBPARTITION_ORDINAL_POSITION	bigint	NULL	NULL	NULL	NULL	bigint(21) unsigned
-3.0000	information_schema	PARTITIONS	PARTITION_METHOD	varchar	12	36	utf8	utf8_general_ci	varchar(12)
+3.0000	information_schema	PARTITIONS	PARTITION_METHOD	varchar	18	54	utf8	utf8_general_ci	varchar(18)
 3.0000	information_schema	PARTITIONS	SUBPARTITION_METHOD	varchar	12	36	utf8	utf8_general_ci	varchar(12)
 1.0000	information_schema	PARTITIONS	PARTITION_EXPRESSION	longtext	4294967295	4294967295	utf8	utf8_general_ci	longtext
 1.0000	information_schema	PARTITIONS	SUBPARTITION_EXPRESSION	longtext	4294967295	4294967295	utf8	utf8_general_ci	longtext

=== modified file 'mysql-test/suite/parts/inc/partition_key_32col.inc'
--- a/mysql-test/suite/parts/inc/partition_key_32col.inc	2009-01-31 16:03:44 +0000
+++ b/mysql-test/suite/parts/inc/partition_key_32col.inc	2009-10-30 16:34:50 +0000
@@ -1,4 +1,4 @@
---error ER_TOO_MANY_KEY_PARTS
+--error ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR
 eval create table t1 (a date not null, b varchar(50) not null, c varchar(50) not null, d enum('m', 'w') not null, e int not null, f decimal (18,2) not null, g bigint not null, h tinyint not null, a1 date not null, b1 varchar(50) not null, c1 varchar(50) not null, d1 enum('m', 'w') not null, e1 int not null, f1 decimal (18,2) not null, g1 bigint not null, h1 tinyint not null, a2 date not null, b2 varchar(50) not null, c2 varchar(50) not null, d2 enum('m', 'w') not null, e2 int not null, f2 decimal (18,2) not null, g2 bigint not null, h2 tinyint not null, a3 date not null, b3 varchar(50) not null, c3 varchar(50) not null, d3 enum('m', 'w') not null, e3 int not null, f3 decimal (18,2) not null, g3 bigint not null, h3 tinyint not null, i char(255), primary key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1,a2,b2,c2,d2,e2,f2,g2,h2,a3,b3,c3,d3,e3,f3,g3,h3)) engine=$engine 
 partition by key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1,a2,b2,c2,d2,e2,f2,g2,h2,a3,b3,c3,d3,e3,f3,g3,h3) (
 partition pa1 max_rows=20 min_rows=2,

=== modified file 'mysql-test/suite/parts/inc/partition_syntax.inc'
--- a/mysql-test/suite/parts/inc/partition_syntax.inc	2007-11-20 15:04:07 +0000
+++ b/mysql-test/suite/parts/inc/partition_syntax.inc	2009-10-21 16:27:34 +0000
@@ -312,7 +312,7 @@ PARTITION BY RANGE(f_int1)
 --echo #------------------------------------------------------------------------
 --echo #  3.5.1 NULL in RANGE partitioning clause
 --echo #  3.5.1.1 VALUE LESS THAN (NULL) is not allowed
---error ER_PARSE_ERROR
+--error ER_NULL_IN_VALUES_LESS_THAN
 eval CREATE TABLE t1 (
 $column_list
 )
@@ -320,7 +320,7 @@ PARTITION BY RANGE(f_int1)
 ( PARTITION part1 VALUES LESS THAN (NULL),
   PARTITION part2 VALUES LESS THAN (1000));
 --echo #  3.5.1.2 VALUE LESS THAN (NULL) is not allowed
---error ER_PARSE_ERROR
+--error ER_NULL_IN_VALUES_LESS_THAN
 eval CREATE TABLE t1 (
 $column_list
 )

=== modified file 'mysql-test/suite/parts/r/partition_special_innodb.result'
--- a/mysql-test/suite/parts/r/partition_special_innodb.result	2009-03-25 22:22:00 +0000
+++ b/mysql-test/suite/parts/r/partition_special_innodb.result	2009-10-30 16:34:50 +0000
@@ -133,7 +133,7 @@ partition pa1 max_rows=20 min_rows=2,
 partition pa2 max_rows=30 min_rows=3,
 partition pa3 max_rows=30 min_rows=4,
 partition pa4 max_rows=40 min_rows=2);
-ERROR 42000: Too many key parts specified; max 16 parts allowed
+ERROR HY000: Too many fields in 'list of partition fields'
 create table t1 (a date not null, b varchar(50) not null, c varchar(50) not null, d enum('m', 'w') not null, e int not null, f decimal (18,2) not null, g bigint not null, h tinyint not null, a1 date not null, b1 varchar(50) not null, c1 varchar(50) not null, d1 enum('m', 'w') not null, e1 int not null, f1 decimal (18,2) not null, g1 bigint not null, h1 tinyint not null, a2 date not null, b2 varchar(50) not null, c2 varchar(50) not null, d2 enum('m', 'w') not null, e2 int not null, f2 decimal (18,2) not null, g2 bigint not null, h2 tinyint not null, a3 date not null, b3 varchar(50) not null, c3 varchar(50) not null, d3 enum('m', 'w') not null, e3 int not null, f3 decimal (18,2) not null, g3 bigint not null, h3 tinyint not null, i char(255), primary key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1)) engine='InnoDB' 
 partition by key(a,b,c,d,e,f,g,h) (
 partition pa1 max_rows=20 min_rows=2,

=== modified file 'mysql-test/suite/parts/r/partition_special_myisam.result'
--- a/mysql-test/suite/parts/r/partition_special_myisam.result	2009-02-03 12:01:22 +0000
+++ b/mysql-test/suite/parts/r/partition_special_myisam.result	2009-10-30 16:34:50 +0000
@@ -133,7 +133,7 @@ partition pa1 max_rows=20 min_rows=2,
 partition pa2 max_rows=30 min_rows=3,
 partition pa3 max_rows=30 min_rows=4,
 partition pa4 max_rows=40 min_rows=2);
-ERROR 42000: Too many key parts specified; max 16 parts allowed
+ERROR HY000: Too many fields in 'list of partition fields'
 create table t1 (a date not null, b varchar(50) not null, c varchar(50) not null, d enum('m', 'w') not null, e int not null, f decimal (18,2) not null, g bigint not null, h tinyint not null, a1 date not null, b1 varchar(50) not null, c1 varchar(50) not null, d1 enum('m', 'w') not null, e1 int not null, f1 decimal (18,2) not null, g1 bigint not null, h1 tinyint not null, a2 date not null, b2 varchar(50) not null, c2 varchar(50) not null, d2 enum('m', 'w') not null, e2 int not null, f2 decimal (18,2) not null, g2 bigint not null, h2 tinyint not null, a3 date not null, b3 varchar(50) not null, c3 varchar(50) not null, d3 enum('m', 'w') not null, e3 int not null, f3 decimal (18,2) not null, g3 bigint not null, h3 tinyint not null, i char(255), primary key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1)) engine='MyISAM' 
 partition by key(a,b,c,d,e,f,g,h) (
 partition pa1 max_rows=20 min_rows=2,

=== modified file 'mysql-test/suite/parts/r/partition_syntax_innodb.result'
--- a/mysql-test/suite/parts/r/partition_syntax_innodb.result	2009-10-12 09:08:34 +0000
+++ b/mysql-test/suite/parts/r/partition_syntax_innodb.result	2009-10-30 16:34:50 +0000
@@ -610,8 +610,7 @@ f_charbig VARCHAR(1000)
 PARTITION BY RANGE(f_int1)
 ( PARTITION part1 VALUES LESS THAN (NULL),
 PARTITION part2 VALUES LESS THAN (1000));
-ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '),
-PARTITION part2 VALUES LESS THAN (1000))' at line 9
+ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN
 #  3.5.1.2 VALUE LESS THAN (NULL) is not allowed
 CREATE TABLE t1 (
 f_int1 INTEGER,
@@ -623,8 +622,7 @@ f_charbig VARCHAR(1000)
 PARTITION BY RANGE(f_int1)
 ( PARTITION part1 VALUES LESS THAN (NULL),
 PARTITION part2 VALUES LESS THAN (1000));
-ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '),
-PARTITION part2 VALUES LESS THAN (1000))' at line 9
+ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN
 #  3.5.2 NULL in LIST partitioning clause
 #  3.5.2.1 VALUE IN (NULL)
 CREATE TABLE t1 (

=== modified file 'mysql-test/suite/parts/r/partition_syntax_myisam.result'
--- a/mysql-test/suite/parts/r/partition_syntax_myisam.result	2009-10-12 09:08:34 +0000
+++ b/mysql-test/suite/parts/r/partition_syntax_myisam.result	2009-10-30 16:34:50 +0000
@@ -610,8 +610,7 @@ f_charbig VARCHAR(1000)
 PARTITION BY RANGE(f_int1)
 ( PARTITION part1 VALUES LESS THAN (NULL),
 PARTITION part2 VALUES LESS THAN (1000));
-ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '),
-PARTITION part2 VALUES LESS THAN (1000))' at line 9
+ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN
 #  3.5.1.2 VALUE LESS THAN (NULL) is not allowed
 CREATE TABLE t1 (
 f_int1 INTEGER,
@@ -623,8 +622,7 @@ f_charbig VARCHAR(1000)
 PARTITION BY RANGE(f_int1)
 ( PARTITION part1 VALUES LESS THAN (NULL),
 PARTITION part2 VALUES LESS THAN (1000));
-ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '),
-PARTITION part2 VALUES LESS THAN (1000))' at line 9
+ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN
 #  3.5.2 NULL in LIST partitioning clause
 #  3.5.2.1 VALUE IN (NULL)
 CREATE TABLE t1 (

=== removed file 'mysql-test/t/debug_sync.test'
--- a/mysql-test/t/debug_sync.test	2009-10-19 10:44:11 +0000
+++ b/mysql-test/t/debug_sync.test	1970-01-01 00:00:00 +0000
@@ -1,420 +0,0 @@
-###################### t/debug_sync.test ###############################
-#                                                                      #
-# Testing of the Debug Sync Facility.                                  #
-#                                                                      #
-# There is important documentation within sql/debug_sync.cc            #
-#                                                                      #
-# Used objects in this test case:                                      #
-# p0 - synchronization point 0. Non-existent dummy sync point.         #
-# s1 - signal 1.                                                       #
-# s2 - signal 2.                                                       #
-#                                                                      #
-# Creation:                                                            #
-# 2008-02-18 istruewing                                                #
-#                                                                      #
-########################################################################
-
-#
-# We need the Debug Sync Facility.
-#
---source include/have_debug_sync.inc
-
-#
-# We are checking privileges, which the embedded server cannot do.
-#
---source include/not_embedded.inc
-
-#
-# Preparative cleanup.
-#
---disable_warnings
-SET DEBUG_SYNC= 'RESET';
-DROP TABLE IF EXISTS t1;
---enable_warnings
-
-#
-# Show the special system variable.
-# It shows ON or OFF depending on the command line option --debug-sync.
-# The test case assumes it is ON (command line option present).
-#
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-
-#
-# Syntax. Valid forms.
-#
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2';
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6           HIT_LIMIT 3';
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6';
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2           EXECUTE 2 HIT_LIMIT 3';
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2           EXECUTE 2';
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2                     HIT_LIMIT 3';
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2';
-SET DEBUG_SYNC='p0 SIGNAL s1                       EXECUTE 2 HIT_LIMIT 3';
-SET DEBUG_SYNC='p0 SIGNAL s1                       EXECUTE 2';
-SET DEBUG_SYNC='p0 SIGNAL s1                                 HIT_LIMIT 3';
-SET DEBUG_SYNC='p0 SIGNAL s1';
-SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
-SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6 EXECUTE 2';
-SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6           HIT_LIMIT 3';
-SET DEBUG_SYNC='p0           WAIT_FOR s2 TIMEOUT 6';
-SET DEBUG_SYNC='p0           WAIT_FOR s2           EXECUTE 2 HIT_LIMIT 3';
-SET DEBUG_SYNC='p0           WAIT_FOR s2           EXECUTE 2';
-SET DEBUG_SYNC='p0           WAIT_FOR s2                     HIT_LIMIT 3';
-SET DEBUG_SYNC='p0           WAIT_FOR s2';
-SET DEBUG_SYNC='p0                                           HIT_LIMIT 3';
-SET DEBUG_SYNC='p0 CLEAR';
-SET DEBUG_SYNC='p0 TEST';
-SET DEBUG_SYNC='RESET';
-
-#
-# Syntax. Valid forms. Lower case.
-#
-set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2 hit_limit 3';
-set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2';
-set debug_sync='p0 signal s1 wait_for s2 timeout 6           hit_limit 3';
-set debug_sync='p0 signal s1 wait_for s2 timeout 6';
-set debug_sync='p0 signal s1 wait_for s2           execute 2 hit_limit 3';
-set debug_sync='p0 signal s1 wait_for s2           execute 2';
-set debug_sync='p0 signal s1 wait_for s2                     hit_limit 3';
-set debug_sync='p0 signal s1 wait_for s2';
-set debug_sync='p0 signal s1                       execute 2 hit_limit 3';
-set debug_sync='p0 signal s1                       execute 2';
-set debug_sync='p0 signal s1                                 hit_limit 3';
-set debug_sync='p0 signal s1';
-set debug_sync='p0           wait_for s2 timeout 6 execute 2 hit_limit 3';
-set debug_sync='p0           wait_for s2 timeout 6 execute 2';
-set debug_sync='p0           wait_for s2 timeout 6           hit_limit 3';
-set debug_sync='p0           wait_for s2 timeout 6';
-set debug_sync='p0           wait_for s2           execute 2 hit_limit 3';
-set debug_sync='p0           wait_for s2           execute 2';
-set debug_sync='p0           wait_for s2                     hit_limit 3';
-set debug_sync='p0           wait_for s2';
-set debug_sync='p0                                           hit_limit 3';
-set debug_sync='p0 clear';
-set debug_sync='p0 test';
-set debug_sync='reset';
-
-#
-# Syntax. Valid forms. Line wrap, leading, mid, trailing space.
-#
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6
-                EXECUTE 2 HIT_LIMIT 3';
-SET DEBUG_SYNC='   p0 SIGNAL s1 WAIT_FOR s2';
-SET DEBUG_SYNC='p0    SIGNAL    s1    WAIT_FOR    s2';
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2   ';
-SET DEBUG_SYNC='   p0 SIGNAL s1 WAIT_FOR s2   ';
-SET DEBUG_SYNC='   p0    SIGNAL    s1    WAIT_FOR    s2   ';
-
-#
-# Syntax. Invalid forms.
-#
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC=' ';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0                                          EXECUTE 2';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0                                TIMEOUT 6 EXECUTE 2';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0                                TIMEOUT 6';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1           EXECUTE 2';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6 EXECUTE 2';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1 EXECUTE 2';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2 EXECUTE 2';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0                  SIGNAL s1 TIMEOUT 6 EXECUTE 2';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0                  SIGNAL s1 TIMEOUT 6';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 EXECUTE 2 SIGNAL s1 TIMEOUT 6';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 TIMEOUT 6 SIGNAL s1';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 EXECUTE 2 TIMEOUT 6 SIGNAL s1';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 CLEAR HIT_LIMIT 3';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='CLEAR';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 CLEAR p0';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='TEST';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 TEST p0';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 RESET';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='RESET p0';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 RESET p0';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 SIGNAL ';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR ';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE ';
-
-#
-# Syntax. Invalid keywords used.
-#
---error ER_UNKNOWN_SYSTEM_VARIABLE
-SET DEBUG_SYNCx='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 SIGNAx s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOx s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUx 0 EXECUTE 2 HIT_LIMIT 3';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTx 2 HIT_LIMIT 3';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIx 3';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 CLEARx';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 TESTx';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='RESETx';
-
-#
-# Syntax. Invalid numbers. Decimal only.
-#
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 0x6 EXECUTE 2 HIT_LIMIT 3';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 0x2 HIT_LIMIT 3';
---error ER_PARSE_ERROR
-SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 7 EXECUTE 2 HIT_LIMIT 0x3';
-
-#
-# Syntax. Invalid value type.
-#
---error ER_WRONG_TYPE_FOR_VAR
-SET DEBUG_SYNC= 7;
-
-#
-# Syntax. DEBUG_SYNC is a SESSION-only variable.
-#
---error ER_LOCAL_VARIABLE
-SET GLOBAL DEBUG_SYNC= 'p0 CLEAR';
-
-#
-# Syntax. The variable value does not need to be a string literal.
-#
-SET @myvar= 'now SIGNAL from_myvar';
-SET DEBUG_SYNC= @myvar;
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-#
-SET DEBUG_SYNC= LEFT('now SIGNAL from_function_cut_here', 24);
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-
-#
-# Functional tests.
-#
-# NOTE: There is the special synchronization point 'now'. It is placed
-#       immediately after setting of the DEBUG_SYNC variable.
-#       So it is executed before the SET statement ends.
-#
-# NOTE: There is only one global signal (say "signal post" or "flag mast").
-#       A SIGNAL action writes its signal into it ("sets a flag").
-#       The signal persists until explicitly overwritten.
-#       To avoid confusion for later tests, it is recommended to clear
-#       the signal by signalling "empty" ("setting the 'empty' flag"):
-#       SET DEBUG_SYNC= 'now SIGNAL empty';
-#       Preferably you can reset the whole facility with:
-#       SET DEBUG_SYNC= 'RESET';
-#       The signal is then '' (really empty) which connot be done otherwise.
-#
-
-#
-# Time out immediately. This gives just a warning.
-#
-SET DEBUG_SYNC= 'now SIGNAL something';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-# Suppress warning number
---replace_column 2 ####
-SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0';
-#
-# If signal is present already, TIMEOUT 0 does not give a warning.
-#
-SET DEBUG_SYNC= 'now SIGNAL nothing';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0';
-
-#
-# EXECUTE 0 is effectively a no-op.
-#
-SET DEBUG_SYNC= 'now SIGNAL something EXECUTE 0';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-SET DEBUG_SYNC= 'now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0';
-
-#
-# Run into HIT_LIMIT. This gives an error.

-#
---error ER_DEBUG_SYNC_HIT_LIMIT
-SET DEBUG_SYNC= 'now HIT_LIMIT 1';
-
-#
-# Many actions. Watch the array growing and shrinking in the debug trace:
-# egrep 'query:|debug_sync_action:' mysql-test/var/log/master.trace
-#
-SET DEBUG_SYNC= 'RESET';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-SET DEBUG_SYNC= 'p1abcd   SIGNAL s1 EXECUTE 2';
-SET DEBUG_SYNC= 'p2abc    SIGNAL s2 EXECUTE 2';
-SET DEBUG_SYNC= 'p9abcdef SIGNAL s9 EXECUTE 2';
-SET DEBUG_SYNC= 'p4a      SIGNAL s4 EXECUTE 2';
-SET DEBUG_SYNC= 'p5abcde  SIGNAL s5 EXECUTE 2';
-SET DEBUG_SYNC= 'p6ab     SIGNAL s6 EXECUTE 2';
-SET DEBUG_SYNC= 'p7       SIGNAL s7 EXECUTE 2';
-SET DEBUG_SYNC= 'p8abcdef SIGNAL s8 EXECUTE 2';
-SET DEBUG_SYNC= 'p3abcdef SIGNAL s3 EXECUTE 2';
-#
-# Execute some actions to show they exist. Each sets a distinct signal.
-#
-SET DEBUG_SYNC= 'p4a      TEST';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-SET DEBUG_SYNC= 'p1abcd   TEST';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-SET DEBUG_SYNC= 'p7       TEST';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-SET DEBUG_SYNC= 'p9abcdef TEST';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-SET DEBUG_SYNC= 'p3abcdef TEST';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-#
-# Clear the actions.
-#
-SET DEBUG_SYNC= 'p1abcd   CLEAR';
-SET DEBUG_SYNC= 'p2abc    CLEAR';
-SET DEBUG_SYNC= 'p5abcde  CLEAR';
-SET DEBUG_SYNC= 'p6ab     CLEAR';
-SET DEBUG_SYNC= 'p8abcdef CLEAR';
-SET DEBUG_SYNC= 'p9abcdef CLEAR';
-SET DEBUG_SYNC= 'p3abcdef CLEAR';
-SET DEBUG_SYNC= 'p4a      CLEAR';
-SET DEBUG_SYNC= 'p7       CLEAR';
-#
-# Execute some actions to show they have gone.
-#
-SET DEBUG_SYNC= 'p1abcd   TEST';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-SET DEBUG_SYNC= 'p7       TEST';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-SET DEBUG_SYNC= 'p9abcdef TEST';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-#
-# Now cleanup. Actions are clear already, but signal needs to be cleared.
-#
-SET DEBUG_SYNC= 'RESET';
-SHOW VARIABLES LIKE 'DEBUG_SYNC';
-
-#
-# Facility requires SUPER privilege.
-#
-CREATE USER mysqltest_1@localhost;
-GRANT SUPER ON *.* TO mysqltest_1@localhost;
---echo connection con1, mysqltest_1
-connect (con1,localhost,mysqltest_1,,);
-SET DEBUG_SYNC= 'RESET';
-disconnect con1;
---echo connection default
-connection default;
-DROP USER mysqltest_1@localhost;
-#
-CREATE USER mysqltest_2@localhost;
-GRANT ALL ON *.* TO mysqltest_2@localhost;
-REVOKE SUPER ON *.* FROM mysqltest_2@localhost;
---echo connection con1, mysqltest_2
-connect (con1,localhost,mysqltest_2,,);
---error ER_SPECIFIC_ACCESS_DENIED_ERROR
-SET DEBUG_SYNC= 'RESET';
-disconnect con1;
---echo connection default
-connection default;
-DROP USER mysqltest_2@localhost;
-
-#
-# Example 1.
-#
-# Preparative cleanup.
---disable_warnings
-SET DEBUG_SYNC= 'RESET';
-DROP TABLE IF EXISTS t1;
---enable_warnings
-#
-# Test.
-CREATE TABLE t1 (c1 INT);
-    --echo connection con1
-    connect (con1,localhost,root,,);
-    SET DEBUG_SYNC= 'before_lock_tables_takes_lock
-      SIGNAL opened WAIT_FOR flushed';
-    send INSERT INTO t1 VALUES(1);
---echo connection default
-connection default;
-SET DEBUG_SYNC= 'now WAIT_FOR opened';
-SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed';
-FLUSH TABLE t1;
-    --echo connection con1
-    connection con1;
-    reap;
-    disconnect con1;
---echo connection default
-connection default;
-DROP TABLE t1;
-
-#
-# Example 2.
-#
-# Preparative cleanup.
---disable_warnings
-SET DEBUG_SYNC= 'RESET';
-DROP TABLE IF EXISTS t1;
---enable_warnings
-#
-# Test.
-CREATE TABLE t1 (c1 INT);
-LOCK TABLE t1 WRITE;
-    --echo connection con1
-    connect (con1,localhost,root,,);
-    # Retain action after use. First used by general_log.
-    SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2';
-    send INSERT INTO t1 VALUES (1);
---echo connection default
-connection default;
-# Wait until INSERT waits for lock.
-SET DEBUG_SYNC= 'now WAIT_FOR locked';
-# let INSERT continue.
-UNLOCK TABLES;
-    --echo connection con1
-    connection con1;
-    --echo retrieve INSERT result.
-    reap;
-    disconnect con1;
---echo connection default
-connection default;
-DROP TABLE t1;
-
-#
-# Cleanup after test case.
-# Otherwise signal would contain 'flushed' here,
-# which could confuse the next test.
-#
-SET DEBUG_SYNC= 'RESET';
-

=== modified file 'mysql-test/t/partition.test'
--- a/mysql-test/t/partition.test	2009-10-23 06:24:37 +0000
+++ b/mysql-test/t/partition.test	2009-10-30 16:34:50 +0000
@@ -424,12 +424,12 @@ drop table t1;
 #
 # BUG 16002: Handle unsigned integer functions properly
 #
---error ER_PARSE_ERROR
+--error ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR
 create table t1 (a bigint)
 partition by range (a)
 (partition p0 values less than (0xFFFFFFFFFFFFFFFF),
  partition p1 values less than (10));
---error ER_PARSE_ERROR
+--error ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR
 create table t1 (a bigint)
 partition by list (a)
 (partition p0 values in (0xFFFFFFFFFFFFFFFF),
@@ -1462,7 +1462,7 @@ PARTITION BY LIST (a)
 SHOW CREATE TABLE t1;
 DROP TABLE t1;
 
---error ER_PARSE_ERROR
+--error ER_NULL_IN_VALUES_LESS_THAN
 CREATE TABLE t1 (a int)
 PARTITION BY RANGE(a)
 (PARTITION p0 VALUES LESS THAN (NULL));

=== added file 'mysql-test/t/partition_column.test'
--- a/mysql-test/t/partition_column.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/partition_column.test	2009-11-03 11:26:54 +0000
@@ -0,0 +1,380 @@
+#
+# Tests for the new column list partitioning introduced in second
+# version for partitioning.
+#
+--source include/have_partition.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (a varchar(5))
+partition by list columns(a)
+( partition p0 values in ('\''),
+  partition p1 values in ('\\'),
+  partition p2 values in ('\0'));
+show create table t1;
+drop table t1;
+
+#
+# BUG#48165, sql_mode gives error
+#
+set @@sql_mode=allow_invalid_dates;
+--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+create table t1 (a char, b char, c date)
+partition by range columns (a,b,c)
+( partition p0 values less than (0,0,to_days('3000-11-31')));
+
+--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+create table t1 (a char, b char, c date)
+partition by range columns (a,b,c)
+( partition p0 values less than (0,0,'3000-11-31'));
+set @@sql_mode='';
+
+--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+create table t1 (a int, b char(10), c varchar(25), d datetime)
+partition by range columns(a,b,c,d)
+subpartition by hash (to_seconds(d))
+subpartitions 4
+( partition p0 values less than (1, 0, MAXVALUE, '1900-01-01'),
+  partition p1 values less than (1, 'a', MAXVALUE, '1999-01-01'),
+  partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE),
+  partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE));
+
+create table t1 (a int, b char(10), c varchar(25), d datetime)
+partition by range columns(a,b,c,d)
+subpartition by hash (to_seconds(d))
+subpartitions 4
+( partition p0 values less than (1, '0', MAXVALUE, '1900-01-01'),
+  partition p1 values less than (1, 'a', MAXVALUE, '1999-01-01'),
+  partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE),
+  partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE));
+select partition_method, partition_expression, partition_description
+  from information_schema.partitions where table_name = "t1";
+show create table t1;
+drop table t1;
+
+--error ER_NULL_IN_VALUES_LESS_THAN
+create table t1 (a int, b int)
+partition by range columns (a,b)
+(partition p0 values less than (NULL, maxvalue));
+
+--error ER_MAXVALUE_IN_VALUES_IN, ER_PARSE_ERROR
+create table t1 (a int, b int)
+partition by list columns(a,b)
+( partition p0 values in ((maxvalue, 0)));
+
+create table t1 (a int, b int)
+partition by list columns (a,b)
+( partition p0 values in ((0,0)));
+--error ER_MAXVALUE_IN_VALUES_IN, ER_PARSE_ERROR
+alter table t1 add partition
+(partition p1 values in (maxvalue, maxvalue));
+drop table t1;
+#
+# BUG#47837, Crash when two same fields in column list processing
+#
+--error ER_SAME_NAME_PARTITION_FIELD
+create table t1 (a int, b int)
+partition by key (a,a);
+--error ER_SAME_NAME_PARTITION_FIELD
+create table t1 (a int, b int)
+partition by list columns(a,a)
+( partition p values in ((1,1)));
+
+#
+# BUG#47838, List partitioning have problems with <= and >=
+#
+create table t1 (a int signed)
+partition by list (a)
+( partition p0 values in (1, 3, 5, 7, 9, NULL),
+  partition p1 values in (2, 4, 6, 8, 0));
+insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8);
+select * from t1 where NULL <= a;
+select * from t1 where a is null;
+explain partitions select * from t1 where a is null;
+select * from t1 where a <= 1;
+drop table t1;
+
+create table t1 (a int signed)
+partition by list columns(a)
+( partition p0 values in (1, 3, 5, 7, 9, NULL),
+  partition p1 values in (2, 4, 6, 8, 0));
+insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8);
+select * from t1 where a <= NULL;
+select * from t1 where a is null;
+explain partitions select * from t1 where a is null;
+select * from t1 where a <= 1;
+drop table t1;
+
+create table t1 (a int, b int)
+partition by list columns(a,b)
+( partition p0 values in ((1, NULL), (2, NULL), (NULL, NULL)),
+  partition p1 values in ((1,1), (2,2)),
+  partition p2 values in ((3, NULL), (NULL, 1)));
+select partition_method, partition_expression, partition_description
+  from information_schema.partitions where table_name = "t1";
+show create table t1;
+#
+# BUG#47754 Crash when selecting using NOT BETWEEN for column list partitioning
+#
+insert into t1 values (3, NULL);
+insert into t1 values (NULL, 1);
+insert into t1 values (NULL, NULL);
+insert into t1 values (1, NULL);
+insert into t1 values (2, NULL);
+insert into t1 values (1,1);
+insert into t1 values (2,2);
+select * from t1 where a = 1;
+select * from t1 where a = 2;
+select * from t1 where a > 8;
+select * from t1 where a not between 8 and 8;
+show create table t1;
+drop table t1;
+
+--error ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR
+create table t1 (a int)
+partition by list (a)
+( partition p0 values in (1),
+  partition p1 values in (1));
+
+create table t1 (a int)
+partition by list (a)
+( partition p0 values in (2, 1),
+  partition p1 values in (4, NULL, 3));
+select partition_method, partition_expression, partition_description
+  from information_schema.partitions where table_name = "t1";
+show create table t1;
+insert into t1 values (1);
+insert into t1 values (2);
+insert into t1 values (3);
+insert into t1 values (4);
+insert into t1 values (NULL);
+--error ER_NO_PARTITION_FOR_GIVEN_VALUE
+insert into t1 values (5);
+drop table t1;
+
+--error ER_PARSE_ERROR
+create table t1 (a int)

+partition by list columns(a)
+( partition p0 values in (2, 1),
+  partition p1 values in ((4), (NULL), (3)));
+
+create table t1 (a int)
+partition by list columns(a)
+( partition p0 values in (2, 1),
+  partition p1 values in (4, NULL, 3));
+select partition_method, partition_expression, partition_description
+ from information_schema.partitions where table_name = "t1";
+show create table t1;
+insert into t1 values (1);
+insert into t1 values (2);
+insert into t1 values (3);
+insert into t1 values (4);
+insert into t1 values (NULL);
+--error ER_NO_PARTITION_FOR_GIVEN_VALUE
+insert into t1 values (5);
+show create table t1;
+drop table t1;
+
+create table t1 (a int, b char(10), c varchar(5), d int)
+partition by range columns(a,b,c)
+subpartition by key (c,d)
+subpartitions 3
+( partition p0 values less than (1,'abc','abc'),
+  partition p1 values less than (2,'abc','abc'),
+  partition p2 values less than (3,'abc','abc'),
+  partition p3 values less than (4,'abc','abc'));
+select partition_method, partition_expression, partition_description
+  from information_schema.partitions where table_name = "t1";
+show create table t1;
+
+insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3);
+insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3);
+insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3);
+insert into t1 values (1,'d','e',1),(2,'d','e',2),(3,'d','e',3);
+select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) OR
+                       (a = 1 AND b >= 'a' AND (c = 'c' OR (c = 'd' AND d = 2))));
+drop table t1;
+
+create table t1 (a int, b varchar(2), c int)
+partition by range columns (a, b, c)
+(partition p0 values less than (1, 'A', 1),
+ partition p1 values less than (1, 'B', 1));
+select partition_method, partition_expression, partition_description
+  from information_schema.partitions where table_name = "t1";
+show create table t1;
+insert into t1 values (1, 'A', 1);
+explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1;
+select * from t1 where a = 1 AND b <= 'A' and c = 1;
+drop table t1;
+
+create table t1 (a char, b char, c char)
+partition by list columns(a)
+( partition p0 values in ('a'));
+insert into t1 (a) values ('a');
+select * from t1 where a = 'a';
+drop table t1;
+
+--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+create table t1 (d time)
+partition by range columns(d)
+( partition p0 values less than ('2000-01-01'),
+  partition p1 values less than ('2040-01-01'));
+
+--error ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD
+create table t1 (d timestamp)
+partition by range columns(d)
+( partition p0 values less than ('2000-01-01'),
+  partition p1 values less than ('2040-01-01'));
+
+--error ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD
+create table t1 (d bit(1))
+partition by range columns(d)
+( partition p0 values less than (0),
+  partition p1 values less than (1));
+
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (maxvalue, 10));
+drop table t1;
+
+create table t1 (d date)
+partition by range columns(d)
+( partition p0 values less than ('2000-01-01'),
+  partition p1 values less than ('2009-01-01'));
+drop table t1;
+
+create table t1 (d date)
+partition by range columns(d)
+( partition p0 values less than ('1999-01-01'),
+  partition p1 values less than ('2000-01-01'));
+drop table t1;
+
+create table t1 (d date)
+partition by range columns(d)
+( partition p0 values less than ('2000-01-01'),
+  partition p1 values less than ('3000-01-01'));
+drop table t1;
+
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p2 values less than (99,99),
+ partition p1 values less than (99,999));
+
+insert into t1 values (99,998);
+select * from t1 where b = 998;
+drop table t1;
+
+create table t1 as select to_seconds(null) as to_seconds;
+select data_type from information_schema.columns
+where column_name='to_seconds';
+drop table t1;
+
+--error ER_PARSE_ERROR
+create table t1 (a int, b int)
+partition by list columns(a,b)
+(partition p0 values in ((maxvalue,maxvalue)));
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (maxvalue,maxvalue));
+drop table t1;
+
+create table t1 (a int)
+partition by list columns(a)
+(partition p0 values in (0));
+select partition_method from information_schema.partitions where table_name='t1';
+drop table t1;
+
+create table t1 (a char(6))
+partition by range columns(a)
+(partition p0 values less than ('H23456'),
+ partition p1 values less than ('M23456'));
+insert into t1 values ('F23456');
+select * from t1;
+drop table t1;
+
+-- error 1054
+create table t1 (a char(6))
+partition by range columns(a)
+(partition p0 values less than (H23456),
+ partition p1 values less than (M23456));
+
+-- error ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+create table t1 (a char(6))
+partition by range columns(a)
+(partition p0 values less than (23456),
+ partition p1 values less than (23456));
+
+-- error 1064
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (10));
+
+-- error ER_PARTITION_COLUMN_LIST_ERROR
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (1,1,1);
+
+create table t1 (a int, b int)
+partition by range columns(a,b)
+(partition p0 values less than (1, 0),
+ partition p1 values less than (2, maxvalue),
+ partition p2 values less than (3, 3),
+ partition p3 values less than (10, maxvalue));
+
+-- error ER_NO_PARTITION_FOR_GIVEN_VALUE
+insert into t1 values (11,0);
+insert into t1 values (0,1),(1,1),(2,1),(3,1),(3,4),(4,9),(9,1);
+select * from t1;
+
+alter table t1
+partition by range columns(b,a)
+(partition p0 values less than (1,2),
+ partition p1 values less than (3,3),
+ partition p2 values less than (9,5));
+explain partitions select * from t1 where b < 2;
+select * from t1 where b < 2;
+explain partitions select * from t1 where b < 4;
+select * from t1 where b < 4;
+
+alter table t1 reorganize partition p1 into
+(partition p11 values less than (2,2),
+ partition p12 values less than (3,3));
+
+-- error ER_REORG_OUTSIDE_RANGE
+alter table t1 reorganize partition p0 into
+(partition p01 values less than (0,3),
+ partition p02 values less than (1,1));
+
+-- error ER_PARTITION_COLUMN_LIST_ERROR
+alter table t1 reorganize partition p2 into
+(partition p2 values less than(9,6,1));
+
+-- error ER_PARTITION_COLUMN_LIST_ERROR
+alter table t1 reorganize partition p2 into
+(partition p2 values less than (10));
+
+alter table t1 reorganize partition p2 into
+(partition p21 values less than (4,7),
+ partition p22 values less than (9,5));
+explain partitions select * from t1 where b < 4;
+select * from t1 where b < 4;
+drop table t1;
+
+create table t1 (a int, b int)
+partition by list columns(a,b)
+subpartition by hash (b)
+subpartitions 2
+(partition p0 values in ((0,0), (1,1)),
+ partition p1 values in ((1000,1000)));
+insert into t1 values (1000,1000);
+#select * from t1 where a = 0 and b = 0;
+drop table t1;
+
+create table t1 (a char, b char, c char)
+partition by range columns(a,b,c)
+( partition p0 values less than ('a','b','c'));
+alter table t1 add partition
+(partition p1 values less than ('b','c','d'));
+drop table t1;

=== added file 'mysql-test/t/partition_column_prune.test'
--- a/mysql-test/t/partition_column_prune.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/partition_column_prune.test	2009-10-29 17:04:23 +0000
@@ -0,0 +1,71 @@
+#
+# Partition pruning tests for new COLUMN LIST feature
+#
+-- source include/have_partition.inc
+
+--disable_warnings
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+--enable_warnings
+
+create table t1 (a char, b char, c char)
+partition by range columns(a,b,c)
+( partition p0 values less than ('a','b','c'));
+insert into t1 values ('a', NULL, 'd');
+explain partitions select * from t1 where a = 'a' AND c = 'd';
+select * from t1 where a = 'a' AND c = 'd';
+drop table t1;
+
+## COLUMN_LIST partition pruning tests
+create table t1 (a int not null) partition by range columns(a) (
+  partition p0 values less than (10),
+  partition p1 values less than (20),
+  partition p2 values less than (30),
+  partition p3 values less than (40),
+  partition p4 values less than (50),
+  partition p5 values less than (60),
+  partition p6 values less than (70)
+);
+insert into t1 values (5),(15),(25),(35),(45),(55),(65);
+insert into t1 values (5),(15),(25),(35),(45),(55),(65);
+
+create table t2 (a int not null) partition by range(a) (
+  partition p0 values less than (10),
+  partition p1 values less than (20),
+  partition p2 values less than (30),
+  partition p3 values less than (40),
+  partition p4 values less than (50),
+  partition p5 values less than (60),
+  partition p6 values less than (70)
+);
+insert into t2 values (5),(15),(25),(35),(45),(55),(65);
+insert into t2 values (5),(15),(25),(35),(45),(55),(65);
+
+explain partitions select * from t1 where a > 35 and a < 45;
+explain partitions select * from t2 where a > 35 and a < 45;
+
+drop table t1, t2;
+
+create table t1 (a int not null, b int not null ) 
+partition by range columns(a,b) (
+  partition p01 values less than (2,10),
+  partition p02 values less than (2,20),
+  partition p03 values less than (2,30),
+
+  partition p11 values less than (4,10),
+  partition p12 values less than (4,20),
+  partition p13 values less than (4,30),
+
+  partition p21 values less than (6,10),
+  partition p22 values less than (6,20),
+  partition p23 values less than (6,30)
+);
+
+insert into t1 values (2,5), (2,15), (2,25),
+  (4,5), (4,15), (4,25), (6,5), (6,15), (6,25);
+insert into t1 select * from t1;
+
+explain partitions select * from t1 where a=2;
+explain partitions select * from t1 where a=4;
+explain partitions select * from t1 where a=2 and b < 22;
+
+drop table t1;

=== modified file 'mysql-test/t/partition_datatype.test'
--- a/mysql-test/t/partition_datatype.test	2008-02-25 20:18:50 +0000
+++ b/mysql-test/t/partition_datatype.test	2009-10-30 20:43:49 +0000
@@ -4,6 +4,7 @@
 # as partition by key
 # Created to verify the fix for Bug#31705
 # Partitions: crash if varchar length > 65530
+# BUG#48164 limited size to 3072 bytes
 #
 -- source include/have_partition.inc
 
@@ -192,27 +193,29 @@ create table t1 (a set('y','n')) partiti
 insert into t1 values ('y');
 select * from t1 where a = 'y';
 drop table t1;
-create table t1 (a varchar(65531)) partition by key (a);
+create table t1 (a varchar(4092)) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
 select * from t1 where a like 'aaa%';
 select * from t1 where a = 'bbbb';
 drop table t1;
-create table t1 (a varchar(65532)) partition by key (a);
+create table t1 (a varchar(4093)) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
 select * from t1 where a like 'aaa%';
 select * from t1 where a = 'bbbb';
 drop table t1;
-create table t1 (a varchar(65533) not null) partition by key (a);
+create table t1 (a varchar(4094) not null) partition by key (a);
 insert into t1 values ('bbbb');
 insert into t1 values ('aaaa');
 select * from t1 where a = 'aaaa';
 select * from t1 where a like 'aaa%';
 select * from t1 where a = 'bbbb';
 drop table t1;
+-- error ER_PARTITION_FIELDS_TOO_LONG
+create table t1 (a varchar(4094)) partition by key (a);
 -- error ER_TOO_BIG_ROWSIZE
 create table t1 (a varchar(65533)) partition by key (a);
 -- error ER_TOO_BIG_ROWSIZE

=== modified file 'mysql-test/t/partition_error.test'
--- a/mysql-test/t/partition_error.test	2009-07-23 15:41:27 +0000
+++ b/mysql-test/t/partition_error.test	2009-10-30 16:34:50 +0000
@@ -190,7 +190,7 @@ partitions 3
 (partition x1, partition x2);
 
 #
-# Partition by key specified 3 partitions but only defined 2 => error
+# Partition by hash, random function
 #
 --error 1064
 CREATE TABLE t1 (
@@ -203,7 +203,7 @@ partitions 2
 (partition x1, partition x2);
 
 #
-# Partition by key specified 3 partitions but only defined 2 => error
+# Partition by range, random function
 #
 --error 1064
 CREATE TABLE t1 (
@@ -216,7 +216,7 @@ partitions 2
 (partition x1 values less than (0), partition x2 values less than (2));
 
 #
-# Partition by key specified 3 partitions but only defined 2 => error
+# Partition by list, random function
 #
 --error 1064
 CREATE TABLE t1 (
@@ -462,7 +462,7 @@ partitions 2
 #
 # Partition by range, inconsistent partition function and constants
 #
---error 1064
+--error ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR
 CREATE TABLE t1 (
 a int not null,
 b int not null,
@@ -532,7 +532,7 @@ partitions 2
 #
 # Partition by range, missing parenthesis
 #
---error 1064
+--error ER_PARTITION_WRONG_VALUES_ERROR
 CREATE TABLE t1 (
 a int not null,
 b int not null,
@@ -546,7 +546,7 @@ partitions 2
 #
 # Partition by range, maxvalue in wrong place
 #
---error 1064
+--error ER_PARTITION_MAXVALUE_ERROR
 CREATE TABLE t1 (
 a int not null,
 b int not null,
@@ -560,7 +560,7 @@ partitions 2
 #
 # Partition by range, maxvalue in several places
 #
---error 1064
+--error ER_PARTITION_MAXVALUE_ERROR
 CREATE TABLE t1 (
 a int not null,
 b int not null,
@@ -775,7 +775,7 @@ partitions 2
 #
 # Partition by list, wrong constant result type (not INT)
 #
---error 1064
+--error ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR
 CREATE TABLE t1 (
 a int not null,
 b int not null,

=== modified file 'mysql-test/t/partition_innodb.test'
--- a/mysql-test/t/partition_innodb.test	2009-09-16 08:23:16 +0000
+++ b/mysql-test/t/partition_innodb.test	2009-10-30 16:34:50 +0000
@@ -6,6 +6,36 @@ drop table if exists t1;
 --enable_warnings
 
 #
+# BUG#47776, Failed to update for MEMORY engine, crash for InnoDB and success for MyISAM
+#
+create table t1 (a varchar(5))
+engine=memory
+partition by range columns(a)
+( partition p0 values less than ('m'),
+  partition p1 values less than ('za'));
+insert into t1 values  ('j');
+update t1 set a = 'z' where (a >= 'j');
+drop table t1;
+
+create table t1 (a varchar(5))
+engine=myisam
+partition by range columns(a)
+( partition p0 values less than ('m'),
+  partition p1 values less than ('za'));
+insert into t1 values  ('j');
+update t1 set a = 'z' where (a >= 'j');
+drop table t1;
+
+create table t1 (a varchar(5))
+engine=innodb
+partition by range columns(a)
+( partition p0 values less than ('m'),
+  partition p1 values less than ('za'));
+insert into t1 values  ('j');
+update t1 set a = 'z' where (a >= 'j');
+drop table t1;
+
+#
 # Bug#47029: Crash when reorganize partition with subpartition
 #
 create table t1 (a int not null,

=== modified file 'mysql-test/t/partition_list.test'
--- a/mysql-test/t/partition_list.test	2007-04-20 16:35:16 +0000
+++ b/mysql-test/t/partition_list.test	2009-10-21 18:04:34 +0000
@@ -40,6 +40,8 @@ subpartitions 2
  partition p1 values in (1),
  partition pnull values in (null, 2),
  partition p3 values in (3));
+select partition_method, partition_expression, partition_description
+  from information_schema.partitions where table_name = "t1";
 insert into t1 values (0,0),(0,1),(1,0),(1,1),(null,0),(null,1);
 insert into t1 values (2,0),(2,1),(3,0),(3,1);
 

=== modified file 'mysql-test/t/partition_mgm_err.test'
--- a/mysql-test/t/partition_mgm_err.test	2008-10-10 18:12:38 +0000
+++ b/mysql-test/t/partition_mgm_err.test	2009-09-15 15:07:52 +0000
@@ -61,7 +61,7 @@ ALTER TABLE t1 REORGANIZE PARTITION x0, 
 ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO
 (PARTITION x01 VALUES LESS THAN (5));
 
---error ER_REORG_OUTSIDE_RANGE
+--error ER_RANGE_NOT_INCREASING_ERROR
 ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO
 (PARTITION x01 VALUES LESS THAN (4),
  PARTITION x11 VALUES LESS THAN (2));

=== modified file 'mysql-test/t/partition_pruning.test'
--- a/mysql-test/t/partition_pruning.test	2009-10-12 09:08:34 +0000
+++ b/mysql-test/t/partition_pruning.test	2009-10-30 16:34:50 +0000
@@ -51,6 +51,26 @@ INSERT INTO t1 VALUES ('0000-00-00'), ('
 ALTER TABLE t1 DROP KEY a;
 --source include/partition_date_range.inc
 DROP TABLE t1;
+--echo # TO_SECONDS, test of LIST and index
+CREATE TABLE t1 (a DATE, KEY(a))
+PARTITION BY LIST (TO_SECONDS(a))
+(PARTITION `p0001-01-01` VALUES IN (TO_SECONDS('0001-01-01')),
+ PARTITION `p2001-01-01` VALUES IN (TO_SECONDS('2001-01-01')),
+ PARTITION `pNULL` VALUES IN (NULL),
+ PARTITION `p0000-01-02` VALUES IN (TO_SECONDS('0000-01-02')),
+ PARTITION `p1001-01-01` VALUES IN (TO_SECONDS('1001-01-01')));
+if ($verify_without_partitions)
+{
+ALTER TABLE t1 REMOVE PARTITIONING;
+}
+INSERT INTO t1 VALUES ('0000-00-00'), ('0000-01-02'), ('0001-01-01'),
+      ('1001-00-00'), ('1001-01-01'), ('1002-00-00'), ('2001-01-01');
+--source include/partition_date_range.inc
+--echo # test without index
+ALTER TABLE t1 DROP KEY a;
+--source include/partition_date_range.inc
+DROP TABLE t1;
+
 
 #
 # Bug#46362: Endpoint should be set to false for TO_DAYS(DATE)

=== modified file 'mysql-test/t/partition_range.test'
--- a/mysql-test/t/partition_range.test	2008-12-13 11:02:16 +0000
+++ b/mysql-test/t/partition_range.test	2009-10-30 16:34:50 +0000
@@ -9,6 +9,78 @@
 drop table if exists t1, t2;
 --enable_warnings
 
+--error ER_NULL_IN_VALUES_LESS_THAN
+create table t1 (a int)
+partition by range (a)
+( partition p0 values less than (NULL),
+  partition p1 values less than (MAXVALUE));
+#
+# Merge fix of bug#27927 for TO_SECONDS function
+#
+create table t1 (a datetime not null)
+partition by range (TO_SECONDS(a))
+( partition p0 VALUES LESS THAN (TO_SECONDS('2007-03-08 00:00:00')),
+  partition p1 VALUES LESS THAN (TO_SECONDS('2007-04-01 00:00:00')));
+select partition_method, partition_expression, partition_description
+  from information_schema.partitions where table_name = "t1";
+INSERT INTO t1 VALUES ('2007-03-01 12:00:00'), ('2007-03-07 12:00:00');
+INSERT INTO t1 VALUES ('2007-03-08 12:00:00'), ('2007-03-15 12:00:00');
+explain partitions select * from t1 where a < '2007-03-08 00:00:00';
+explain partitions select * from t1 where a < '2007-03-08 00:00:01';
+explain partitions select * from t1 where a <= '2007-03-08 00:00:00';
+explain partitions select * from t1 where a <= '2007-03-07 23:59:59';
+explain partitions select * from t1 where a < '2007-03-07 23:59:59';
+drop table t1;
+#
+# New test cases for new function to_seconds
+#
+create table t1 (a date)
+partition by range(to_seconds(a))
+(partition p0 values less than (to_seconds('2004-01-01')),
+ partition p1 values less than (to_seconds('2005-01-01')));
+insert into t1 values ('2003-12-30'),('2004-12-31');
+select * from t1;
+explain partitions select * from t1 where a <= '2003-12-31';
+select * from t1 where a <= '2003-12-31';
+explain partitions select * from t1 where a <= '2005-01-01';
+select * from t1 where a <= '2005-01-01';
+drop table t1;
+
+create table t1 (a datetime)
+partition by range(to_seconds(a))
+(partition p0 values less than (to_seconds('2004-01-01 12:00:00')),
+ partition p1 values less than (to_seconds('2005-01-01 12:00:00')));
+insert into t1 values ('2004-01-01 11:59:29'),('2005-01-01 11:59:59');
+select * from t1;
+explain partitions select * from t1 where a <= '2004-01-01 11:59.59';
+select * from t1 where a <= '2004-01-01 11:59:59';
+explain partitions select * from t1 where a <= '2005-01-01';
+select * from t1 where a <= '2005-01-01';
+drop table t1;
+
+#
+# Adding new test cases for column list variant for partitioning
+#
+--error 1064
+create table t1 (a int, b char(20))
+partition by range columns(a,b)
+(partition p0 values less than (1));
+
+--error ER_TOO_MANY_VALUES_ERROR
+create table t1 (a int, b char(20))
+partition by range(a)
+(partition p0 values less than (1,"b"));
+
+--error ER_TOO_MANY_VALUES_ERROR
+create table t1 (a int, b char(20))
+partition by range(a)
+(partition p0 values less than (1,"b"));
+
+create table t1 (a int, b char(20))
+partition by range columns(b)
+(partition p0 values less than ("b"));
+drop table t1;
+
 #
 # BUG 33429: Succeeds in  adding partition when maxvalue on last partition
 #

=== added file 'mysql-test/t/partition_utf8.test'
--- a/mysql-test/t/partition_utf8.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/partition_utf8.test	2009-11-03 11:37:39 +0000
@@ -0,0 +1,42 @@
+# Tests for Column list which requires utf8 output
+--source include/have_partition.inc
+set names utf8;
+create table t1 (a varchar(2) character set cp1250)
+partition by list columns (a)
+( partition p0 values in (0x81));
+show create table t1;
+drop table t1;
+create table t1 (a varchar(2) character set cp1250)
+partition by list columns (a)
+( partition p0 values in (0x80));
+show create table t1;
+drop table t1;
+
+#
+# BUG#48164, too long partition fields causes crash
+#
+--error ER_PARTITION_FIELDS_TOO_LONG
+create table t1 (a varchar(2000), b varchar(2094))
+partition by list columns(a,b)
+( partition p0 values in (('a','b')));
+
+create table t1 (a varchar(1023) character set utf8 collate utf8_spanish2_ci)
+partition by range columns(a)
+( partition p0 values less than ('CZ'),
+  partition p1 values less than ('CH'),
+  partition p2 values less than ('D'));
+insert into t1 values ('czz'),('chi'),('ci'),('cg');
+select * from t1 where a between 'cg' AND 'ci';
+drop table t1;
+
+#
+# BUG#48163, Dagger in UCS2 not working as partition value
+#
+create table t1 (a varchar(2) character set ucs2)
+partition by list columns (a)
+(partition p0 values in (0x2020),
+ partition p1 values in (''));
+show create table t1;
+insert into t1 values ('');
+insert into t1 values (_ucs2 0x2020);
+drop table t1;

=== modified file 'mysql-test/t/type_decimal.test'
--- a/mysql-test/t/type_decimal.test	2008-04-28 18:14:22 +0000
+++ b/mysql-test/t/type_decimal.test	2009-10-30 16:34:50 +0000
@@ -8,13 +8,13 @@ SET SQL_WARNINGS=1;
 CREATE TABLE t1 (
    id int(11) NOT NULL auto_increment,
    datatype_id int(11) DEFAULT '0' NOT NULL,
-   minvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
-   maxvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
+   min_value decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
+   max_value decimal(20,10) DEFAULT '0.0000000000' NOT NULL,
    valuename varchar(20),
    forecolor int(11),
    backcolor int(11),
    PRIMARY KEY (id),
-   UNIQUE datatype_id (datatype_id, minvalue, maxvalue)
+   UNIQUE datatype_id (datatype_id, min_value, max_value)
 );
 INSERT INTO t1 VALUES ( '1', '4', '0.0000000000', '0.0000000000', 'Ei saja', '0', '16776960');
 INSERT INTO t1 VALUES ( '2', '4', '1.0000000000', '1.0000000000', 'Sajab', '16777215', '255');
@@ -148,8 +148,8 @@ INSERT INTO t1 VALUES ( '139', '21', '32
 INSERT INTO t1 VALUES ( '143', '16', '-4.9000000000', '-0.1000000000', '', NULL, '15774720');
 INSERT INTO t1 VALUES ( '145', '15', '0.0000000000', '1.9000000000', '', '0', '16769024');
 INSERT INTO t1 VALUES ( '146', '16', '0.0000000000', '1.9000000000', '', '0', '16769024');
-select * from t1 where minvalue<=1 and maxvalue>=-1 and datatype_id=16;
-select * from t1 where minvalue<=-1 and maxvalue>=-1 and datatype_id=16;
+select * from t1 where min_value<=1 and max_value>=-1 and datatype_id=16;
+select * from t1 where min_value<=-1 and max_value>=-1 and datatype_id=16;
 drop table t1;
 
 #

=== modified file 'mysys/mf_pack.c'
--- a/mysys/mf_pack.c	2009-08-30 18:08:25 +0000
+++ b/mysys/mf_pack.c	2009-11-05 08:44:22 +0000
@@ -335,7 +335,13 @@ size_t safe_cleanup_cat_path(char *to, s
   start= to;
   end= to + to_size;
 
-  IF_DBUG({uint idx; for(idx=0; idx<to_size; idx++) {to[idx]= '0'+idx%10;}});
+#ifndef DBUG_OFF
+  {
+    uint idx;
+    for(idx=0; idx<to_size; idx++)
+      to[idx]= '0'+idx%10;
+  }
+#endif
 
   /* Handle special conditions. */
 #ifdef FN_DEVCHAR

=== modified file 'mysys/my_malloc.c'
--- a/mysys/my_malloc.c	2009-02-26 13:07:12 +0000
+++ b/mysys/my_malloc.c	2009-11-05 08:44:22 +0000
@@ -34,10 +34,11 @@ void *my_malloc(size_t size, myf my_flag
 
   /* If compiled with DBUG, test for error injection. Described in my_sys.h. */
   /* purecov: begin tested */
-  if (!(point= IF_DBUG(my_malloc_error_inject ? NULL :) (char*) malloc(size)))
+  if (!(point= my_malloc_error_inject ? NULL : (char*) malloc(size)))
   {
-    IF_DBUG(if (my_malloc_error_inject) errno= ENOMEM;
-            my_malloc_error_inject= 0);
+    if (my_malloc_error_inject)
+      errno= ENOMEM;
+    my_malloc_error_inject= 0;
     my_errno=errno;
     if (my_flags & MY_FAE)
       error_handler_hook=fatal_error_handler_hook;

=== modified file 'mysys/my_static.c'
--- a/mysys/my_static.c	2009-10-19 18:36:44 +0000
+++ b/mysys/my_static.c	2009-11-05 08:44:22 +0000
@@ -67,7 +67,7 @@ uint    my_large_page_size= 0;
 #endif
 
 /* ERROR INJECTION: Described in my_sys.h. */
-IF_DBUG(int my_malloc_error_inject= 0);
+int my_malloc_error_inject= 0;
 
 	/* from safe_malloc */
 uint sf_malloc_prehunc=0,		/* If you have problem with core- */

=== modified file 'mysys/my_thr_init.c'
--- a/mysys/my_thr_init.c	2009-10-19 18:36:44 +0000
+++ b/mysys/my_thr_init.c	2009-11-05 08:44:22 +0000
@@ -429,17 +429,6 @@ struct st_my_thread_var *_my_thread_var(
   return  my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 }
 
-#ifndef DBUG_OFF
-/* Return pointer to DBUG for holding current state */
-
-extern void **my_thread_var_dbug()
-{
-  struct st_my_thread_var *tmp=
-    my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
-  return tmp && tmp->init ? &tmp->dbug : 0;
-}
-#endif
-
 /* Return pointer to mutex_in_use */
 
 safe_mutex_t **my_thread_var_mutex_in_use()
@@ -478,6 +467,15 @@ const char *my_thread_name(void)
   }
   return tmp->name;
 }
+
+/* Return pointer to DBUG for holding current state */
+
+extern void **my_thread_var_dbug()
+{
+  struct st_my_thread_var *tmp=
+    my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+  return tmp && tmp->init ? &tmp->dbug : 0;
+}
 #endif /* DBUG_OFF */
 
 

=== modified file 'mysys/safemalloc.c'
--- a/mysys/safemalloc.c	2009-05-25 10:10:18 +0000
+++ b/mysys/safemalloc.c	2009-11-05 08:44:22 +0000
@@ -134,11 +134,11 @@ void *_mymalloc(size_t size, const char 
     If compiled with DBUG, test for error injection. Described in my_sys.h.
   */
   if ((size + sf_malloc_cur_memory > sf_malloc_mem_limit)
-      IF_DBUG(|| my_malloc_error_inject))
+      || my_malloc_error_inject)
   {
-    IF_DBUG(if (my_malloc_error_inject)
-              errno= ENOMEM;
-            my_malloc_error_inject= 0);
+    if (my_malloc_error_inject)
+      errno= ENOMEM;
+    my_malloc_error_inject= 0;
     irem= 0;
   }
   else

=== modified file 'sql/CMakeLists.txt' (properties changed: +x to -x)
=== modified file 'sql/backup/be_default.cc'
--- a/sql/backup/be_default.cc	2009-10-12 09:08:34 +0000
+++ b/sql/backup/be_default.cc	2009-11-05 08:44:22 +0000
@@ -857,7 +857,7 @@ result_t Restore::send_data(Buffer &buf)
       DBUG_EXECUTE_IF("Restore__send_data_write_error",
                       last_write_res= -1; goto write_skip;);
       last_write_res = hdl->ha_write_row(cur_table->record[0]);
-      IF_DBUG(write_skip:); /* Label for error injection. */
+write_skip:
       DBUG_PRINT("backup_default_write", ("%d", last_write_res));
 
       /*

=== modified file 'sql/debug_sync.cc'
--- a/sql/debug_sync.cc	2009-10-05 08:51:41 +0000
+++ b/sql/debug_sync.cc	2009-11-05 08:44:22 +0000
@@ -1701,9 +1701,11 @@ uchar *sys_var_debug_sync::value_ptr(THD
 
 static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
 {
-  IF_DBUG(const char *dsp_name= action->sync_point.c_ptr());
-  IF_DBUG(const char *sig_emit= action->signal.c_ptr());
-  IF_DBUG(const char *sig_wait= action->wait_for.c_ptr());
+#ifndef DBUG_OFF
+  const char *dsp_name= action->sync_point.c_ptr();
+  const char *sig_emit= action->signal.c_ptr();
+  const char *sig_wait= action->wait_for.c_ptr();
+#endif
   DBUG_ENTER("debug_sync_execute");
   DBUG_ASSERT(thd);
   DBUG_ASSERT(action);

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2009-11-03 10:27:17 +0000
+++ b/sql/field.cc	2009-11-06 16:34:09 +0000
@@ -6485,13 +6485,11 @@ int Field_string::cmp(const uchar *a_ptr
 
 void Field_string::sort_string(uchar *to,uint length)
 {
-  IF_DBUG(uint tmp=) field_charset->coll->strnxfrm(field_charset,
-                                                   to, length,
-                                                   field_length /
-                                                   field_charset->mbmaxlen,
-                                                   ptr, field_length,
-                                                   MY_STRXFRM_PAD_WITH_SPACE |
-                                                   MY_STRXFRM_PAD_TO_MAXLEN);
+  uint tmp __attribute__((unused))=
+        field_charset->coll->strnxfrm(field_charset, to, length,
+                         field_length / field_charset->mbmaxlen,
+                         ptr, field_length,
+                         MY_STRXFRM_PAD_WITH_SPACE | MY_STRXFRM_PAD_TO_MAXLEN);
   DBUG_ASSERT(tmp == length);
 }
 

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2009-11-02 15:16:58 +0000
+++ b/sql/ha_ndbcluster.cc	2009-11-05 12:13:00 +0000
@@ -3552,7 +3552,7 @@ void ha_ndbcluster::unpack_record(uchar 
           /* Field_bit in DBUG requires the bit set in write_set for store(). */
           my_bitmap_map *old_map=
             dbug_tmp_use_all_columns(table, table->write_set);
-          IF_DBUG(int res=) field_bit->store(value, true);
+          int res __attribute__((unused))= field_bit->store(value, true);
           dbug_tmp_restore_column_map(table->write_set, old_map);
           DBUG_ASSERT(res == 0);
           field->move_field_offset(-dst_offset);
@@ -6199,7 +6199,7 @@ int ha_ndbcluster::rename_table(const ch
     DBUG_PRINT("NDB_SHARE", ("%s temporary  use_count: %u",
                              share->key, share->use_count));
     ndbcluster_prepare_rename_share(share, to);
-    IF_DBUG(int r=) ndbcluster_rename_share(thd, share);
+    int r __attribute__((unused))= ndbcluster_rename_share(thd, share);
     DBUG_ASSERT(r == 0);
   }
 #endif
@@ -6212,7 +6212,7 @@ int ha_ndbcluster::rename_table(const ch
 #ifdef HAVE_NDB_BINLOG
     if (share)
     {
-      IF_DBUG(int ret=) ndbcluster_undo_rename_share(thd, share);
+      int ret __attribute__((unused))= ndbcluster_undo_rename_share(thd, share);
       DBUG_ASSERT(ret == 0);
       /* ndb_share reference temporary free */
       DBUG_PRINT("NDB_SHARE", ("%s temporary free  use_count: %u",
@@ -6913,7 +6913,7 @@ void ha_ndbcluster::set_part_info(partit
     }
     if (m_part_info->part_type == HASH_PARTITION &&
         m_part_info->list_of_part_fields &&
-        m_part_info->no_full_part_fields == 0)
+        m_part_info->num_full_part_fields == 0)
     {
       /*
         CREATE TABLE t (....) ENGINE NDB PARTITON BY KEY();
@@ -10693,7 +10693,7 @@ void ha_ndbcluster::set_auto_partitions(
 int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info)
 {
   NDBTAB *tab= (NDBTAB*)tab_ref;
-  int32 *range_data= (int32*)my_malloc(part_info->no_parts*sizeof(int32),
+  int32 *range_data= (int32*)my_malloc(part_info->num_parts*sizeof(int32),
                                        MYF(0));
   uint i;
   int error= 0;
@@ -10702,17 +10702,17 @@ int ha_ndbcluster::set_range_data(void *
 
   if (!range_data)
   {
-    mem_alloc_error(part_info->no_parts*sizeof(int32));
+    mem_alloc_error(part_info->num_parts*sizeof(int32));
     DBUG_RETURN(1);
   }
-  for (i= 0; i < part_info->no_parts; i++)
+  for (i= 0; i < part_info->num_parts; i++)
   {
     longlong range_val= part_info->range_int_array[i];
     if (unsigned_flag)
       range_val-= 0x8000000000000000ULL;
     if (range_val < INT_MIN32 || range_val >= INT_MAX32)
     {
-      if ((i != part_info->no_parts - 1) ||
+      if ((i != part_info->num_parts - 1) ||
           (range_val != LONGLONG_MAX))
       {
         my_error(ER_LIMITED_PART_RANGE, MYF(0), "NDB");
@@ -10723,7 +10723,7 @@ int ha_ndbcluster::set_range_data(void *
     }
     range_data[i]= (int32)range_val;
   }
-  tab->setRangeListData(range_data, sizeof(int32)*part_info->no_parts);
+  tab->setRangeListData(range_data, sizeof(int32)*part_info->num_parts);
 error:
   my_free((char*)range_data, MYF(0));
   DBUG_RETURN(error);
@@ -10732,7 +10732,7 @@ error:
 int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info)
 {
   NDBTAB *tab= (NDBTAB*)tab_ref;
-  int32 *list_data= (int32*)my_malloc(part_info->no_list_values * 2
+  int32 *list_data= (int32*)my_malloc(part_info->num_list_values * 2
                                       * sizeof(int32), MYF(0));
   uint32 *part_id, i;
   int error= 0;
@@ -10741,10 +10741,10 @@ int ha_ndbcluster::set_list_data(void *t
 
   if (!list_data)
   {
-    mem_alloc_error(part_info->no_list_values*2*sizeof(int32));
+    mem_alloc_error(part_info->num_list_values*2*sizeof(int32));
     DBUG_RETURN(1);
   }
-  for (i= 0; i < part_info->no_list_values; i++)
+  for (i= 0; i < part_info->num_list_values; i++)
   {
     LIST_PART_ENTRY *list_entry= &part_info->list_array[i];
     longlong list_val= list_entry->list_value;
@@ -10760,7 +10760,7 @@ int ha_ndbcluster::set_list_data(void *t
     part_id= (uint32*)&list_data[2*i+1];
     *part_id= list_entry->partition_id;
   }
-  tab->setRangeListData(list_data, 2*sizeof(int32)*part_info->no_list_values);
+  tab->setRangeListData(list_data, 2*sizeof(int32)*part_info->num_list_values);
 error:
   my_free((char*)list_data, MYF(0));
   DBUG_RETURN(error);
@@ -10882,11 +10882,11 @@ uint ha_ndbcluster::set_up_partition_inf
           ng= 0;
         ts_names[fd_index]= part_elem->tablespace_name;
         frag_data[fd_index++]= ng;
-      } while (++j < part_info->no_subparts);
+      } while (++j < part_info->num_subparts);
     }
     first= FALSE;
-  } while (++i < part_info->no_parts);
-  tab->setDefaultNoPartitionsFlag(part_info->use_default_no_partitions);
+  } while (++i < part_info->num_parts);
+  tab->setDefaultNoPartitionsFlag(part_info->use_default_num_partitions);
   tab->setLinearFlag(part_info->linear_hash_ind);
   {
     ha_rows max_rows= table_share->max_rows;
@@ -11650,7 +11650,7 @@ ndberror2:
 }
 
 
-bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
+bool ha_ndbcluster::get_no_parts(const char *name, uint *num_parts)
 {
   THD *thd= current_thd;
   Ndb *ndb;
@@ -11673,7 +11673,7 @@ bool ha_ndbcluster::get_no_parts(const c
     Ndb_table_guard ndbtab_g(dict= ndb->getDictionary(), m_tabname);
     if (!ndbtab_g.get_table())
       ERR_BREAK(dict->getNdbError(), err);
-    *no_parts= ndbtab_g.get_table()->getFragmentCount();
+    *num_parts= ndbtab_g.get_table()->getFragmentCount();
     DBUG_RETURN(FALSE);
   }
 

=== modified file 'sql/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc	2009-11-02 15:11:43 +0000
+++ b/sql/ha_ndbcluster_binlog.cc	2009-11-05 12:13:00 +0000
@@ -4421,14 +4421,14 @@ ndb_binlog_thread_handle_data_event(Ndb 
       if (share->flags & NSF_BLOB_FLAG)
       {
         my_ptrdiff_t ptrdiff= 0;
-        IF_DBUG(int ret =) get_ndb_blobs_value(table, event_data->ndb_value[0],
+        int ret __attribute__((unused))= get_ndb_blobs_value(table, event_data->ndb_value[0],
                                                blobs_buffer[0],
                                                blobs_buffer_size[0],
                                                ptrdiff);
         DBUG_ASSERT(ret == 0);
       }
       ndb_unpack_record(table, event_data->ndb_value[0], &b, table->record[0]);
-      IF_DBUG(int ret=) trans.write_row(originating_server_id,
+      int ret __attribute__((unused))= trans.write_row(originating_server_id,
                                         injector::transaction::table(table,
                                                                      TRUE),
                                         &b, n_fields, table->record[0]);
@@ -4461,7 +4461,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
       if (share->flags & NSF_BLOB_FLAG)
       {
         my_ptrdiff_t ptrdiff= table->record[n] - table->record[0];
-        IF_DBUG(int ret =) get_ndb_blobs_value(table, event_data->ndb_value[n],
+        int ret __attribute__((unused))= get_ndb_blobs_value(table, event_data->ndb_value[n],
                                                blobs_buffer[n],
                                                blobs_buffer_size[n],
                                                ptrdiff);
@@ -4469,7 +4469,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
       }
       ndb_unpack_record(table, event_data->ndb_value[n], &b, table->record[n]);
       DBUG_EXECUTE("info", print_records(table, table->record[n]););
-      IF_DBUG(int ret =) trans.delete_row(originating_server_id,
+      int ret __attribute__((unused))= trans.delete_row(originating_server_id,
                                           injector::transaction::table(table,
                                                                        TRUE),
                                           &b, n_fields, table->record[n]);
@@ -4485,7 +4485,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
       if (share->flags & NSF_BLOB_FLAG)
       {
         my_ptrdiff_t ptrdiff= 0;
-        IF_DBUG(int ret =) get_ndb_blobs_value(table, event_data->ndb_value[0],
+        int ret __attribute__((unused))= get_ndb_blobs_value(table, event_data->ndb_value[0],
                                                blobs_buffer[0],
                                                blobs_buffer_size[0],
                                                ptrdiff);
@@ -4501,7 +4501,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
           since table has a primary key, we can do a write
           using only after values
         */
-        IF_DBUG(int ret =) trans.write_row(originating_server_id,
+        int ret __attribute__((unused))= trans.write_row(originating_server_id,
                                            injector::transaction::table(table, TRUE),
                                            &b, n_fields, table->record[0]);// after values
         DBUG_ASSERT(ret == 0);
@@ -4515,7 +4515,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
         if (share->flags & NSF_BLOB_FLAG)
         {
           my_ptrdiff_t ptrdiff= table->record[1] - table->record[0];
-          IF_DBUG(int ret =) get_ndb_blobs_value(table, event_data->ndb_value[1],
+          int ret __attribute__((unused))= get_ndb_blobs_value(table, event_data->ndb_value[1],
                                                  blobs_buffer[1],
                                                  blobs_buffer_size[1],
                                                  ptrdiff);
@@ -4523,7 +4523,7 @@ ndb_binlog_thread_handle_data_event(Ndb 
         }
         ndb_unpack_record(table, event_data->ndb_value[1], &b, table->record[1]);
         DBUG_EXECUTE("info", print_records(table, table->record[1]););
-        IF_DBUG(int ret =) trans.update_row(originating_server_id,
+        int ret __attribute__((unused))= trans.update_row(originating_server_id,
                                             injector::transaction::table(table,
                                                                          TRUE),
                                             &b, n_fields,
@@ -4823,7 +4823,7 @@ restart:
         { C_STRING_WITH_LEN("mysqld startup")    },
         { C_STRING_WITH_LEN("cluster disconnect")}
       };
-    IF_DBUG(int error=)
+    int error __attribute__((unused))=
       inj->record_incident(thd, INCIDENT_LOST_EVENTS, msg[incident_id]);
     DBUG_ASSERT(!error);
     break;
@@ -5227,7 +5227,7 @@ restart:
                                 (int) name.length, name.str,
                                 table->s->fields));
             injector::transaction::table tbl(table, TRUE);
-            IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
+            int ret __attribute__((unused))= trans.use_table(::server_id, tbl);
             DBUG_ASSERT(ret == 0);
           }
         }
@@ -5241,7 +5241,7 @@ restart:
                                 (int) name.length, name.str));
 #endif
             injector::transaction::table tbl(apply_status_table, TRUE);
-            IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
+            int ret __attribute__((unused))= trans.use_table(::server_id, tbl);
             DBUG_ASSERT(ret == 0);
 
             /* add the gci to the record */
@@ -5314,7 +5314,7 @@ restart:
           else
           {
             // set injector_ndb database/schema from table internal name
-            IF_DBUG(int ret=)
+            int ret __attribute__((unused))=
               i_ndb->setDatabaseAndSchemaName(pOp->getEvent()->getTable());
             DBUG_ASSERT(ret == 0);
             ndb_binlog_thread_handle_non_data_event(thd, i_ndb, pOp, *rows);

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2009-11-02 15:11:43 +0000
+++ b/sql/ha_partition.cc	2009-11-04 09:02:10 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -245,7 +245,7 @@ void ha_partition::init_handler_variable
   /*
     this allows blackhole to work properly
   */
-  m_no_locks= 0;
+  m_num_locks= 0;
 
 #ifdef DONT_HAVE_TO_BE_INITALIZED
   m_start_key.flag= 0;
@@ -581,8 +581,8 @@ int ha_partition::drop_partitions(THD *t
 {
   List_iterator<partition_element> part_it(m_part_info->partitions);
   char part_name_buff[FN_REFLEN];
-  uint no_parts= m_part_info->partitions.elements;
-  uint no_subparts= m_part_info->no_subparts;
+  uint num_parts= m_part_info->partitions.elements;
+  uint num_subparts= m_part_info->num_subparts;
   uint i= 0;
   uint name_variant;
   int  ret_error;
@@ -612,7 +612,7 @@ int ha_partition::drop_partitions(THD *t
         do
         {
           partition_element *sub_elem= sub_it++;
-          part= i * no_subparts + j;
+          part= i * num_subparts + j;
           create_subpartition_name(part_name_buff, path,
                                    part_elem->partition_name,
                                    sub_elem->partition_name, name_variant);
@@ -622,7 +622,7 @@ int ha_partition::drop_partitions(THD *t
             error= ret_error;
           if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos))
             error= 1;
-        } while (++j < no_subparts);
+        } while (++j < num_subparts);
       }
       else
       {
@@ -642,7 +642,7 @@ int ha_partition::drop_partitions(THD *t
       else
         part_elem->part_state= PART_IS_DROPPED;
     }
-  } while (++i < no_parts);
+  } while (++i < num_parts);
   (void) sync_ddl_log();
   DBUG_RETURN(error);
 }
@@ -673,9 +673,9 @@ int ha_partition::rename_partitions(THD 
   List_iterator<partition_element> temp_it(m_part_info->temp_partitions);
   char part_name_buff[FN_REFLEN];
   char norm_name_buff[FN_REFLEN];
-  uint no_parts= m_part_info->partitions.elements;
+  uint num_parts= m_part_info->partitions.elements;
   uint part_count= 0;
-  uint no_subparts= m_part_info->no_subparts;
+  uint num_subparts= m_part_info->num_subparts;
   uint i= 0;
   uint j= 0;
   int error= 0;
@@ -726,7 +726,7 @@ int ha_partition::rename_partitions(THD 
           else
             sub_elem->log_entry= NULL; /* Indicate success */
           delete file;
-        } while (++j < no_subparts);
+        } while (++j < num_subparts);
       }
       else
       {
@@ -784,7 +784,7 @@ int ha_partition::rename_partitions(THD 
         do
         {
           sub_elem= sub_it++;
-          part= i * no_subparts + j;
+          part= i * num_subparts + j;
           create_subpartition_name(norm_name_buff, path,
                                    part_elem->partition_name,
                                    sub_elem->partition_name,
@@ -817,7 +817,7 @@ int ha_partition::rename_partitions(THD 
           else
             sub_elem->log_entry= NULL;
           delete file;
-        } while (++j < no_subparts);
+        } while (++j < num_subparts);
       }
       else
       {
@@ -853,7 +853,7 @@ int ha_partition::rename_partitions(THD 
         delete file;
       }
     }
-  } while (++i < no_parts);
+  } while (++i < num_parts);
   (void) sync_ddl_log();
   DBUG_RETURN(error);
 }
@@ -1107,8 +1107,8 @@ int ha_partition::handle_opt_partitions(
                                         uint flag)
 {
   List_iterator<partition_element> part_it(m_part_info->partitions);
-  uint no_parts= m_part_info->no_parts;
-  uint no_subparts= m_part_info->no_subparts;
+  uint num_parts= m_part_info->num_parts;
+  uint num_subparts= m_part_info->num_subparts;
   uint i= 0;
   int error;
   DBUG_ENTER("ha_partition::handle_opt_partitions");
@@ -1132,7 +1132,7 @@ int ha_partition::handle_opt_partitions(
         do
         {
           sub_elem= subpart_it++;
-          part= i * no_subparts + j;
+          part= i * num_subparts + j;
           DBUG_PRINT("info", ("Optimize subpartition %u (%s)",
                      part, sub_elem->partition_name));
 #ifdef NOT_USED
@@ -1162,7 +1162,7 @@ int ha_partition::handle_opt_partitions(
             } while ((part_elem= part_it++));
             DBUG_RETURN(error);
           }
-        } while (++j < no_subparts);
+        } while (++j < num_subparts);
       }
       else
       {
@@ -1197,7 +1197,7 @@ int ha_partition::handle_opt_partitions(
       }
       part_elem->part_state= PART_NORMAL;
     }
-  } while (++i < no_parts);
+  } while (++i < num_parts);
   DBUG_RETURN(FALSE);
 }
 
@@ -1401,10 +1401,10 @@ int ha_partition::change_partitions(HA_C
   List_iterator<partition_element> part_it(m_part_info->partitions);
   List_iterator <partition_element> t_it(m_part_info->temp_partitions);
   char part_name_buff[FN_REFLEN];
-  uint no_parts= m_part_info->partitions.elements;
-  uint no_subparts= m_part_info->no_subparts;
+  uint num_parts= m_part_info->partitions.elements;
+  uint num_subparts= m_part_info->num_subparts;
   uint i= 0;
-  uint no_remain_partitions, part_count, orig_count;
+  uint num_remain_partitions, part_count, orig_count;
   handler **new_file_array;
   int error= 1;
   bool first;
@@ -1420,7 +1420,7 @@ int ha_partition::change_partitions(HA_C
                                                    part_name_buff)));
   m_reorged_parts= 0;
   if (!m_part_info->is_sub_partitioned())
-    no_subparts= 1;
+    num_subparts= 1;
 
   /*
     Step 1:
@@ -1429,7 +1429,7 @@ int ha_partition::change_partitions(HA_C
   */
   if (temp_partitions)
   {
-    m_reorged_parts= temp_partitions * no_subparts;
+    m_reorged_parts= temp_partitions * num_subparts;
   }
   else
   {
@@ -1439,9 +1439,9 @@ int ha_partition::change_partitions(HA_C
       if (part_elem->part_state == PART_CHANGED ||
           part_elem->part_state == PART_REORGED_DROPPED)
       {
-        m_reorged_parts+= no_subparts;
+        m_reorged_parts+= num_subparts;
       }
-    } while (++i < no_parts);
+    } while (++i < num_parts);
   }
   if (m_reorged_parts &&
       !(m_reorged_file= (handler**)sql_calloc(sizeof(handler*)*
@@ -1456,10 +1456,10 @@ int ha_partition::change_partitions(HA_C
       Calculate number of partitions after change and allocate space for
       their handler references.
   */
-  no_remain_partitions= 0;
+  num_remain_partitions= 0;
   if (temp_partitions)
   {
-    no_remain_partitions= no_parts * no_subparts;
+    num_remain_partitions= num_parts * num_subparts;
   }
   else
   {
@@ -1472,17 +1472,17 @@ int ha_partition::change_partitions(HA_C
           part_elem->part_state == PART_TO_BE_ADDED ||
           part_elem->part_state == PART_CHANGED)
       {
-        no_remain_partitions+= no_subparts;
+        num_remain_partitions+= num_subparts;
       }
-    } while (++i < no_parts);
+    } while (++i < num_parts);
   }
   if (!(new_file_array= (handler**)sql_calloc(sizeof(handler*)*
-                                              (2*(no_remain_partitions + 1)))))
+                                            (2*(num_remain_partitions + 1)))))
   {
-    mem_alloc_error(sizeof(handler*)*2*(no_remain_partitions+1));
+    mem_alloc_error(sizeof(handler*)*2*(num_remain_partitions+1));
     DBUG_RETURN(ER_OUTOFMEMORY);
   }
-  m_added_file= &new_file_array[no_remain_partitions + 1];
+  m_added_file= &new_file_array[num_remain_partitions + 1];
 
   /*
     Step 3:
@@ -1501,9 +1501,9 @@ int ha_partition::change_partitions(HA_C
           part_elem->part_state == PART_REORGED_DROPPED)
       {
         memcpy((void*)&m_reorged_file[part_count],
-               (void*)&m_file[i*no_subparts],
-               sizeof(handler*)*no_subparts);
-        part_count+= no_subparts;
+               (void*)&m_file[i*num_subparts],
+               sizeof(handler*)*num_subparts);
+        part_count+= num_subparts;
       }
       else if (first && temp_partitions &&
                part_elem->part_state == PART_TO_BE_ADDED)
@@ -1518,11 +1518,11 @@ int ha_partition::change_partitions(HA_C
           ones used to be.
         */
         first= FALSE;
-        DBUG_ASSERT(((i*no_subparts) + m_reorged_parts) <= m_file_tot_parts);
-        memcpy((void*)m_reorged_file, &m_file[i*no_subparts],
+        DBUG_ASSERT(((i*num_subparts) + m_reorged_parts) <= m_file_tot_parts);
+        memcpy((void*)m_reorged_file, &m_file[i*num_subparts],
                sizeof(handler*)*m_reorged_parts);
       }
-    } while (++i < no_parts);
+    } while (++i < num_parts);
   }
 
   /*
@@ -1540,11 +1540,11 @@ int ha_partition::change_partitions(HA_C
     partition_element *part_elem= part_it++;
     if (part_elem->part_state == PART_NORMAL)
     {
-      DBUG_ASSERT(orig_count + no_subparts <= m_file_tot_parts);
+      DBUG_ASSERT(orig_count + num_subparts <= m_file_tot_parts);
       memcpy((void*)&new_file_array[part_count], (void*)&m_file[orig_count],
-             sizeof(handler*)*no_subparts);
-      part_count+= no_subparts;
-      orig_count+= no_subparts;
+             sizeof(handler*)*num_subparts);
+      part_count+= num_subparts;
+      orig_count+= num_subparts;
     }
     else if (part_elem->part_state == PART_CHANGED ||
              part_elem->part_state == PART_TO_BE_ADDED)
@@ -1560,16 +1560,16 @@ int ha_partition::change_partitions(HA_C
           mem_alloc_error(sizeof(handler));
           DBUG_RETURN(ER_OUTOFMEMORY);
         }
-      } while (++j < no_subparts);
+      } while (++j < num_subparts);
       if (part_elem->part_state == PART_CHANGED)
-        orig_count+= no_subparts;
+        orig_count+= num_subparts;
       else if (temp_partitions && first)
       {
-        orig_count+= (no_subparts * temp_partitions);
+        orig_count+= (num_subparts * temp_partitions);
         first= FALSE;
       }
     }
-  } while (++i < no_parts);
+  } while (++i < num_parts);
   first= FALSE;
   /*
     Step 5:
@@ -1606,7 +1606,7 @@ int ha_partition::change_partitions(HA_C
                                    part_elem->partition_name,
                                    sub_elem->partition_name,
                                    name_variant);
-          part= i * no_subparts + j;
+          part= i * num_subparts + j;
           DBUG_PRINT("info", ("Add subpartition %s", part_name_buff));
           if ((error= prepare_new_partition(table, create_info,
                                             new_file_array[part],
@@ -1617,7 +1617,7 @@ int ha_partition::change_partitions(HA_C
             DBUG_RETURN(error);
           }
           m_added_file[part_count++]= new_file_array[part];
-        } while (++j < no_subparts);
+        } while (++j < num_subparts);
       }
       else
       {
@@ -1636,7 +1636,7 @@ int ha_partition::change_partitions(HA_C
         m_added_file[part_count++]= new_file_array[i];
       }
     }
-  } while (++i < no_parts);
+  } while (++i < num_parts);

 
   /*
     Step 6:
@@ -1653,7 +1653,7 @@ int ha_partition::change_partitions(HA_C
       part_elem->part_state= PART_IS_CHANGED;
     else if (part_elem->part_state == PART_REORGED_DROPPED)
       part_elem->part_state= PART_TO_BE_DROPPED;
-  } while (++i < no_parts);
+  } while (++i < num_parts);
   for (i= 0; i < temp_partitions; i++)
   {
     partition_element *part_elem= t_it++;
@@ -1694,9 +1694,9 @@ int ha_partition::copy_partitions(ulongl
   if (m_part_info->linear_hash_ind)
   {
     if (m_part_info->part_type == HASH_PARTITION)
-      set_linear_hash_mask(m_part_info, m_part_info->no_parts);
+      set_linear_hash_mask(m_part_info, m_part_info->num_parts);
     else
-      set_linear_hash_mask(m_part_info, m_part_info->no_subparts);
+      set_linear_hash_mask(m_part_info, m_part_info->num_subparts);
   }
 
   while (reorg_part < m_reorged_parts)
@@ -1976,7 +1976,7 @@ partition_element *ha_partition::find_pa
   uint curr_part_id= 0;
   List_iterator_fast <partition_element> part_it(m_part_info->partitions);
 
-  for (i= 0; i < m_part_info->no_parts; i++)
+  for (i= 0; i < m_part_info->num_parts; i++)
   {
     partition_element *part_elem;
     part_elem= part_it++;
@@ -1984,7 +1984,7 @@ partition_element *ha_partition::find_pa
     {
       uint j;
       List_iterator_fast <partition_element> sub_it(part_elem->subpartitions);
-      for (j= 0; j < m_part_info->no_subparts; j++)
+      for (j= 0; j < m_part_info->num_subparts; j++)
       {
 	part_elem= sub_it++;
 	if (part_id == curr_part_id++)
@@ -2105,7 +2105,7 @@ bool ha_partition::create_handler_file(c
 {
   partition_element *part_elem, *subpart_elem;
   uint i, j, part_name_len, subpart_name_len;
-  uint tot_partition_words, tot_name_len, no_parts;
+  uint tot_partition_words, tot_name_len, num_parts;
   uint tot_parts= 0;
   uint tot_len_words, tot_len_byte, chksum, tot_name_words;
   char *name_buffer_ptr;
@@ -2118,11 +2118,11 @@ bool ha_partition::create_handler_file(c
   List_iterator_fast <partition_element> part_it(m_part_info->partitions);
   DBUG_ENTER("create_handler_file");
 
-  no_parts= m_part_info->partitions.elements;
-  DBUG_PRINT("info", ("table name = %s, no_parts = %u", name,
-                      no_parts));
+  num_parts= m_part_info->partitions.elements;
+  DBUG_PRINT("info", ("table name = %s, num_parts = %u", name,
+                      num_parts));
   tot_name_len= 0;
-  for (i= 0; i < no_parts; i++)
+  for (i= 0; i < num_parts; i++)
   {
     part_elem= part_it++;
     if (part_elem->part_state != PART_NORMAL &&
@@ -2140,7 +2140,7 @@ bool ha_partition::create_handler_file(c
     else
     {
       List_iterator_fast <partition_element> sub_it(part_elem->subpartitions);
-      for (j= 0; j < m_part_info->no_subparts; j++)
+      for (j= 0; j < m_part_info->num_subparts; j++)
       {
 	subpart_elem= sub_it++;
         tablename_to_filename(subpart_elem->partition_name,
@@ -2174,7 +2174,7 @@ bool ha_partition::create_handler_file(c
   engine_array= (file_buffer + 12);
   name_buffer_ptr= (char*) (file_buffer + ((4 + tot_partition_words) * 4));
   part_it.rewind();
-  for (i= 0; i < no_parts; i++)
+  for (i= 0; i < num_parts; i++)
   {
     part_elem= part_it++;
     if (part_elem->part_state != PART_NORMAL &&
@@ -2192,7 +2192,7 @@ bool ha_partition::create_handler_file(c
     else
     {
       List_iterator_fast <partition_element> sub_it(part_elem->subpartitions);
-      for (j= 0; j < m_part_info->no_subparts; j++)
+      for (j= 0; j < m_part_info->num_subparts; j++)
       {
 	subpart_elem= sub_it++;
         tablename_to_filename(part_elem->partition_name, part_name,
@@ -2328,7 +2328,7 @@ bool ha_partition::new_handlers_from_par
   }
   m_file_tot_parts= m_tot_parts;
   bzero((char*) m_file, alloc_len);
-  DBUG_ASSERT(m_part_info->no_parts > 0);
+  DBUG_ASSERT(m_part_info->num_parts > 0);
 
   i= 0;
   part_count= 0;
@@ -2341,7 +2341,7 @@ bool ha_partition::new_handlers_from_par
     part_elem= part_it++;
     if (m_is_sub_partitioned)
     {
-      for (j= 0; j < m_part_info->no_subparts; j++)
+      for (j= 0; j < m_part_info->num_subparts; j++)
       {
 	if (!(m_file[part_count++]= get_new_handler(table_share, mem_root,
                                                     part_elem->engine_type)))
@@ -2358,7 +2358,7 @@ bool ha_partition::new_handlers_from_par
       DBUG_PRINT("info", ("engine_type: %u",
                  (uint) ha_legacy_type(part_elem->engine_type)));
     }
-  } while (++i < m_part_info->no_parts);
+  } while (++i < m_part_info->num_parts);
   if (part_elem->engine_type == myisam_hton)
   {
     DBUG_PRINT("info", ("MyISAM"));
@@ -2576,7 +2576,7 @@ int ha_partition::open(const char *name,
     if ((error= (*file)->ha_open(table, (const char*) name_buff, mode,
                                  test_if_locked)))
       goto err_handler;
-    m_no_locks+= (*file)->lock_count();
+    m_num_locks+= (*file)->lock_count();
     name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
     set_if_bigger(ref_length, ((*file)->ref_length));
     /*
@@ -2925,8 +2925,8 @@ int ha_partition::start_stmt(THD *thd, t
 uint ha_partition::lock_count() const
 {
   DBUG_ENTER("ha_partition::lock_count");
-  DBUG_PRINT("info", ("m_no_locks %d", m_no_locks));
-  DBUG_RETURN(m_no_locks);
+  DBUG_PRINT("info", ("m_num_locks %d", m_num_locks));
+  DBUG_RETURN(m_num_locks);
 }
 
 
@@ -3336,13 +3336,13 @@ int ha_partition::delete_all_rows()
       /* ALTER TABLE t TRUNCATE PARTITION ... */
       List_iterator<partition_element> part_it(m_part_info->partitions);
       int saved_error= 0;
-      uint no_parts= m_part_info->no_parts;
-      uint no_subparts= m_part_info->no_subparts;
+      uint num_parts= m_part_info->num_parts;
+      uint num_subparts= m_part_info->num_subparts;
       uint i= 0;
-      uint no_parts_set= alter_info->partition_names.elements;
-      uint no_parts_found= set_part_state(alter_info, m_part_info,
-                                          PART_ADMIN);
-      if (no_parts_set != no_parts_found &&
+      uint num_parts_set= alter_info->partition_names.elements;
+      uint num_parts_found= set_part_state(alter_info, m_part_info,
+                                           PART_ADMIN);
+      if (num_parts_set != num_parts_found &&
           (!(alter_info->flags & ALTER_ALL_PARTITION)))
         DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
 
@@ -3365,7 +3365,7 @@ int ha_partition::delete_all_rows()
             do
             {
               sub_elem= subpart_it++;
-              part= i * no_subparts + j;
+              part= i * num_subparts + j;
               bitmap_set_bit(&m_part_info->used_partitions, part);
               if (!saved_error)
               {
@@ -3379,7 +3379,7 @@ int ha_partition::delete_all_rows()
                     error != HA_ERR_WRONG_COMMAND)
                   saved_error= error;
               }
-            } while (++j < no_subparts);
+            } while (++j < num_subparts);
           }
           else
           {
@@ -3399,7 +3399,7 @@ int ha_partition::delete_all_rows()
           }
           part_elem->part_state= PART_NORMAL;
         }
-      } while (++i < no_parts);
+      } while (++i < num_parts);
       DBUG_RETURN(saved_error);
     }
     truncate= TRUE;

=== modified file 'sql/ha_partition.h'
--- a/sql/ha_partition.h	2009-11-02 15:16:58 +0000
+++ b/sql/ha_partition.h	2009-11-04 09:02:10 +0000
@@ -1,7 +1,7 @@
 #ifndef HA_PARTITION_INCLUDED
 #define HA_PARTITION_INCLUDED
 
-/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -22,7 +22,8 @@
 
 enum partition_keywords
 { 
-  PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR
+  PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR,
+  PKW_COLUMNS
 };
 
 /*
@@ -116,7 +117,7 @@ private:
 
   uint m_reorged_parts;                  // Number of reorganised parts
   uint m_tot_parts;                      // Total number of partitions;
-  uint m_no_locks;                       // For engines like ha_blackhole, which needs no locks
+  uint m_num_locks;                       // For engines like ha_blackhole, which needs no locks
   uint m_last_part;                      // Last file that we update,write,read
   int m_lock_type;                       // Remembers type of last
                                          // external_lock
@@ -248,10 +249,10 @@ public:
                                 size_t pack_frm_len);
   virtual int drop_partitions(THD *thd, const char *path);
   virtual int rename_partitions(THD *thd, const char *path);
-  bool get_no_parts(const char *name, uint *no_parts)
+  bool get_no_parts(const char *name, uint *num_parts)
   {
     DBUG_ENTER("ha_partition::get_no_parts");
-    *no_parts= m_tot_parts;
+    *num_parts= m_tot_parts;
     DBUG_RETURN(0);
   }
   virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share);

=== modified file 'sql/item_create.cc'
--- a/sql/item_create.cc	2009-11-02 15:11:43 +0000
+++ b/sql/item_create.cc	2009-11-04 09:02:10 +0000
@@ -2052,6 +2052,18 @@ protected:
   virtual ~Create_func_to_days() {}
 };
 
+class Create_func_to_seconds : public Create_func_arg1
+{
+public:
+  virtual Item* create(THD *thd, Item *arg1);
+
+  static Create_func_to_seconds s_singleton;
+
+protected:
+  Create_func_to_seconds() {}
+  virtual ~Create_func_to_seconds() {}
+};
+
 
 #ifdef HAVE_SPATIAL
 class Create_func_touches : public Create_func_arg2
@@ -4505,6 +4517,15 @@ Create_func_to_days::create(THD *thd, It
 }
 
 
+Create_func_to_seconds Create_func_to_seconds::s_singleton;
+
+Item*
+Create_func_to_seconds::create(THD *thd, Item *arg1)
+{
+  return new (thd->mem_root) Item_func_to_seconds(arg1);
+}
+
+
 #ifdef HAVE_SPATIAL
 Create_func_touches Create_func_touches::s_singleton;
 
@@ -4942,6 +4963,7 @@ static Native_func_registry func_array[]
   { { C_STRING_WITH_LEN("TIME_TO_SEC") }, BUILDER(Create_func_time_to_sec)},
   { { C_STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
   { { C_STRING_WITH_LEN("TO_DAYS") }, BUILDER(Create_func_to_days)},
+  { { C_STRING_WITH_LEN("TO_SECONDS") }, BUILDER(Create_func_to_seconds)},
   { { C_STRING_WITH_LEN("UCASE") }, BUILDER(Create_func_ucase)},
   { { C_STRING_WITH_LEN("UNCOMPRESS") }, BUILDER(Create_func_uncompress)},
   { { C_STRING_WITH_LEN("UNCOMPRESSED_LENGTH") }, BUILDER(Create_func_uncompressed_length)},

=== modified file 'sql/item_timefunc.cc'
--- a/sql/item_timefunc.cc	2009-10-22 06:12:30 +0000
+++ b/sql/item_timefunc.cc	2009-10-30 16:34:50 +0000
@@ -937,6 +937,48 @@ longlong Item_func_to_days::val_int()
 }
 
 
+longlong Item_func_to_seconds::val_int_endpoint(bool left_endp,
+                                                bool *incl_endp)
+{
+  DBUG_ASSERT(fixed == 1);
+  MYSQL_TIME ltime;
+  longlong seconds;
+  longlong days;
+  int dummy;                                /* unused */
+  if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
+  {
+    /* got NULL, leave the incl_endp intact */
+    return LONGLONG_MIN;
+  }
+  seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
+  seconds= ltime.neg ? -seconds : seconds;
+  days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
+  seconds+= days * 24L * 3600L;
+  /* Set to NULL if invalid date, but keep the value */
+  null_value= check_date(&ltime,
+                         (ltime.year || ltime.month || ltime.day),
+                         (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE),
+                         &dummy);
+  /*
+    Even if the evaluation return NULL, seconds is useful for pruning
+  */
+  return seconds;
+}
+
+longlong Item_func_to_seconds::val_int()
+{
+  DBUG_ASSERT(fixed == 1);
+  MYSQL_TIME ltime;
+  longlong seconds;
+  longlong days;
+  if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
+    return 0;
+  seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
+  seconds=ltime.neg ? -seconds : seconds;
+  days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
+  return seconds + days * 24L * 3600L;
+}
+
 /*
   Get information about this Item tree monotonicity
 
@@ -963,6 +1005,17 @@ enum_monotonicity_info Item_func_to_days
   return NON_MONOTONIC;
 }
 
+enum_monotonicity_info Item_func_to_seconds::get_monotonicity_info() const
+{
+  if (args[0]->type() == Item::FIELD_ITEM)
+  {
+    if (args[0]->field_type() == MYSQL_TYPE_DATE ||
+        args[0]->field_type() == MYSQL_TYPE_DATETIME)
+      return MONOTONIC_STRICT_INCREASING_NOT_NULL;
+  }
+  return NON_MONOTONIC;
+}
+
 
 longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
 {

=== modified file 'sql/item_timefunc.h'
--- a/sql/item_timefunc.h	2009-10-27 10:03:00 +0000
+++ b/sql/item_timefunc.h	2009-11-03 11:26:54 +0000
@@ -76,6 +76,24 @@ public:
 };
 
 
+class Item_func_to_seconds :public Item_int_func
+{
+public:
+  Item_func_to_seconds(Item *a) :Item_int_func(a) {}
+  longlong val_int();
+  const char *func_name() const { return "to_seconds"; }
+  void fix_length_and_dec() 
+  { 
+    decimals=0; 
+    max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
+    maybe_null=1; 
+  }
+  enum_monotonicity_info get_monotonicity_info() const;
+  longlong val_int_endpoint(bool left_endp, bool *incl_endp);
+  bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
+};
+
+
 class Item_func_dayofmonth :public Item_int_func
 {
 public:

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2009-11-03 09:42:49 +0000
+++ b/sql/log_event.cc	2009-11-06 16:34:09 +0000
@@ -1200,15 +1200,13 @@ Log_event* Log_event::read_log_event(con
     */
     if (description_event->event_type_permutation)
     {
-      IF_DBUG({
-          int new_event_type=
-            description_event->event_type_permutation[event_type];
-          DBUG_PRINT("info",
-                     ("converting event type %d to %d (%s)",
-                      event_type, new_event_type,
-                      get_type_str((Log_event_type)new_event_type)));
-        });
-      event_type= description_event->event_type_permutation[event_type];
+      int new_event_type=
+        description_event->event_type_permutation[event_type];
+      DBUG_PRINT("info",
+                 ("converting event type %d to %d (%s)",
+                  event_type, new_event_type,
+                  get_type_str((Log_event_type)new_event_type)));
+      event_type= new_event_type;
     }
 
     switch(event_type) {
@@ -3613,10 +3611,12 @@ Format_description_log_event(uint8 binlo
     */
     if (post_header_len)
     {
+#ifndef DBUG_OFF      
       // Allows us to sanity-check that all events initialized their
       // events (see the end of this 'if' block).
-      IF_DBUG(memset(post_header_len, 255,
-                     number_of_event_types*sizeof(uint8)););
+      memset(post_header_len, 255,
+                     number_of_event_types*sizeof(uint8));
+#endif
 
       /* Note: all event types must explicitly fill in their lengths here. */
       post_header_len[START_EVENT_V3-1]= START_V3_HEADER_LEN;
@@ -3670,11 +3670,9 @@ Format_description_log_event(uint8 binlo
       post_header_len[HEARTBEAT_LOG_EVENT-1]= HEARTBEAT_HEADER_LEN;
 
       // Sanity-check that all post header lengths are initialized.
-      IF_DBUG({
-          int i;
-          for (i=0; i<number_of_event_types; i++)
-            assert(post_header_len[i] != 255);
-        });
+      int i;
+      for (i=0; i<number_of_event_types; i++)
+        DBUG_ASSERT(post_header_len[i] != 255);
     }
     break;
 

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2009-11-03 09:42:49 +0000
+++ b/sql/mysql_priv.h	2009-11-06 16:34:09 +0000
@@ -1180,6 +1180,8 @@ int prepare_create_field(Create_field *s
 			 uint *blob_columns, 
 			 int *timestamps, int *timestamps_with_niladic,
 			 longlong table_flags);
+CHARSET_INFO* get_sql_field_charset(Create_field *sql_field,
+                                    HA_CREATE_INFO *create_info);
 bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
                         HA_CREATE_INFO *create_info,
                         Alter_info *alter_info);
@@ -1344,7 +1346,6 @@ void remove_status_vars(SHOW_VAR *list);
 void init_status_vars();
 void free_status_vars();
 void reset_status_vars();
-
 /* information schema */
 extern LEX_STRING INFORMATION_SCHEMA_NAME;
 /* log tables */
@@ -1577,6 +1578,11 @@ uint prep_alter_part_table(THD *thd, TAB
                            handlerton *old_db_type,
                            bool *partition_changed,
                            uint *fast_alter_partition);
+char *generate_partition_syntax(partition_info *part_info,
+                                uint *buf_length, bool use_sql_alloc,
+                                bool show_partition_options,
+                                HA_CREATE_INFO *create_info,
+                                Alter_info *alter_info);
 #endif
 
 enum enum_tdc_remove_table_type {TDC_RT_REMOVE_ALL, TDC_RT_REMOVE_NOT_OWN,

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2009-11-03 09:03:04 +0000
+++ b/sql/opt_range.cc	2009-11-06 16:34:09 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -481,8 +481,19 @@ public:
     return 0;
   }
 
-  /* returns a number of keypart values appended to the key buffer */
-  int store_min_key(KEY_PART *key, uchar **range_key, uint *range_key_flag)
+  /*
+    Returns a number of keypart values appended to the key buffer
+    for min key and max key. This function is used by both Range
+    Analysis and Partition pruning. For partition pruning we have
+    to ensure that we don't store also subpartition fields. Thus
+    we have to stop at the last partition part and not step into
+    the subpartition fields. For Range Analysis we set last_part
+    to MAX_KEY which we should never reach.
+  */
+  int store_min_key(KEY_PART *key,
+                    uchar **range_key,
+                    uint *range_key_flag,
+                    uint last_part)
   {
     SEL_ARG *key_tree= first();
     uint res= key_tree->store_min(key[key_tree->part].store_length,
@@ -490,27 +501,36 @@ public:
     *range_key_flag|= key_tree->min_flag;
     
     if (key_tree->next_key_part &&
+        key_tree->part != last_part &&
 	key_tree->next_key_part->part == key_tree->part+1 &&
 	!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) &&
 	key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
-      res+= key_tree->next_key_part->store_min_key(key, range_key,
-                                                   range_key_flag);
+      res+= key_tree->next_key_part->store_min_key(key,
+                                                   range_key,
+                                                   range_key_flag,
+                                                   last_part);
     return res;
   }
 
   /* returns a number of keypart values appended to the key buffer */
-  int store_max_key(KEY_PART *key, uchar **range_key, uint *range_key_flag)
+  int store_max_key(KEY_PART *key,
+                    uchar **range_key,
+                    uint *range_key_flag,
+                    uint last_part)
   {
     SEL_ARG *key_tree= last();
     uint res=key_tree->store_max(key[key_tree->part].store_length,
                                  range_key, *range_key_flag);
     (*range_key_flag)|= key_tree->max_flag;
     if (key_tree->next_key_part &&
-	key_tree->next_key_part->part == key_tree->part+1 &&
-	!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) &&
-	key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
-      res+= key_tree->next_key_part->store_max_key(key, range_key,
-                                                   range_key_flag);
+        key_tree->part != last_part &&
+        key_tree->next_key_part->part == key_tree->part+1 &&
+        !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) &&
+        key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
+      res+= key_tree->next_key_part->store_max_key(key,
+                                                   range_key,
+                                                   range_key_flag,
+                                                   last_part);
     return res;
   }
 
@@ -683,6 +703,14 @@ public:
     using_real_indexes==TRUE
   */
   uint real_keynr[MAX_KEY];
+
+  /*
+    Used to store 'current key tuples', in both range analysis and
+    partitioning (list) analysis
+  */
+  uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
+    max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
+
   /* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
   uint alloced_sel_args; 
   bool force_default_mrr;
@@ -693,11 +721,8 @@ class PARAM : public RANGE_OPT_PARAM
 public:
   KEY_PART *key[MAX_KEY]; /* First key parts of keys used in the query */
   longlong baseflag;
-  uint max_key_part;
-  /* Number of ranges in the last checked tree->key */
-  uint range_count;
-  uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
-    max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
+  uint max_key_part, range_count;
+
   bool quick;				// Don't calulate possible keys
 
   uint fields_bitmap_size;
@@ -2675,6 +2700,8 @@ typedef struct st_part_prune_param
   /* Same as above for subpartitioning */
   my_bool *is_subpart_keypart;
 
+  my_bool ignore_part_fields; /* Ignore rest of partioning fields */
+
   /***************************************************************
    Following fields form find_used_partitions() recursion context:
    **************************************************************/
@@ -2688,8 +2715,13 @@ typedef struct st_part_prune_param
   /* Iterator to be used to obtain the "current" set of used partitions */
   PARTITION_ITERATOR part_iter;
 
-  /* Initialized bitmap of no_subparts size */
+  /* Initialized bitmap of num_subparts size */
   MY_BITMAP subparts_bitmap;
+
+  uchar *cur_min_key;
+  uchar *cur_max_key;
+
+  uint cur_min_flag, cur_max_flag;
 } PART_PRUNE_PARAM;
 
 static bool create_partition_index_description(PART_PRUNE_PARAM *prune_par);
@@ -2806,6 +2838,11 @@ bool prune_partitions(THD *thd, TABLE *t
     prune_param.arg_stack_end= prune_param.arg_stack;
     prune_param.cur_part_fields= 0;
     prune_param.cur_subpart_fields= 0;
+    
+    prune_param.cur_min_key= prune_param.range_param.min_key;
+    prune_param.cur_max_key= prune_param.range_param.max_key;
+    prune_param.cur_min_flag= prune_param.cur_max_flag= 0;
+
     init_all_partitions_iterator(part_info, &prune_param.part_iter);
     if (!tree->keys[0] || (-1 == (res= find_used_partitions(&prune_param,
                                                             tree->keys[0]))))
@@ -2943,8 +2980,8 @@ static void mark_full_partition_used_no_
 static void mark_full_partition_used_with_parts(partition_info *part_info,
                                                 uint32 part_id)
 {
-  uint32 start= part_id * part_info->no_subparts;
-  uint32 end=   start + part_info->no_subparts; 
+  uint32 start= part_id * part_info->num_subparts;
+  uint32 end=   start + part_info->num_subparts; 
   DBUG_ENTER("mark_full_partition_used_with_parts");
 
   for (; start != end; start++)
@@ -3042,6 +3079,11 @@ int find_used_partitions_imerge(PART_PRU
     ppar->arg_stack_end= ppar->arg_stack;
     ppar->cur_part_fields= 0;
     ppar->cur_subpart_fields= 0;
+    
+    ppar->cur_min_key= ppar->range_param.min_key;
+    ppar->cur_max_key= ppar->range_param.max_key;
+    ppar->cur_min_flag= ppar->cur_max_flag= 0;
+
     init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
     SEL_ARG *key_tree= (*ptree)->keys[0];
     if (!key_tree || (-1 == (res |= find_used_partitions(ppar, key_tree))))
@@ -3165,9 +3207,14 @@ static 
 int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
 {
   int res, left_res=0, right_res=0;
-  int partno= (int)key_tree->part;
-  bool pushed= FALSE;
+  int key_tree_part= (int)key_tree->part;
   bool set_full_part_if_bad_ret= FALSE;
+  bool ignore_part_fields= ppar->ignore_part_fields;
+  bool did_set_ignore_part_fields= FALSE;
+  RANGE_OPT_PARAM *range_par= &(ppar->range_param);
+
+  if (check_stack_overrun(range_par->thd, 3*STACK_MIN_SIZE, NULL))
+    return -1;
 
   if (key_tree->left != &null_element)
   {
@@ -3175,56 +3222,177 @@ int find_used_partitions(PART_PRUNE_PARA
       return -1;
   }
 
+  /* Push SEL_ARG's to stack to enable looking backwards as well */
+  ppar->cur_part_fields+= ppar->is_part_keypart[key_tree_part];
+  ppar->cur_subpart_fields+= ppar->is_subpart_keypart[key_tree_part];
+  *(ppar->arg_stack_end++)= key_tree;
+
   if (key_tree->type == SEL_ARG::KEY_RANGE)
   {
-    if (partno == 0 && (NULL != ppar->part_info->get_part_iter_for_interval))
+    if (ppar->part_info->get_part_iter_for_interval && 
+        key_tree->part <= ppar->last_part_partno)
     {
-      /* 
-        Partitioning is done by RANGE|INTERVAL(monotonic_expr(fieldX)), and
-        we got "const1 CMP fieldX CMP const2" interval
+      if (ignore_part_fields)
+      {
+        /*
+          We come here when a condition on the first partitioning
+          fields led to evaluating the partitioning condition
+          (due to finding a condition of the type a < const or
+          b > const). Thus we must ignore the rest of the
+          partitioning fields but we still want to analyse the
+          subpartitioning fields.
+        */
+        if (key_tree->next_key_part)
+          res= find_used_partitions(ppar, key_tree->next_key_part);
+        else
+          res= -1;
+        goto pop_and_go_right;
+      }
+      /* Collect left and right bound, their lengths and flags */
+      uchar *min_key= ppar->cur_min_key;
+      uchar *max_key= ppar->cur_max_key;
+      uchar *tmp_min_key= min_key;
+      uchar *tmp_max_key= max_key;
+      key_tree->store_min(ppar->key[key_tree->part].store_length,
+                          &tmp_min_key, ppar->cur_min_flag);
+      key_tree->store_max(ppar->key[key_tree->part].store_length,
+                          &tmp_max_key, ppar->cur_max_flag);
+      uint flag;
+      if (key_tree->next_key_part &&
+          key_tree->next_key_part->part == key_tree->part+1 &&
+          key_tree->next_key_part->part <= ppar->last_part_partno &&
+          key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
+      {
+        /*
+          There are more key parts for partition pruning to handle
+          This mainly happens when the condition is an equality
+          condition.
+        */
+        if ((tmp_min_key - min_key) == (tmp_max_key - max_key) && 
+            (memcmp(min_key, max_key, (uint)(tmp_max_key - max_key)) == 0) &&
+            !key_tree->min_flag && !key_tree->max_flag)
+        {
+          /* Set 'parameters' */
+          ppar->cur_min_key= tmp_min_key;
+          ppar->cur_max_key= tmp_max_key;
+          uint save_min_flag= ppar->cur_min_flag;
+          uint save_max_flag= ppar->cur_max_flag;
+
+          ppar->cur_min_flag|= key_tree->min_flag;
+          ppar->cur_max_flag|= key_tree->max_flag;
+          
+          res= find_used_partitions(ppar, key_tree->next_key_part);
+           
+          /* Restore 'parameters' back */
+          ppar->cur_min_key= min_key;
+          ppar->cur_max_key= max_key;
+
+          ppar->cur_min_flag= save_min_flag;
+          ppar->cur_max_flag= save_max_flag;
+          goto pop_and_go_right;
+        }
+        /* We have arrived at the last field in the partition pruning */
+        uint tmp_min_flag= key_tree->min_flag,
+             tmp_max_flag= key_tree->max_flag;
+        if (!tmp_min_flag)
+          key_tree->next_key_part->store_min_key(ppar->key,
+                                                 &tmp_min_key,
+                                                 &tmp_min_flag,
+                                                 ppar->last_part_partno);
+        if (!tmp_max_flag)
+          key_tree->next_key_part->store_max_key(ppar->key,
+                                                 &tmp_max_key,
+                                                 &tmp_max_flag,
+                                                 ppar->last_part_partno);
+        flag= tmp_min_flag | tmp_max_flag;
+      }
+      else
+        flag= key_tree->min_flag | key_tree->max_flag;
+      
+      if (tmp_min_key != range_par->min_key)
+        flag&= ~NO_MIN_RANGE;
+      else
+        flag|= NO_MIN_RANGE;
+      if (tmp_max_key != range_par->max_key)
+        flag&= ~NO_MAX_RANGE;
+      else
+        flag|= NO_MAX_RANGE;
+
+      /*
+        We need to call the interval mapper if we have a condition which
+        makes sense to prune on. In the example of COLUMNS on a and
+        b it makes sense if we have a condition on a, or conditions on
+        both a and b. If we only have conditions on b it might make sense
+        but this is a harder case we will solve later. For the harder case
+        this clause then turns into use of all partitions and thus we
+        simply set res= -1 as if the mapper had returned that.
+        TODO: What to do here is defined in WL#4065.
       */
-      DBUG_EXECUTE("info", dbug_print_segment_range(key_tree,
-                                                    ppar->range_param.
-                                                    key_parts););
-      res= ppar->part_info->
-           get_part_iter_for_interval(ppar->part_info,
-                                      FALSE,
-                                      key_tree->min_value, 
-                                      key_tree->max_value,
-                                      key_tree->min_flag | key_tree->max_flag,
-                                      &ppar->part_iter);
-      if (!res)
-        goto go_right; /* res==0 --> no satisfying partitions */
+      if (ppar->arg_stack[0]->part == 0)
+      {
+        uint32 i;
+        uint32 store_length_array[MAX_KEY];
+        uint32 num_keys= ppar->part_fields;
+
+        for (i= 0; i < num_keys; i++)
+          store_length_array[i]= ppar->key[i].store_length;
+        res= ppar->part_info->
+             get_part_iter_for_interval(ppar->part_info,
+                                        FALSE,
+                                        store_length_array,
+                                        range_par->min_key,
+                                        range_par->max_key,
+                                        tmp_min_key - range_par->min_key,
+                                        tmp_max_key - range_par->max_key,
+                                        flag,
+                                        &ppar->part_iter);
+        if (!res)
+          goto pop_and_go_right; /* res==0 --> no satisfying partitions */
+      }
+      else
+        res= -1;
+
       if (res == -1)
       {
-        //get a full range iterator
+        /* get a full range iterator */
         init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
       }
       /* 
         Save our intent to mark full partition as used if we will not be able
         to obtain further limits on subpartitions
       */
+      if (key_tree_part < ppar->last_part_partno)
+      {
+        /*
+          We need to ignore the rest of the partitioning fields in all
+          evaluations after this
+        */
+        did_set_ignore_part_fields= TRUE;
+        ppar->ignore_part_fields= TRUE;
+      }
       set_full_part_if_bad_ret= TRUE;
       goto process_next_key_part;
     }
 
-    if (partno == ppar->last_subpart_partno && 
+    if (key_tree_part == ppar->last_subpart_partno && 
         (NULL != ppar->part_info->get_subpart_iter_for_interval))
     {
       PARTITION_ITERATOR subpart_iter;
       DBUG_EXECUTE("info", dbug_print_segment_range(key_tree,
-                                                    ppar->range_param.
-                                                    key_parts););
+                                                    range_par->key_parts););
       res= ppar->part_info->
            get_subpart_iter_for_interval(ppar->part_info,
                                          TRUE,
+                                         NULL, /* Currently not used here */
                                          key_tree->min_value, 
                                          key_tree->max_value,
-                                         key_tree->min_flag | key_tree->max_flag,
+                                         0, 0, /* Those are ignored here */
+                                         key_tree->min_flag |
+                                           key_tree->max_flag,
                                          &subpart_iter);
       DBUG_ASSERT(res); /* We can't get "no satisfying subpartitions" */
       if (res == -1)
-        return -1; /* all subpartitions satisfy */
+        goto pop_and_go_right; /* all subpartitions satisfy */
         
       uint32 subpart_id;
       bitmap_clear_all(&ppar->subparts_bitmap);
@@ -3237,23 +3405,19 @@ int find_used_partitions(PART_PRUNE_PARA
       while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) !=
               NOT_A_PARTITION_ID)
       {
-        for (uint i= 0; i < ppar->part_info->no_subparts; i++)
+        for (uint i= 0; i < ppar->part_info->num_subparts; i++)
           if (bitmap_is_set(&ppar->subparts_bitmap, i))
             bitmap_set_bit(&ppar->part_info->used_partitions,
-                           part_id * ppar->part_info->no_subparts + i);
+                           part_id * ppar->part_info->num_subparts + i);
       }
-      goto go_right;
+      goto pop_and_go_right;
     }
 
     if (key_tree->is_singlepoint())
     {
-      pushed= TRUE;
-      ppar->cur_part_fields+=    ppar->is_part_keypart[partno];
-      ppar->cur_subpart_fields+= ppar->is_subpart_keypart[partno];
-      *(ppar->arg_stack_end++) = key_tree;
-
-      if (partno == ppar->last_part_partno &&
-          ppar->cur_part_fields == ppar->part_fields)
+      if (key_tree_part == ppar->last_part_partno &&
+          ppar->cur_part_fields == ppar->part_fields &&
+          ppar->part_info->get_part_iter_for_interval == NULL)
       {
         /* 
           Ok, we've got "fieldN<=>constN"-type SEL_ARGs for all partitioning
@@ -3282,7 +3446,7 @@ int find_used_partitions(PART_PRUNE_PARA
         goto process_next_key_part;
       }
 
-      if (partno == ppar->last_subpart_partno &&
+      if (key_tree_part == ppar->last_subpart_partno &&
           ppar->cur_subpart_fields == ppar->subpart_fields)
       {
         /* 
@@ -3306,7 +3470,7 @@ int find_used_partitions(PART_PRUNE_PARA
                 NOT_A_PARTITION_ID)
         {
           bitmap_set_bit(&part_info->used_partitions,
-                         part_id * part_info->no_subparts + subpart_id);
+                         part_id * part_info->num_subparts + subpart_id);
         }
         res= 1; /* Some partitions were marked as used */
         goto pop_and_go_right;
@@ -3319,8 +3483,11 @@ int find_used_partitions(PART_PRUNE_PARA
         we're processing subpartititoning's key parts, this means we'll not be
         able to infer any suitable condition, so bail out.
       */
-      if (partno >= ppar->last_part_partno)
-        return -1;
+      if (key_tree_part >= ppar->last_part_partno)
+      {
+        res= -1;
+        goto pop_and_go_right;
+      }
     }
   }
 
@@ -3329,7 +3496,17 @@ process_next_key_part:
     res= find_used_partitions(ppar, key_tree->next_key_part);
   else
     res= -1;
- 
+
+  if (did_set_ignore_part_fields)
+  {
+    /*
+      We have returned from processing all key trees linked to our next
+      key part. We are ready to be moving down (using right pointers) and
+      this tree is a new evaluation requiring its own decision on whether
+      to ignore partitioning fields.
+    */
+    ppar->ignore_part_fields= FALSE;
+  }
   if (set_full_part_if_bad_ret)
   {
     if (res == -1)
@@ -3352,18 +3529,14 @@ process_next_key_part:
     init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
   }
 
-  if (pushed)
-  {
 pop_and_go_right:
-    /* Pop this key part info off the "stack" */
-    ppar->arg_stack_end--;
-    ppar->cur_part_fields-=    ppar->is_part_keypart[partno];
-    ppar->cur_subpart_fields-= ppar->is_subpart_keypart[partno];
-  }
+  /* Pop this key part info off the "stack" */
+  ppar->arg_stack_end--;
+  ppar->cur_part_fields-=    ppar->is_part_keypart[key_tree_part];
+  ppar->cur_subpart_fields-= ppar->is_subpart_keypart[key_tree_part];
 
   if (res == -1)
     return -1;
-go_right:
   if (key_tree->right != &null_element)
   {
     if (-1 == (right_res= find_used_partitions(ppar,key_tree->right)))
@@ -3445,13 +3618,14 @@ static bool create_partition_index_descr
   uint used_part_fields, used_subpart_fields;
 
   used_part_fields= fields_ok_for_partition_index(part_info->part_field_array) ?
-                      part_info->no_part_fields : 0;
+                      part_info->num_part_fields : 0;
   used_subpart_fields= 
     fields_ok_for_partition_index(part_info->subpart_field_array)? 
-      part_info->no_subpart_fields : 0;
+      part_info->num_subpart_fields : 0;
   
   uint total_parts= used_part_fields + used_subpart_fields;
 
+  ppar->ignore_part_fields= FALSE;
   ppar->part_fields=      used_part_fields;
   ppar->last_part_partno= (int)used_part_fields - 1;
 
@@ -3486,10 +3660,10 @@ static bool create_partition_index_descr
   if (ppar->subpart_fields)
   {
     my_bitmap_map *buf;
-    uint32 bufsize= bitmap_buffer_size(ppar->part_info->no_subparts);
+    uint32 bufsize= bitmap_buffer_size(ppar->part_info->num_subparts);
     if (!(buf= (my_bitmap_map*) alloc_root(alloc, bufsize)))
       return TRUE;
-    bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->no_subparts,
+    bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->num_subparts,
                 FALSE);
   }
   range_par->key_parts= key_part;
@@ -3500,12 +3674,8 @@ static bool create_partition_index_descr
   {
     key_part->key=          0;
     key_part->part=	    part;
-    key_part->store_length= key_part->length= (uint16) (*field)->key_length();
-    if ((*field)->real_maybe_null())
-      key_part->store_length+= HA_KEY_NULL_LENGTH;
-    if ((*field)->type() == MYSQL_TYPE_BLOB || 
-        (*field)->real_type() == MYSQL_TYPE_VARCHAR)
-      key_part->store_length+= HA_KEY_BLOB_LENGTH;
+    key_part->length= (uint16)(*field)->key_length();
+    key_part->store_length= (uint16)get_partition_field_store_length(*field);
 
     DBUG_PRINT("info", ("part %u length %u store_length %u", part,
                          key_part->length, key_part->store_length));
@@ -7540,12 +7710,14 @@ walk_right_n_up:
           cur->min_key_parts += 
             key_tree->next_key_part->store_min_key(seq->param->key[seq->keyno],
                                                    &cur->min_key,
-                                                   &cur->min_key_flag);
+                                                   &cur->min_key_flag,
+                                                   MAX_KEY);
         if (!key_tree->max_flag)
           cur->max_key_parts += 
             key_tree->next_key_part->store_max_key(seq->param->key[seq->keyno],
                                                    &cur->max_key,
-                                                   &cur->max_key_flag);
+                                                   &cur->max_key_flag,
+                                                   MAX_KEY);
         break;
       }
     }
@@ -7921,11 +8093,15 @@ get_quick_keys(PARAM *param,QUICK_RANGE_
     {
       uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag;
       if (!tmp_min_flag)
-        min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key,
-                                                          &tmp_min_flag);
+        min_part+= key_tree->next_key_part->store_min_key(key,
+                                                          &tmp_min_key,
+                                                          &tmp_min_flag,
+                                                          MAX_KEY);
       if (!tmp_max_flag)
-        max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key,
-                                                          &tmp_max_flag);
+        max_part+= key_tree->next_key_part->store_max_key(key,
+                                                          &tmp_max_key,
+                                                          &tmp_max_flag,
+                                                          MAX_KEY);
       flag=tmp_min_flag | tmp_max_flag;
     }
   }

=== modified file 'sql/partition_element.h'
--- a/sql/partition_element.h	2009-10-26 14:02:26 +0000
+++ b/sql/partition_element.h	2009-10-30 16:34:50 +0000
@@ -1,7 +1,7 @@
 #ifndef PARTITION_ELEMENT_INCLUDED
 #define PARTITION_ELEMENT_INCLUDED
 
-/* Copyright (C) 2006 MySQL AB
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -40,6 +40,35 @@ enum partition_state {
 };
 
 /*
+  This struct is used to keep track of column expressions as part
+  of the COLUMNS concept in conjunction with RANGE and LIST partitioning.
+  The value can be either of MINVALUE, MAXVALUE and an expression that
+  must be constant and evaluate to the same type as the column it
+  represents.
+
+  The data in this fixed in two steps. The parser will only fill in whether
+  it is a max_value or provide an expression. Filling in
+  column_value, part_info, partition_id, null_value is done by the
+  function fix_column_value_function. However the item tree needs
+  fixed also before writing it into the frm file (in add_column_list_values).
+  To distinguish between those two variants, fixed= 1 after the
+  fixing in add_column_list_values and fixed= 2 otherwise. This is
+  since the fixing in add_column_list_values isn't a complete fixing.
+*/
+
+typedef struct p_column_list_val
+{
+  void* column_value;
+  Item* item_expression;
+  partition_info *part_info;
+  uint partition_id;
+  bool max_value;
+  bool null_value;
+  char fixed;
+} part_column_list_val;
+
+
+/*
   This struct is used to contain the value of an element
   in the VALUES IN struct. It needs to keep knowledge of
   whether it is a signed/unsigned value and whether it is
@@ -49,8 +78,10 @@ enum partition_state {
 typedef struct p_elem_val
 {
   longlong value;
+  uint added_items;
   bool null_value;
   bool unsigned_flag;
+  part_column_list_val *col_val_array;
 } part_elem_value;
 
 struct st_ddl_log_memory_entry;
@@ -72,8 +103,9 @@ public:
   enum partition_state part_state;
   uint16 nodegroup_id;
   bool has_null_value;
-  bool signed_flag;/* Indicate whether this partition uses signed constants */
-  bool max_value;  /* Indicate whether this partition uses MAXVALUE */
+  /* signed_flag and max_value only relevant for subpartitions */
+  bool signed_flag;
+  bool max_value;
 
   partition_element()
   : part_max_rows(0), part_min_rows(0), range_value(0),

=== modified file 'sql/partition_info.cc'
--- a/sql/partition_info.cc	2009-09-23 15:02:56 +0000
+++ b/sql/partition_info.cc	2009-10-30 20:43:49 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006-2008 MySQL AB, Sun Microsystems Inc. 2008-2009
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -75,7 +75,7 @@ partition_info *partition_info::get_clon
   SYNOPSIS
     create_default_partition_names()
     part_no                         Partition number for subparts
-    no_parts                        Number of partitions
+    num_parts                       Number of partitions
     start_no                        Starting partition number
     subpart                         Is it subpartitions
 
@@ -91,10 +91,10 @@ partition_info *partition_info::get_clon
 #define MAX_PART_NAME_SIZE 8
 
 char *partition_info::create_default_partition_names(uint part_no,
-                                                     uint no_parts_arg,
+                                                     uint num_parts_arg,
                                                      uint start_no)
 {
-  char *ptr= (char*) sql_calloc(no_parts_arg*MAX_PART_NAME_SIZE);
+  char *ptr= (char*) sql_calloc(num_parts_arg*MAX_PART_NAME_SIZE);
   char *move_ptr= ptr;
   uint i= 0;
   DBUG_ENTER("create_default_partition_names");
@@ -105,11 +105,11 @@ char *partition_info::create_default_par
     {
       my_sprintf(move_ptr, (move_ptr,"p%u", (start_no + i)));
       move_ptr+=MAX_PART_NAME_SIZE;
-    } while (++i < no_parts_arg);
+    } while (++i < num_parts_arg);
   }
   else
   {
-    mem_alloc_error(no_parts_arg*MAX_PART_NAME_SIZE);
+    mem_alloc_error(num_parts_arg*MAX_PART_NAME_SIZE);
   }
   DBUG_RETURN(ptr);
 }
@@ -189,19 +189,19 @@ bool partition_info::set_up_default_part
     goto end;
   }
 
-  if ((no_parts == 0) &&
-      ((no_parts= file->get_default_no_partitions(info)) == 0))
+  if ((num_parts == 0) &&
+      ((num_parts= file->get_default_no_partitions(info)) == 0))
   {
     my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions");
     goto end;
   }
 
-  if (unlikely(no_parts > MAX_PARTITIONS))
+  if (unlikely(num_parts > MAX_PARTITIONS))
   {
     my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
     goto end;
   }
-  if (unlikely((!(default_name= create_default_partition_names(0, no_parts,
+  if (unlikely((!(default_name= create_default_partition_names(0, num_parts,
                                                                start_no)))))
     goto end;
   i= 0;
@@ -220,7 +220,7 @@ bool partition_info::set_up_default_part
       mem_alloc_error(sizeof(partition_element));
       goto end;
     }
-  } while (++i < no_parts);
+  } while (++i < num_parts);

   result= FALSE;
 end:
   DBUG_RETURN(result);
@@ -259,9 +259,9 @@ bool partition_info::set_up_default_subp
   List_iterator<partition_element> part_it(partitions);
   DBUG_ENTER("partition_info::set_up_default_subpartitions");
 
-  if (no_subparts == 0)
-    no_subparts= file->get_default_no_partitions(info);
-  if (unlikely((no_parts * no_subparts) > MAX_PARTITIONS))
+  if (num_subparts == 0)
+    num_subparts= file->get_default_no_partitions(info);
+  if (unlikely((num_parts * num_subparts) > MAX_PARTITIONS))
   {
     my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
     goto end;
@@ -288,8 +288,8 @@ bool partition_info::set_up_default_subp
         mem_alloc_error(sizeof(partition_element));
         goto end;
       }
-    } while (++j < no_subparts);
-  } while (++i < no_parts);
+    } while (++j < num_subparts);
+  } while (++i < num_parts);
   result= FALSE;
 end:
   DBUG_RETURN(result);
@@ -334,6 +334,49 @@ bool partition_info::set_up_defaults_for
 
 
 /*
+  Support routine for check_partition_info
+
+  SYNOPSIS
+    has_unique_fields
+    no parameters
+
+  RETURN VALUE
+    Erroneus field name  Error, there are two fields with same name
+    NULL                 Ok, no field defined twice
+
+  DESCRIPTION
+    Check that the user haven't defined the same field twice in
+    key or column list partitioning.
+*/
+char* partition_info::has_unique_fields()
+{
+  char *field_name_outer, *field_name_inner;
+  List_iterator<char> it_outer(part_field_list);
+  uint num_fields= part_field_list.elements;
+  uint i,j;
+  DBUG_ENTER("partition_info::has_unique_fields");
+
+  for (i= 0; i < num_fields; i++)
+  {
+    field_name_outer= it_outer++;
+    List_iterator<char> it_inner(part_field_list);
+    for (j= 0; j < num_fields; j++)
+    {
+      field_name_inner= it_inner++;
+      if (i >= j)
+        continue;
+      if (!(my_strcasecmp(system_charset_info,
+                          field_name_outer,
+                          field_name_inner)))
+      {
+        DBUG_RETURN(field_name_outer);
+      }
+    }
+  }
+  DBUG_RETURN(NULL);
+}
+
+/*

   A support function to check if a partition element's name is unique
   
   SYNOPSIS
@@ -518,12 +561,12 @@ bool partition_info::check_engine_mix(ha
 {
   handlerton *old_engine_type= engine_type;
   bool first= TRUE;
-  uint no_parts= partitions.elements;
+  uint num_parts= partitions.elements;
   DBUG_ENTER("partition_info::check_engine_mix");
   DBUG_PRINT("info", ("in: engine_type = %s, table_engine_set = %u",
                        ha_resolve_storage_engine_name(engine_type),
                        table_engine_set));
-  if (no_parts)
+  if (num_parts)
   {
     List_iterator<partition_element> part_it(partitions);
     uint i= 0;
@@ -536,7 +579,7 @@ bool partition_info::check_engine_mix(ha
       if (is_sub_partitioned() &&
           part_elem->subpartitions.elements)
       {
-        uint no_subparts= part_elem->subpartitions.elements;
+        uint num_subparts= part_elem->subpartitions.elements;
         uint j= 0;
         List_iterator<partition_element> sub_it(part_elem->subpartitions);
         do
@@ -548,7 +591,7 @@ bool partition_info::check_engine_mix(ha
           if (check_engine_condition(sub_elem, table_engine_set,
                                      &engine_type, &first))
             goto error;
-        } while (++j < no_subparts);
+        } while (++j < num_subparts);
         /* ensure that the partition also has correct engine */
         if (check_engine_condition(part_elem, table_engine_set,
                                    &engine_type, &first))
@@ -557,7 +600,7 @@ bool partition_info::check_engine_mix(ha
       else if (check_engine_condition(part_elem, table_engine_set,
                                       &engine_type, &first))
         goto error;
-    } while (++i < no_parts);
+    } while (++i < num_parts);
   }
   DBUG_PRINT("info", ("engine_type = %s",
                        ha_resolve_storage_engine_name(engine_type)));
@@ -589,6 +632,7 @@ error:
 
   SYNOPSIS
     check_range_constants()
+    thd                          Thread object
 
   RETURN VALUE
     TRUE                An error occurred during creation of range constants
@@ -601,76 +645,112 @@ error:
     called for RANGE PARTITIONed tables.
 */
 
-bool partition_info::check_range_constants()
+bool partition_info::check_range_constants(THD *thd)
 {
   partition_element* part_def;
-  longlong current_largest;
-  longlong part_range_value;
   bool first= TRUE;
   uint i;
   List_iterator<partition_element> it(partitions);
-  bool result= TRUE;
-  bool signed_flag= !part_expr->unsigned_flag;
+  int result= TRUE;
   DBUG_ENTER("partition_info::check_range_constants");
-  DBUG_PRINT("enter", ("INT_RESULT with %d parts", no_parts));
+  DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", num_parts,
+                                                         column_list));
 
-  LINT_INIT(current_largest);
-
-  part_result_type= INT_RESULT;
-  range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong));
-  if (unlikely(range_int_array == NULL))
-  {
-    mem_alloc_error(no_parts * sizeof(longlong));
-    goto end;
-  }
-  i= 0;
-  do
+  if (column_list)
   {
-    part_def= it++;
-    if ((i != (no_parts - 1)) || !defined_max_value)
+    part_column_list_val *loc_range_col_array;
+    part_column_list_val *current_largest_col_val;
+    uint num_column_values= part_field_list.elements;
+    uint size_entries= sizeof(part_column_list_val) * num_column_values;
+    range_col_array= (part_column_list_val*)sql_calloc(num_parts *
+                                                       size_entries);
+    LINT_INIT(current_largest_col_val);
+    if (unlikely(range_col_array == NULL))
     {
-      part_range_value= part_def->range_value;
-      if (!signed_flag)
-        part_range_value-= 0x8000000000000000ULL;
+      mem_alloc_error(num_parts * size_entries);
+      goto end;
     }
-    else
-      part_range_value= LONGLONG_MAX;
-    if (first)
+    loc_range_col_array= range_col_array;
+    i= 0;
+    do
     {
-      current_largest= part_range_value;
-      range_int_array[0]= part_range_value;
+      part_def= it++;
+      {
+        List_iterator<part_elem_value> list_val_it(part_def->list_val_list);
+        part_elem_value *range_val= list_val_it++;
+        part_column_list_val *col_val= range_val->col_val_array;
+
+        if (fix_column_value_functions(thd, range_val, i))
+          goto end;
+        memcpy(loc_range_col_array, (const void*)col_val, size_entries);
+        loc_range_col_array+= num_column_values;
+        if (!first)
+        {
+          if (compare_column_values((const void*)current_largest_col_val,
+                                    (const void*)col_val) >= 0)
+            goto range_not_increasing_error;
+        }
+        current_largest_col_val= col_val;
+      }
       first= FALSE;
+    } while (++i < num_parts);
+  }
+  else
+  {
+    longlong current_largest;
+    longlong part_range_value;
+    bool signed_flag= !part_expr->unsigned_flag;
+
+    LINT_INIT(current_largest);
+
+    part_result_type= INT_RESULT;
+    range_int_array= (longlong*)sql_alloc(num_parts * sizeof(longlong));
+    if (unlikely(range_int_array == NULL))
+    {
+      mem_alloc_error(num_parts * sizeof(longlong));
+      goto end;
     }
-    else
+    i= 0;
+    do
     {
-      if (likely(current_largest < part_range_value))
-      {
-        current_largest= part_range_value;
-        range_int_array[i]= part_range_value;
-      }
-      else if (defined_max_value &&
-               current_largest == part_range_value &&
-               part_range_value == LONGLONG_MAX &&
-               i == (no_parts - 1))
+      part_def= it++;
+      if ((i != (num_parts - 1)) || !defined_max_value)
       {
-        range_int_array[i]= part_range_value;
+        part_range_value= part_def->range_value;
+        if (!signed_flag)
+          part_range_value-= 0x8000000000000000ULL;
       }
       else
+        part_range_value= LONGLONG_MAX;
+
+      if (!first)
       {
-        my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
-        goto end;
+        if (unlikely(current_largest > part_range_value) ||
+            (unlikely(current_largest == part_range_value) &&
+            (part_range_value < LONGLONG_MAX ||
+             i != (num_parts - 1) ||
+             !defined_max_value)))
+          goto range_not_increasing_error;
       }
-    }
-  } while (++i < no_parts);
+      range_int_array[i]= part_range_value;
+      current_largest= part_range_value;
+      first= FALSE;
+    } while (++i < num_parts);
+  }
   result= FALSE;
 end:
   DBUG_RETURN(result);
+
+range_not_increasing_error:
+  my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
+  goto end;
 }
 
 
 /*
   Support routines for check_list_constants used by qsort to sort the
-  constant list expressions. One routine for unsigned and one for signed.
+  constant list expressions. One routine for integers and one for
+  column lists.
 
   SYNOPSIS
     list_part_cmp()
@@ -695,6 +775,54 @@ int partition_info::list_part_cmp(const 
     return 0;
 }
 
+ /*
+  Compare two lists of column values in RANGE/LIST partitioning
+  SYNOPSIS
+    compare_column_values()
+    first                    First column list argument
+    second                   Second column list argument
+  RETURN VALUES
+    0                        Equal
+    -1                       First argument is smaller
+    +1                       First argument is larger
+*/
+
+int partition_info::compare_column_values(const void *first_arg,
+                                          const void *second_arg)
+{
+  const part_column_list_val *first= (part_column_list_val*)first_arg;
+  const part_column_list_val *second= (part_column_list_val*)second_arg;
+  partition_info *part_info= first->part_info;

+  Field **field;
+
+  for (field= part_info->part_field_array; *field;
+       field++, first++, second++)
+  {
+    if (first->max_value || second->max_value)
+    {
+      if (first->max_value && second->max_value)
+        continue;
+      if (second->max_value)
+        return -1;
+      else
+        return +1;
+    }
+    if (first->null_value || second->null_value)
+    {
+      if (first->null_value && second->null_value)
+        continue;
+      if (second->null_value)
+        return +1;
+      else
+        return -1;
+    }
+    int res= (*field)->cmp((const uchar*)first->column_value,
+                           (const uchar*)second->column_value);
+    if (res)
+      return res;
+  }
+  return 0;
+}
 
 /*
   This routine allocates an array for all list constants to achieve a fast
@@ -704,6 +832,7 @@ int partition_info::list_part_cmp(const 
 
   SYNOPSIS
     check_list_constants()
+    thd                            Thread object
 
   RETURN VALUE
     TRUE                  An error occurred during creation of list constants
@@ -716,20 +845,23 @@ int partition_info::list_part_cmp(const 
     called for LIST PARTITIONed tables.
 */
 
-bool partition_info::check_list_constants()
+bool partition_info::check_list_constants(THD *thd)
 {
-  uint i;
+  uint i, size_entries, num_column_values;
   uint list_index= 0;
   part_elem_value *list_value;
   bool result= TRUE;
-  longlong curr_value, prev_value, type_add, calc_value;
+  longlong type_add, calc_value;
+  void *curr_value, *prev_value;
   partition_element* part_def;
   bool found_null= FALSE;
+  int (*compare_func)(const void *, const void*);
+  void *ptr;
   List_iterator<partition_element> list_func_it(partitions);
   DBUG_ENTER("partition_info::check_list_constants");
 
   part_result_type= INT_RESULT;
-  no_list_values= 0;
+  num_list_values= 0;
   /*
     We begin by calculating the number of list values that have been
     defined in the first step.
@@ -762,51 +894,86 @@ bool partition_info::check_list_constant
     }
     List_iterator<part_elem_value> list_val_it1(part_def->list_val_list);
     while (list_val_it1++)
-      no_list_values++;
-  } while (++i < no_parts);
+      num_list_values++;
+  } while (++i < num_parts);
   list_func_it.rewind();
-  list_array= (LIST_PART_ENTRY*)sql_alloc((no_list_values+1) *
-                                          sizeof(LIST_PART_ENTRY));
-  if (unlikely(list_array == NULL))
+  num_column_values= part_field_list.elements;
+  size_entries= column_list ?
+        (num_column_values * sizeof(part_column_list_val)) :
+        sizeof(LIST_PART_ENTRY);
+  ptr= sql_calloc((num_list_values+1) * size_entries);
+  if (unlikely(ptr == NULL))
   {
-    mem_alloc_error(no_list_values * sizeof(LIST_PART_ENTRY));
+    mem_alloc_error(num_list_values * size_entries);
     goto end;
   }
-
-  i= 0;
-  /*
-    Fix to be able to reuse signed sort functions also for unsigned
-    partition functions.
-  */
-  type_add= (longlong)(part_expr->unsigned_flag ?
+  if (column_list)
+  {
+    part_column_list_val *loc_list_col_array;
+    loc_list_col_array= (part_column_list_val*)ptr;
+    list_col_array= (part_column_list_val*)ptr;
+    compare_func= compare_column_values;
+    i= 0;
+    do
+    {
+      part_def= list_func_it++;
+      List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
+      while ((list_value= list_val_it2++))
+      {
+        part_column_list_val *col_val= list_value->col_val_array;
+        if (unlikely(fix_column_value_functions(thd, list_value, i)))
+        {
+          DBUG_RETURN(TRUE);
+        }
+        memcpy(loc_list_col_array, (const void*)col_val, size_entries);
+        loc_list_col_array+= num_column_values;
+      }
+    } while (++i < num_parts);
+  }
+  else
+  {
+    compare_func= list_part_cmp;
+    list_array= (LIST_PART_ENTRY*)ptr;
+    i= 0;
+    /*
+      Fix to be able to reuse signed sort functions also for unsigned
+      partition functions.
+    */
+    type_add= (longlong)(part_expr->unsigned_flag ?
                                        0x8000000000000000ULL :
                                        0ULL);
 
-  do
-  {
-    part_def= list_func_it++;
-    List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
-    while ((list_value= list_val_it2++))
+    do
     {
-      calc_value= list_value->value - type_add;
-      list_array[list_index].list_value= calc_value;
-      list_array[list_index++].partition_id= i;
-    }
-  } while (++i < no_parts);
-
-  if (fixed && no_list_values)
+      part_def= list_func_it++;
+      List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
+      while ((list_value= list_val_it2++))
+      {
+        calc_value= list_value->value - type_add;
+        list_array[list_index].list_value= calc_value;
+        list_array[list_index++].partition_id= i;
+      }
+    } while (++i < num_parts);
+  }
+  DBUG_ASSERT(fixed);
+  if (num_list_values)
   {
     bool first= TRUE;
-    my_qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), 
-             &list_part_cmp);
- 
+    /*
+      list_array and list_col_array are unions, so this works for both
+      variants of LIST partitioning.
+    */
+    my_qsort((void*)list_array, num_list_values, size_entries,
+             compare_func);
+
     i= 0;
     LINT_INIT(prev_value);
     do
     {
-      DBUG_ASSERT(i < no_list_values);
-      curr_value= list_array[i].list_value;
-      if (likely(first || prev_value != curr_value))
+      DBUG_ASSERT(i < num_list_values);
+      curr_value= column_list ? (void*)&list_col_array[num_column_values * i] :
+                                (void*)&list_array[i];
+      if (likely(first || compare_func(curr_value, prev_value)))
       {
         prev_value= curr_value;
         first= FALSE;
@@ -816,7 +983,7 @@ bool partition_info::check_list_constant
         my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
         goto end;
       }
-    } while (++i < no_list_values);
+    } while (++i < num_list_values);
   }
   result= FALSE;
 end:
@@ -829,10 +996,11 @@ end:
 
   SYNOPSIS
     check_partition_info()
+    thd                 Thread object
+    eng_type            Return value for used engine in partitions
     file                A reference to a handler of the table
     info                Create info
-    engine_type         Return value for used engine in partitions
-    check_partition_function Should we check the partition function
+    add_or_reorg_part   Is it ALTER TABLE ADD/REORGANIZE command
 
   RETURN VALUE
     TRUE                 Error, something went wrong
@@ -848,7 +1016,7 @@ end:
 
 bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
                                           handler *file, HA_CREATE_INFO *info,
-                                          bool check_partition_function)
+                                          bool add_or_reorg_part)
 {
   handlerton *table_engine= default_engine_type;
   uint i, tot_partitions;
@@ -859,11 +1027,11 @@ bool partition_info::check_partition_inf
 
   DBUG_PRINT("info", ("default table_engine = %s",
                       ha_resolve_storage_engine_name(table_engine)));
-  if (check_partition_function)
+  if (!add_or_reorg_part)
   {
     int err= 0;
 
-    if (part_type != HASH_PARTITION || !list_of_part_fields)
+    if (!list_of_part_fields)
     {
       DBUG_ASSERT(part_expr);
       err= part_expr->walk(&Item::check_partition_func_processor, 0,
@@ -877,9 +1045,12 @@ bool partition_info::check_partition_inf
       my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
       goto end;
     }
+    if (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
+        fix_parser_data(thd))
+      goto end;
   }
   if (unlikely(!is_sub_partitioned() && 
-               !(use_default_subpartitions && use_default_no_subpartitions)))
+               !(use_default_subpartitions && use_default_num_subpartitions)))
   {
     my_error(ER_SUBPARTITION_ERROR, MYF(0));
     goto end;
@@ -937,6 +1108,12 @@ bool partition_info::check_partition_inf
     }
   }
 
+  if (part_field_list.elements > 0 &&
+      (same_name= has_unique_fields()))
+  {
+    my_error(ER_SAME_NAME_PARTITION_FIELD, MYF(0), same_name);
+    goto end;
+  }
   if ((same_name= has_unique_names()))
   {
     my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
@@ -945,8 +1122,8 @@ bool partition_info::check_partition_inf
   i= 0;
   {
     List_iterator<partition_element> part_it(partitions);
-    uint no_parts_not_set= 0;
-    uint prev_no_subparts_not_set= no_subparts + 1;
+    uint num_parts_not_set= 0;
+    uint prev_num_subparts_not_set= num_subparts + 1;
     do
     {
       partition_element *part_elem= part_it++;
@@ -971,7 +1148,7 @@ bool partition_info::check_partition_inf
       {
         if (part_elem->engine_type == NULL)
         {
-          no_parts_not_set++;
+          num_parts_not_set++;
           part_elem->engine_type= default_engine_type;
         }
         if (check_table_name(part_elem->partition_name,
@@ -986,7 +1163,7 @@ bool partition_info::check_partition_inf
       else
       {
         uint j= 0;
-        uint no_subparts_not_set= 0;
+        uint num_subparts_not_set= 0;
         List_iterator<partition_element> sub_it(part_elem->subpartitions);
         partition_element *sub_elem;
         do
@@ -1005,46 +1182,47 @@ bool partition_info::check_partition_inf
             else
             {
               sub_elem->engine_type= default_engine_type;
-              no_subparts_not_set++;
+              num_subparts_not_set++;
             }
           }
           if (!sub_elem->tablespace_name)
             sub_elem->tablespace_name= part_elem->tablespace_name;
           DBUG_PRINT("info", ("part = %d sub = %d engine = %s", i, j,
                      ha_resolve_storage_engine_name(sub_elem->engine_type)));
-        } while (++j < no_subparts);
+        } while (++j < num_subparts);
 
-        if (prev_no_subparts_not_set == (no_subparts + 1) &&
-            (no_subparts_not_set == 0 || no_subparts_not_set == no_subparts))
-          prev_no_subparts_not_set= no_subparts_not_set;
+        if (prev_num_subparts_not_set == (num_subparts + 1) &&
+            (num_subparts_not_set == 0 ||
+             num_subparts_not_set == num_subparts))
+          prev_num_subparts_not_set= num_subparts_not_set;
 
         if (!table_engine_set &&
-            prev_no_subparts_not_set != no_subparts_not_set)
+            prev_num_subparts_not_set != num_subparts_not_set)
         {
-          DBUG_PRINT("info", ("no_subparts_not_set = %u no_subparts = %u",
-                     no_subparts_not_set, no_subparts));
+          DBUG_PRINT("info", ("num_subparts_not_set = %u num_subparts = %u",
+                     num_subparts_not_set, num_subparts));
           my_error(ER_MIX_HANDLER_ERROR, MYF(0));
           goto end;
         }
 
         if (part_elem->engine_type == NULL)
         {
-          if (no_subparts_not_set == 0)
+          if (num_subparts_not_set == 0)
             part_elem->engine_type= sub_elem->engine_type;
           else
           {
-            no_parts_not_set++;
+            num_parts_not_set++;
             part_elem->engine_type= default_engine_type;
           }
         }
       }
-    } while (++i < no_parts);
+    } while (++i < num_parts);
     if (!table_engine_set &&
-        no_parts_not_set != 0 &&
-        no_parts_not_set != no_parts)
+        num_parts_not_set != 0 &&
+        num_parts_not_set != num_parts)
     {
-      DBUG_PRINT("info", ("no_parts_not_set = %u no_parts = %u",
-                 no_parts_not_set, no_subparts));
+      DBUG_PRINT("info", ("num_parts_not_set = %u num_parts = %u",
+                 num_parts_not_set, num_subparts));
       my_error(ER_MIX_HANDLER_ERROR, MYF(0));
       goto end;
     }
@@ -1067,10 +1245,12 @@ bool partition_info::check_partition_inf
     list constants.
   */
 
-  if (fixed)
+  if (add_or_reorg_part)
   {
-    if (unlikely((part_type == RANGE_PARTITION && check_range_constants()) ||
-                  (part_type == LIST_PARTITION && check_list_constants())))
+    if (unlikely((part_type == RANGE_PARTITION &&
+                  check_range_constants(thd)) ||
+                 (part_type == LIST_PARTITION &&
+                  check_list_constants(thd))))
       goto end;
   }
   result= FALSE;
@@ -1101,20 +1281,101 @@ void partition_info::print_no_partition_
 
   if (check_single_table_access(current_thd,
                                 SELECT_ACL, &table_list, TRUE))
+  {
     my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE,
                ER(ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), MYF(0));
+  }
   else
   {
-    my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
-    if (part_expr->null_value)
-      buf_ptr= (char*)"NULL";
+    if (column_list)
+      buf_ptr= (char*)"from column_list";
     else
-      longlong2str(err_value, buf,
-                   part_expr->unsigned_flag ? 10 : -10);
+    {
+      my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+      if (part_expr->null_value)
+        buf_ptr= (char*)"NULL";
+      else
+        longlong2str(err_value, buf,
+                     part_expr->unsigned_flag ? 10 : -10);
+      dbug_tmp_restore_column_map(table->read_set, old_map);
+    }
     my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr);
-    dbug_tmp_restore_column_map(table->read_set, old_map);
   }
 }
+
+
+/*
+  Set fields related to partition expression
+  SYNOPSIS
+    set_part_expr()
+    start_token               Start of partition function string
+    item_ptr                  Pointer to item tree
+    end_token                 End of partition function string
+    is_subpart                Subpartition indicator
+  RETURN VALUES
+    TRUE                      Memory allocation error
+    FALSE                     Success
+*/
+
+bool partition_info::set_part_expr(char *start_token, Item *item_ptr,
+                                   char *end_token, bool is_subpart)
+{
+  uint expr_len= end_token - start_token;
+  char *func_string= (char*) sql_memdup(start_token, expr_len);
+
+  if (!func_string)
+  {
+    mem_alloc_error(expr_len);
+    return TRUE;
+  }
+  if (is_subpart)
+  {
+    list_of_subpart_fields= FALSE;
+    subpart_expr= item_ptr;
+    subpart_func_string= func_string;
+    subpart_func_len= expr_len;
+  }
+  else
+  {
+    list_of_part_fields= FALSE;
+    part_expr= item_ptr;
+    part_func_string= func_string;
+    part_func_len= expr_len;
+  }
+  return FALSE;
+}
+
+
+/*
+  Check that partition fields and subpartition fields are not too long
+
+  SYNOPSIS
+    check_partition_field_length()
+
+  RETURN VALUES
+    TRUE                             Total length was too big
+    FALSE                            Length is ok
+*/
+
+bool partition_info::check_partition_field_length()
+{
+  uint store_length= 0;
+  uint i;
+  DBUG_ENTER("partition_info::check_partition_field_length");
+
+  for (i= 0; i < num_part_fields; i++)
+    store_length+= get_partition_field_store_length(part_field_array[i]);
+  if (store_length > MAX_KEY_LENGTH)
+    DBUG_RETURN(TRUE);
+  store_length= 0;
+  for (i= 0; i < num_subpart_fields; i++)
+    store_length+= get_partition_field_store_length(subpart_field_array[i]);
+  if (store_length > MAX_KEY_LENGTH)
+    DBUG_RETURN(TRUE);
+  DBUG_RETURN(FALSE);
+}
+
+
 /*
   Set up buffers and arrays for fields requiring preparation
   SYNOPSIS
@@ -1224,46 +1485,6 @@ bool partition_info::set_up_charset_fiel
     }
     subpart_charset_field_array[i]= NULL;
   }
-  if (tot_fields)
-  {
-    uint k;
-    size= tot_fields*sizeof(char**);
-    if (!(char_ptrs= (uchar**)sql_calloc(size)))
-      goto error;
-    full_part_field_buffers= char_ptrs;
-    if (!(char_ptrs= (uchar**)sql_calloc(size)))
-      goto error;
-    restore_full_part_field_ptrs= char_ptrs;
-    size= (tot_fields + 1) * sizeof(char**);
-    if (!(char_ptrs= (uchar**)sql_calloc(size)))
-      goto error;
-    full_part_charset_field_array= (Field**)char_ptrs;
-    for (i= 0; i < tot_part_fields; i++)
-    {
-      full_part_charset_field_array[i]= part_charset_field_array[i];
-      full_part_field_buffers[i]= part_field_buffers[i];
-    }
-    k= tot_part_fields;
-    for (i= 0; i < tot_subpart_fields; i++)
-    {
-      uint j;
-      bool found= FALSE;
-      field= subpart_charset_field_array[i];
-
-      for (j= 0; j < tot_part_fields; j++)
-      {
-        if (field == part_charset_field_array[i])
-          found= TRUE;
-      }
-      if (!found)
-      {
-        full_part_charset_field_array[k]= subpart_charset_field_array[i];
-        full_part_field_buffers[k]= subpart_field_buffers[i];
-        k++;
-      }
-    }
-    full_part_charset_field_array[k]= NULL;
-  }
   DBUG_RETURN(FALSE);
 error:
   mem_alloc_error(size);
@@ -1324,5 +1545,631 @@ id_err:
   return 1;
 }
 
+/*
+  Create a new column value in current list with maxvalue
+  Called from parser
+
+  SYNOPSIS
+    add_max_value()
+  RETURN

+    TRUE               Error
+    FALSE              Success
+*/
+
+int partition_info::add_max_value()
+{
+  DBUG_ENTER("partition_info::add_max_value");
+
+  part_column_list_val *col_val;
+  if (!(col_val= add_column_value()))
+  {
+    DBUG_RETURN(TRUE);
+  }
+  col_val->max_value= TRUE;
+  DBUG_RETURN(FALSE);
+}
+
+/*
+  Create a new column value in current list
+  Called from parser
 
+  SYNOPSIS
+    add_column_value()
+  RETURN
+    >0                 A part_column_list_val object which have been
+                       inserted into its list
+    0                  Memory allocation failure
+*/
+
+part_column_list_val *partition_info::add_column_value()
+{
+  uint max_val= num_columns ? num_columns : MAX_REF_PARTS;
+  DBUG_ENTER("add_column_value");
+  DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u",
+                        num_columns, curr_list_object, max_val));
+  if (curr_list_object < max_val)
+  {
+    curr_list_val->added_items++;
+    DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]);
+  }
+  if (!num_columns && part_type == LIST_PARTITION)
+  {
+    /*
+      We're trying to add more than MAX_REF_PARTS, this can happen
+      in ALTER TABLE using List partitions where the first partition
+      uses VALUES IN (1,2,3...,17) where the number of fields in
+      the list is more than MAX_REF_PARTS, in this case we know
+      that the number of columns must be 1 and we thus reorganize
+      into the structure used for 1 column. After this we call
+      ourselves recursively which should always succeed.
+    */
+    if (!reorganize_into_single_field_col_val())
+    {
+      DBUG_RETURN(add_column_value());
+    }
+    DBUG_RETURN(NULL);
+  }
+  if (column_list)
+  {
+    my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
+  }
+  else
+  {
+    if (part_type == RANGE_PARTITION)
+      my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "RANGE");
+    else
+      my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "LIST");
+  }
+  DBUG_RETURN(NULL);
+}
+
+
+/*
+  Initialise part_elem_value object at setting of a new object
+  (Helper functions to functions called by parser)
+
+  SYNOPSIS
+    init_col_val
+    col_val                  Column value object to be initialised
+    item                     Item object representing column value
+
+  RETURN VALUES
+    TRUE                     Failure
+    FALSE                    Success
+*/
+void partition_info::init_col_val(part_column_list_val *col_val, Item *item)
+{
+  DBUG_ENTER("partition_info::init_col_val");
+
+  col_val->item_expression= item;
+  col_val->null_value= item->null_value;
+  if (item->result_type() == INT_RESULT)
+  {
+    /*
+      This could be both column_list partitioning and function
+      partitioning, but it doesn't hurt to set the function
+      partitioning flags about unsignedness.
+    */
+    curr_list_val->value= item->val_int();
+    curr_list_val->unsigned_flag= TRUE;
+    if (!item->unsigned_flag &&
+        curr_list_val->value < 0)
+      curr_list_val->unsigned_flag= FALSE;
+    if (!curr_list_val->unsigned_flag)
+      curr_part_elem->signed_flag= TRUE;
+  }
+  col_val->part_info= NULL;
+  DBUG_VOID_RETURN;
+}
+/*
+  Add a column value in VALUES LESS THAN or VALUES IN
+  (Called from parser)
+
+  SYNOPSIS
+    add_column_list_value()
+    lex                      Parser's lex object
+    thd                      Thread object
+    item                     Item object representing column value
+
+  RETURN VALUES
+    TRUE                     Failure
+    FALSE                    Success
+*/
+bool partition_info::add_column_list_value(THD *thd, Item *item)
+{
+  part_column_list_val *col_val;
+  Name_resolution_context *context= &thd->lex->current_select->context;
+  TABLE_LIST *save_list= context->table_list;
+  const char *save_where= thd->where;
+  DBUG_ENTER("partition_info::add_column_list_value");
+
+  if (part_type == LIST_PARTITION &&
+      num_columns == 1U)
+  {
+    if (init_column_part())
+    {
+      DBUG_RETURN(TRUE);
+    }
+  }
+
+  context->table_list= 0;
+  if (column_list)
+    thd->where= "field list";
+  else
+    thd->where= "partition function";
+
+  if (item->walk(&Item::check_partition_func_processor, 0,
+                 NULL))
+  {
+    my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+    DBUG_RETURN(TRUE);
+  }
+  if (item->fix_fields(thd, (Item**)0) ||
+      ((context->table_list= save_list), FALSE) ||
+      (!item->const_item()))
+  {
+    context->table_list= save_list;
+    thd->where= save_where;
+    my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+    DBUG_RETURN(TRUE);
+  }
+  thd->where= save_where;
+
+  if (!(col_val= add_column_value()))
+  {
+    DBUG_RETURN(TRUE);
+  }
+  init_col_val(col_val, item);
+  DBUG_RETURN(FALSE);
+}
+
+/*
+  Initialise part_info object for receiving a set of column values
+  for a partition, called when parser reaches VALUES LESS THAN or
+  VALUES IN.
+
+  SYNOPSIS
+    init_column_part()
+    lex                    Parser's lex object
+
+  RETURN VALUES
+    TRUE                     Failure
+    FALSE                    Success
+*/
+bool partition_info::init_column_part()
+{
+  partition_element *p_elem= curr_part_elem;
+  part_column_list_val *col_val_array;
+  part_elem_value *list_val;
+  uint loc_num_columns;
+  DBUG_ENTER("partition_info::init_column_part");
+
+  if (!(list_val=
+      (part_elem_value*)sql_calloc(sizeof(part_elem_value))) ||
+       p_elem->list_val_list.push_back(list_val))
+  {
+    mem_alloc_error(sizeof(part_elem_value));
+    DBUG_RETURN(TRUE);
+  }
+  if (num_columns)
+    loc_num_columns= num_columns;
+  else
+    loc_num_columns= MAX_REF_PARTS;
+  if (!(col_val_array=
+        (part_column_list_val*)sql_calloc(loc_num_columns *
+         sizeof(part_column_list_val))))
+  {
+    mem_alloc_error(loc_num_columns * sizeof(part_elem_value));
+    DBUG_RETURN(TRUE);
+  }
+  list_val->col_val_array= col_val_array;
+  list_val->added_items= 0;
+  curr_list_val= list_val;
+  curr_list_object= 0;
+  DBUG_RETURN(FALSE);
+}
+
+/*
+  In the case of ALTER TABLE ADD/REORGANIZE PARTITION for LIST
+  partitions we can specify list values as:
+  VALUES IN (v1, v2,,,, v17) if we're using the first partitioning
+  variant with a function or a column list partitioned table with
+  one partition field. In this case the parser knows not the
+  number of columns start with and allocates MAX_REF_PARTS in the
+  array. If we try to allocate something beyond MAX_REF_PARTS we
+  will call this function to reorganize into a structure with
+  num_columns = 1. Also when the parser knows that we used LIST
+  partitioning and we used a VALUES IN like above where number of
+  values was smaller than MAX_REF_PARTS or equal, then we will
+  reorganize after discovering this in the parser.
+
+  SYNOPSIS
+    reorganize_into_single_field_col_val()
+
+  RETURN VALUES
+    TRUE                     Failure
+    FALSE                    Success
+*/
+int partition_info::reorganize_into_single_field_col_val()
+{
+  part_column_list_val *col_val, *new_col_val;
+  part_elem_value *val= curr_list_val;
+  uint loc_num_columns= num_columns;
+  uint i;
+  DBUG_ENTER("partition_info::reorganize_into_single_field_col_val");
+
+  num_columns= 1;
+  val->added_items= 1U;
+  col_val= &val->col_val_array[0];
+  init_col_val(col_val, col_val->item_expression);
+  for (i= 1; i < loc_num_columns; i++)
+  {
+    col_val= &val->col_val_array[i];
+    DBUG_ASSERT(part_type == LIST_PARTITION);
+    if (init_column_part())
+    {
+      DBUG_RETURN(TRUE);
+    }
+    if (!(new_col_val= add_column_value()))
+    {
+      DBUG_RETURN(TRUE);
+    }
+    memcpy(new_col_val, col_val, sizeof(*col_val));
+    init_col_val(new_col_val, col_val->item_expression);
+  }
+  curr_list_val= val;
+  DBUG_RETURN(FALSE);
+}
+
+/*
+  This function handles the case of function-based partitioning.
+  It fixes some data structures created in the parser and puts
+  them in the format required by the rest of the partitioning
+  code.
+
+  SYNOPSIS
+  fix_func_partition()
+  thd                             Thread object
+  col_val                         Array of one value
+  part_elem                       The partition instance
+  part_id                         Id of partition instance
+
+  RETURN VALUES
+    TRUE                     Failure
+    FALSE                    Success
+*/
+int partition_info::fix_func_partition(THD *thd,
+                                       part_elem_value *val,
+                                       partition_element *part_elem,
+                                       uint part_id)
+{
+  part_column_list_val *col_val= val->col_val_array;
+  DBUG_ENTER("partition_info::fix_func_partition");
+
+  if (col_val->fixed)
+  {
+    DBUG_RETURN(FALSE);
+  }
+  if (val->added_items != 1)
+  {
+    my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
+    DBUG_RETURN(TRUE);
+  }
+  if (col_val->max_value)
+  {
+    /* The parser ensures we're not LIST partitioned here */
+    DBUG_ASSERT(part_type == RANGE_PARTITION);
+    if (defined_max_value)
+    {
+      my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
+      DBUG_RETURN(TRUE);
+    }
+    if (part_id == (num_parts - 1))
+    {
+      defined_max_value= TRUE;
+      part_elem->max_value= TRUE;
+      part_elem->range_value= LONGLONG_MAX;
+    }
+    else
+    {
+      my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
+      DBUG_RETURN(TRUE);
+    }
+  }
+  else
+  {
+    Item *item_expr= col_val->item_expression;
+    if ((val->null_value= item_expr->null_value))
+    {
+      if (part_elem->has_null_value)
+      {
+         my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
+         DBUG_RETURN(TRUE);
+      }
+      part_elem->has_null_value= TRUE;
+    }
+    else if (item_expr->result_type() != INT_RESULT)
+    {
+      my_error(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR, MYF(0));
+      DBUG_RETURN(TRUE);
+    }
+    if (part_type == RANGE_PARTITION)
+    {
+      if (part_elem->has_null_value)
+      {
+        my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0));
+        DBUG_RETURN(TRUE);
+      }
+      part_elem->range_value= val->value;
+    }
+  }
+  col_val->fixed= 2;
+  DBUG_RETURN(FALSE);
+}
+
+/*
+  Get column item with a proper character set according to the field
+
+  SYNOPSIS
+    get_column_item()
+    item                     Item object to start with
+    field                    Field for which the item will be compared to
+
+  RETURN VALUES
+    NULL                     Error
+    item                     Returned item
+*/
+
+Item* partition_info::get_column_item(Item *item, Field *field)
+{
+  if (field->result_type() == STRING_RESULT &&
+      item->collation.collation != field->charset())
+  {
+    if (!(item= convert_charset_partition_constant(item,
+                                                   field->charset())))
+    {
+      my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+      return NULL;
+    }
+  }
+  return item;
+}
+
+
+/*
+  Evaluate VALUES functions for column list values
+  SYNOPSIS
+    fix_column_value_functions()
+    thd                              Thread object
+    col_val                          List of column values
+    part_id                          Partition id we are fixing
+
+  RETURN VALUES
+    TRUE                             Error
+    FALSE                            Success
+  DESCRIPTION
+    Fix column VALUES and store in memory array adapted to the data type
+*/
+
+bool partition_info::fix_column_value_functions(THD *thd,
+                                                part_elem_value *val,
+                                                uint part_id)
+{
+  uint num_columns= part_field_list.elements;
+  bool result= FALSE;
+  uint i;
+  part_column_list_val *col_val= val->col_val_array;
+  DBUG_ENTER("partition_info::fix_column_value_functions");
+
+  if (col_val->fixed > 1)
+  {
+    DBUG_RETURN(FALSE);
+  }
+  for (i= 0; i < num_columns; col_val++, i++)
+  {
+    Item *column_item= col_val->item_expression;
+    Field *field= part_field_array[i];
+    col_val->part_info= this;
+    col_val->partition_id= part_id;
+    if (col_val->max_value)
+      col_val->column_value= NULL;
+    else
+    {
+      col_val->column_value= NULL;
+      if (!col_val->null_value)
+      {
+        uchar *val_ptr;
+        uint len= field->pack_length();
+        ulong save_sql_mode;
+        bool save_got_warning;
+
+        if (!(column_item= get_column_item(column_item,
+                                           field)))
+        {
+          result= TRUE;
+          goto end;
+        }
+        save_sql_mode= thd->variables.sql_mode;
+        thd->variables.sql_mode= 0;
+        save_got_warning= thd->got_warning;
+        thd->got_warning= 0;
+        if (column_item->save_in_field(field, TRUE) ||
+            thd->got_warning)
+        {
+          my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
+          result= TRUE;
+          goto end;
+        }
+        thd->got_warning= save_got_warning;
+        thd->variables.sql_mode= save_sql_mode;
+        if (!(val_ptr= (uchar*) sql_calloc(len)))
+        {
+          mem_alloc_error(len);
+          result= TRUE;
+          goto end;
+        }
+        col_val->column_value= val_ptr;
+        memcpy(val_ptr, field->ptr, len);
+      }
+    }
+    col_val->fixed= 2;
+  }
+end:
+  DBUG_RETURN(result);
+}
+
+/*
+  The parser generates generic data structures, we need to set them up
+  as the rest of the code expects to find them. This is in reality part
+  of the syntax check of the parser code.
+
+  It is necessary to call this function in the case of a CREATE TABLE
+  statement, in this case we do it early in the check_partition_info
+  function.
+
+  It is necessary to call this function for ALTER TABLE where we
+  assign a completely new partition structure, in this case we do it
+  in prep_alter_part_table after discovering that the partition
+  structure is entirely redefined.
+
+  It's necessary to call this method also for ALTER TABLE ADD/REORGANIZE
+  of partitions, in this we call it in prep_alter_part_table after
+  making some initial checks but before going deep to check the partition
+  info, we also assign the column_list variable before calling this function
+  here.
+
+  Finally we also call it immediately after returning from parsing the
+  partitioning text found in the frm file.
+
+  This function mainly fixes the VALUES parts, these are handled differently
+  whether or not we use column list partitioning. Since the parser doesn't
+  know which we are using we need to set-up the old data structures after
+  the parser is complete when we know if what type of partitioning the
+  base table is using.
+
+  For column lists we will handle this in the fix_column_value_function.
+  For column lists it is sufficient to verify that the number of columns
+  and number of elements are in synch with each other. So only partitioning
+  using functions need to be set-up to their data structures.
+
+  SYNOPSIS
+    fix_parser_data()
+    thd                      Thread object
+
+  RETURN VALUES
+    TRUE                     Failure
+    FALSE                    Success
+*/
+
+int partition_info::fix_parser_data(THD *thd)
+{
+  List_iterator<partition_element> it(partitions);
+  partition_element *part_elem;
+  uint num_elements;
+  uint i= 0, j, k;
+  DBUG_ENTER("partition_info::fix_parser_data");
+
+  if (!(part_type == RANGE_PARTITION ||
+        part_type == LIST_PARTITION))
+  {
+    /* Nothing to do for HASH/KEY partitioning */
+    DBUG_RETURN(FALSE);
+  }
+  do
+  {
+    part_elem= it++;
+    List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
+    j= 0;
+    num_elements= part_elem->list_val_list.elements;
+    DBUG_ASSERT(part_type == RANGE_PARTITION ?
+                num_elements == 1U : TRUE);
+    do
+    {
+      part_elem_value *val= list_val_it++;
+      if (column_list)
+      {
+        if (val->added_items != num_columns)
+        {
+          my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
+          DBUG_RETURN(TRUE);
+        }
+        for (k= 0; k < num_columns; k++)
+        {
+          part_column_list_val *col_val= &val->col_val_array[k];
+          if (col_val->null_value && part_type == RANGE_PARTITION)
+          {
+            my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0));
+            DBUG_RETURN(TRUE);
+          }
+        }
+      }
+      else
+      {
+        if (fix_func_partition(thd, val, part_elem, i))
+        {
+          DBUG_RETURN(TRUE);
+        }
+        if (val->null_value)
+        {
+          /*
+            Null values aren't required in the value part, they are kept per
+            partition instance, only LIST partitions have NULL values.
+          */
+          list_val_it.remove();
+        }
+      }
+    } while (++j < num_elements);
+  } while (++i < num_parts);
+  DBUG_RETURN(FALSE);
+}
+
+void partition_info::print_debug(const char *str, uint *value)
+{
+  DBUG_ENTER("print_debug");
+  if (value)
+    DBUG_PRINT("info", ("parser: %s, val = %u", str, *value));
+  else
+    DBUG_PRINT("info", ("parser: %s", str));
+  DBUG_VOID_RETURN;
+}
+#else /* WITH_PARTITION_STORAGE_ENGINE */
+ /*
+   For builds without partitioning we need to define these functions
+   since we they are called from the parser. The parser cannot
+   remove code parts using ifdef, but the code parts cannot be called
+   so we simply need to add empty functions to make the linker happy.
+ */
+part_column_list_val *partition_info::add_column_value()
+{
+  return NULL;
+}
+
+bool partition_info::set_part_expr(char *start_token, Item *item_ptr,
+                                   char *end_token, bool is_subpart)
+{
+  (void)start_token;
+  (void)item_ptr;
+  (void)end_token;
+  (void)is_subpart;
+  return FALSE;
+}
+
+int partition_info::reorganize_into_single_field_col_val()
+{
+  return 0;
+}
+
+bool partition_info::init_column_part()
+{
+  return FALSE;
+}
+
+bool partition_info::add_column_list_value(Item *item)
+{
+  return FALSE;
+}
+int partition_info::add_max_value()
+{
+  return 0;
+}
 #endif /* WITH_PARTITION_STORAGE_ENGINE */

=== modified file 'sql/partition_info.h'
--- a/sql/partition_info.h	2009-10-26 14:02:26 +0000
+++ b/sql/partition_info.h	2009-10-30 16:34:50 +0000
@@ -1,7 +1,7 @@
 #ifndef PARTITION_INFO_INCLUDED
 #define PARTITION_INFO_INCLUDED
 
-/* Copyright 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -67,10 +67,9 @@ public:
   /*
     When we have various string fields we might need some preparation
     before and clean-up after calling the get_part_id_func's. We need
-    one such method for get_partition_id and one for
-    get_part_partition_id and one for get_subpartition_id.
+    one such method for get_part_partition_id and one for
+    get_subpartition_id.
   */
-  get_part_id_func get_partition_id_charset;
   get_part_id_func get_part_partition_id_charset;
   get_subpart_id_func get_subpartition_id_charset;
 
@@ -84,7 +83,6 @@ public:
     without duplicates, NULL-terminated.
   */
   Field **full_part_field_array;
-  Field **full_part_charset_field_array;
   /*
     Set of all fields used in partition and subpartition expression.
     Required for testing of partition fields in write_set when
@@ -100,10 +98,8 @@ public:
   */
   uchar **part_field_buffers;
   uchar **subpart_field_buffers;
-  uchar **full_part_field_buffers;
   uchar **restore_part_field_ptrs;
   uchar **restore_subpart_field_ptrs;
-  uchar **restore_full_part_field_ptrs;
 
   Item *part_expr;
   Item *subpart_expr;
@@ -127,6 +123,8 @@ public:
   union {
     longlong *range_int_array;
     LIST_PART_ENTRY *list_array;
+    part_column_list_val *range_col_array;
+    part_column_list_val *list_col_array;
   };
   
   /********************************************
@@ -157,6 +155,9 @@ public:
 
   partition_element *curr_part_elem;
   partition_element *current_partition;
+  part_elem_value *curr_list_val;
+  uint curr_list_object;
+  uint num_columns;
 
   TABLE *table;
   /*
@@ -177,17 +178,17 @@ public:
   uint part_func_len;
   uint subpart_func_len;
 
-  uint no_parts;
-  uint no_subparts;
+  uint num_parts;
+  uint num_subparts;
   uint count_curr_subparts;
 
   uint part_error_code;
 
-  uint no_list_values;
+  uint num_list_values;
 
-  uint no_part_fields;
-  uint no_subpart_fields;
-  uint no_full_part_fields;
+  uint num_part_fields;
+  uint num_subpart_fields;
+  uint num_full_part_fields;
 
   uint has_null_part_id;
   /*
@@ -198,9 +199,9 @@ public:
   uint16 linear_hash_mask;
 
   bool use_default_partitions;
-  bool use_default_no_partitions;
+  bool use_default_num_partitions;
   bool use_default_subpartitions;
-  bool use_default_no_subpartitions;
+  bool use_default_num_subpartitions;
   bool default_partitions_setup;
   bool defined_max_value;
   bool list_of_part_fields;
@@ -210,7 +211,7 @@ public:
   bool is_auto_partitioned;
   bool from_openfrm;
   bool has_null_value;
-
+  bool column_list;
 
   partition_info()
   : get_partition_id(NULL), get_part_partition_id(NULL),
@@ -219,11 +220,8 @@ public:
     part_charset_field_array(NULL),
     subpart_charset_field_array(NULL),
     full_part_field_array(NULL),
-    full_part_charset_field_array(NULL),
     part_field_buffers(NULL), subpart_field_buffers(NULL),
-    full_part_field_buffers(NULL),
     restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL),
-    restore_full_part_field_ptrs(NULL),
     part_expr(NULL), subpart_expr(NULL), item_free_list(NULL),
     first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL),
     list_array(NULL), err_value(0),
@@ -231,22 +229,23 @@ public:
     part_func_string(NULL), subpart_func_string(NULL),
     part_state(NULL),
     curr_part_elem(NULL), current_partition(NULL),
+    curr_list_object(0), num_columns(0),
     default_engine_type(NULL),
     part_result_type(INT_RESULT),
     part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION),
     part_info_len(0), part_state_len(0),
     part_func_len(0), subpart_func_len(0),
-    no_parts(0), no_subparts(0),
+    num_parts(0), num_subparts(0),
     count_curr_subparts(0), part_error_code(0),
-    no_list_values(0), no_part_fields(0), no_subpart_fields(0),
-    no_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0),
-    use_default_partitions(TRUE), use_default_no_partitions(TRUE),
-    use_default_subpartitions(TRUE), use_default_no_subpartitions(TRUE),
+    num_list_values(0), num_part_fields(0), num_subpart_fields(0),
+    num_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0),
+    use_default_partitions(TRUE), use_default_num_partitions(TRUE),
+    use_default_subpartitions(TRUE), use_default_num_subpartitions(TRUE),
     default_partitions_setup(FALSE), defined_max_value(FALSE),
     list_of_part_fields(FALSE), list_of_subpart_fields(FALSE),
     linear_hash_ind(FALSE), fixed(FALSE),
     is_auto_partitioned(FALSE), from_openfrm(FALSE),
-    has_null_value(FALSE)
+    has_null_value(FALSE), column_list(FALSE)
   {
     all_fields_in_PF.clear_all();
     all_fields_in_PPF.clear_all();
@@ -269,27 +268,47 @@ public:
   /* Returns the total number of partitions on the leaf level */
   uint get_tot_partitions()
   {
-    return no_parts * (is_sub_partitioned() ? no_subparts : 1);
+    return num_parts * (is_sub_partitioned() ? num_subparts : 1);
   }
 
   bool set_up_defaults_for_partitioning(handler *file, HA_CREATE_INFO *info,
                                         uint start_no);
+  char *has_unique_fields();
   char *has_unique_names();
   bool check_engine_mix(handlerton *engine_type, bool default_engine);
-  bool check_range_constants();
-  bool check_list_constants();
+  bool check_range_constants(THD *thd);
+  bool check_list_constants(THD *thd);
   bool check_partition_info(THD *thd, handlerton **eng_type,
                             handler *file, HA_CREATE_INFO *info,
                             bool check_partition_function);
   void print_no_partition_found(TABLE *table);
+  void print_debug(const char *str, uint*);
+  Item* get_column_item(Item *item, Field *field);
+  int fix_func_partition(THD *thd,
+                         part_elem_value *val,
+                         partition_element *part_elem,
+                         uint part_id);
+  bool fix_column_value_functions(THD *thd,
+                                  part_elem_value *val,
+                                  uint part_id);
+  int fix_parser_data(THD *thd);
+  int add_max_value();
+  void init_col_val(part_column_list_val *col_val, Item *item);
+  int reorganize_into_single_field_col_val();
+  part_column_list_val *add_column_value();
+  bool set_part_expr(char *start_token, Item *item_ptr,
+                     char *end_token, bool is_subpart);
+  static int compare_column_values(const void *a, const void *b);
   bool set_up_charset_field_preps();
+  bool check_partition_field_length();
+  bool init_column_part();
+  bool add_column_list_value(THD *thd, Item *item);
 private:
   static int list_part_cmp(const void* a, const void* b);
-  static int list_part_cmp_unsigned(const void* a, const void* b);
   bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info,
                                  uint start_no);
   bool set_up_default_subpartitions(handler *file, HA_CREATE_INFO *info);
-  char *create_default_partition_names(uint part_no, uint no_parts,
+  char *create_default_partition_names(uint part_no, uint num_parts,
                                        uint start_no);
   char *create_subpartition_name(uint subpart_no, const char *part_name);
   bool has_unique_name(partition_element *element);
@@ -315,7 +334,7 @@ void init_all_partitions_iterator(partit
                                   PARTITION_ITERATOR *part_iter)
 {
   part_iter->part_nums.start= part_iter->part_nums.cur= 0;
-  part_iter->part_nums.end= part_info->no_parts;
+  part_iter->part_nums.end= part_info->num_parts;
   part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
   part_iter->get_next= get_next_partition_id_range;
 }

=== modified file 'sql/replication.h'
--- a/sql/replication.h	2009-05-14 08:56:34 +0000
+++ b/sql/replication.h	2009-11-05 08:44:22 +0000
@@ -16,6 +16,8 @@
 #ifndef REPLICATION_H
 #define REPLICATION_H
 
+typedef struct st_mysql MYSQL;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -487,6 +489,64 @@ const char* thd_enter_cond(MYSQL_THD thd
 */
 void thd_exit_cond(MYSQL_THD thd, const char *old_msg);
 
+/**
+   Get the value of user variable as an integer.
+
+   This function will return the value of variable @a name as an
+   integer. If the original value of the variable is not an integer,
+   the value will be converted into an integer.
+
+   @param name     user variable name
+   @param value    pointer to return the value
+   @param null_value if not NULL, the function will set it to true if
+   the value of variable is null, set to false if not
+
+   @retval 0 Success
+   @retval 1 Variable not found
+*/
+int get_user_var_int(const char *name,
+                     long long int *value, int *null_value);
+
+/**
+   Get the value of user variable as a double precision float number.
+
+   This function will return the value of variable @a name as real
+   number. If the original value of the variable is not a real number,
+   the value will be converted into a real number.
+
+   @param name     user variable name
+   @param value    pointer to return the value
+   @param null_value if not NULL, the function will set it to true if
+   the value of variable is null, set to false if not
+
+   @retval 0 Success
+   @retval 1 Variable not found
+*/
+int get_user_var_real(const char *name,
+                      double *value, int *null_value);
+
+/**
+   Get the value of user variable as a string.
+
+   This function will return the value of variable @a name as
+   string. If the original value of the variable is not a string,
+   the value will be converted into a string.
+
+   @param name     user variable name
+   @param value    pointer to the value buffer
+   @param len      length of the value buffer
+   @param precision precision of the value if it is a float number
+   @param null_value if not NULL, the function will set it to true if
+   the value of variable is null, set to false if not
+
+   @retval 0 Success
+   @retval 1 Variable not found
+*/
+int get_user_var_str(const char *name,
+                     char *value, unsigned long len,
+                     unsigned int precision, int *null_value);
+
+  
 
 #ifdef __cplusplus
 }

=== modified file 'sql/share/errmsg-utf8.txt'
--- a/sql/share/errmsg-utf8.txt	2009-10-12 09:08:34 +0000
+++ b/sql/share/errmsg-utf8.txt	2009-10-30 16:34:50 +0000
@@ -6562,3 +6562,21 @@ ER_BACKUP_ACCESS_OBJS_INCOMPLETE
   eng "Insufficient privileges. You do not have privileges to backup database '%s'."
 ER_WARN_I_S_SKIPPED_TABLE
   eng "Table '%s'.'%s' was skipped since its definition is being modified by concurrent DDL statement."
+ER_SAME_NAME_PARTITION_FIELD
+  eng "Duplicate partition field name '%-.192s'"
+ER_PARTITION_COLUMN_LIST_ERROR
+  eng "Inconsistency in usage of column lists for partitioning"
+ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+  eng "Partition column values of incorrect type"
+ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR
+  eng "Too many fields in '%-.192s'"
+ER_MAXVALUE_IN_VALUES_IN
+  eng "Cannot use MAXVALUE as value in VALUES IN"
+ER_TOO_MANY_VALUES_ERROR
+  eng "Cannot have more than one value for this type of %-.64s partitioning"
+ER_ROW_SINGLE_PARTITION_FIELD_ERROR
+  eng "Row expressions in VALUES IN only allowed for multi-field column partitioning"
+ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD
+  eng "Field '%-.192s' is of a not allowed type for this type of partitioning"
+ER_PARTITION_FIELDS_TOO_LONG
+  eng "The total length of the partitioning fields is too large"

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2009-10-26 14:02:26 +0000
+++ b/sql/share/errmsg.txt	2009-10-30 16:34:50 +0000
@@ -6562,3 +6562,21 @@ ER_BACKUP_ACCESS_OBJS_INCOMPLETE
   eng "Insufficient privileges. You do not have privileges to backup database '%s'."
 ER_WARN_I_S_SKIPPED_TABLE
   eng "Table '%s'.'%s' was skipped since its definition is being modified by concurrent DDL statement."
+ER_SAME_NAME_PARTITION_FIELD
+  eng "Duplicate partition field name '%-.192s'"
+ER_PARTITION_COLUMN_LIST_ERROR
+  eng "Inconsistency in usage of column lists for partitioning"
+ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+  eng "Partition column values of incorrect type"
+ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR
+  eng "Too many fields in '%-.192s'"
+ER_MAXVALUE_IN_VALUES_IN
+  eng "Cannot use MAXVALUE as value in VALUES IN"
+ER_TOO_MANY_VALUES_ERROR
+  eng "Cannot have more than one value for this type of %-.64s partitioning"
+ER_ROW_SINGLE_PARTITION_FIELD_ERROR
+  eng "Row expressions in VALUES IN only allowed for multi-field column partitioning"
+ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD
+  eng "Field '%-.192s' is of a not allowed type for this type of partitioning"
+ER_PARTITION_FIELDS_TOO_LONG
+  eng "The total length of the partitioning fields is too large"

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2009-11-02 15:16:58 +0000
+++ b/sql/slave.cc	2009-11-05 12:13:00 +0000
@@ -685,7 +685,7 @@ terminate_slave_thread(THD *thd,
       EINVAL: invalid signal number (can't happen)
       ESRCH: thread already killed (can happen, should be ignored)
     */
-    IF_DBUG(int err= ) pthread_kill(thd->real_id, thr_client_alarm);
+    int err __attribute__((unused))= pthread_kill(thd->real_id, thr_client_alarm);
     DBUG_ASSERT(err != EINVAL);
 #endif
     thd->awake(THD::NOT_KILLED);

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2009-11-03 09:42:49 +0000
+++ b/sql/sql_class.h	2009-11-06 16:34:09 +0000
@@ -27,7 +27,6 @@
 #include "log.h"
 #include "rpl_tblmap.h"
 #include "mdl.h"
-// #include "replication.h"
 
 #include <waiting_threads.h>
 

=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc	2009-11-02 15:11:43 +0000
+++ b/sql/sql_lex.cc	2009-11-04 09:02:10 +0000
@@ -1573,7 +1573,7 @@ Alter_info::Alter_info(const Alter_info 
   keys_onoff(rhs.keys_onoff),
   tablespace_op(rhs.tablespace_op),
   partition_names(rhs.partition_names, mem_root),
-  no_parts(rhs.no_parts),
+  num_parts(rhs.num_parts),
   build_method(rhs.build_method),
   datetime_field(rhs.datetime_field),
   error_if_not_empty(rhs.error_if_not_empty)

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2009-11-02 15:16:58 +0000
+++ b/sql/sql_lex.h	2009-11-04 09:02:10 +0000
@@ -848,7 +848,7 @@ public:
   enum enum_enable_or_disable   keys_onoff;
   enum tablespace_op_type       tablespace_op;
   List<char>                    partition_names;
-  uint                          no_parts;
+  uint                          num_parts;
   enum ha_build_method          build_method;
   Create_field                 *datetime_field;
   bool                          error_if_not_empty;
@@ -858,7 +858,7 @@ public:
     flags(0),
     keys_onoff(LEAVE_AS_IS),
     tablespace_op(NO_TABLESPACE_OP),
-    no_parts(0),
+    num_parts(0),
     build_method(HA_BUILD_DEFAULT),
     datetime_field(NULL),
     error_if_not_empty(FALSE)
@@ -873,7 +873,7 @@ public:
     flags= 0;
     keys_onoff= LEAVE_AS_IS;
     tablespace_op= NO_TABLESPACE_OP;
-    no_parts= 0;
+    num_parts= 0;
     partition_names.empty();
     build_method= HA_BUILD_DEFAULT;
     datetime_field= 0;

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2009-10-26 14:02:26 +0000
+++ b/sql/sql_partition.cc	2009-11-04 09:02:10 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -18,16 +18,29 @@
   to partitioning introduced in MySQL version 5.1. It contains functionality
   used by all handlers that support partitioning, such as
   the partitioning handler itself and the NDB handler.
+  (Much of the code in this file has been split into partition_info.cc and
+   the header files partition_info.h + partition_element.h + sql_partition.h)
 
-  The first version was written by Mikael Ronstrom.
+  The first version was written by Mikael Ronstrom 2004-2006.
+  Various parts of the optimizer code was written by Sergey Petrunia.
+  Code have been maintained by Mattias Jonsson.
+  The second version was written by Mikael Ronstrom 2006-2007 with some
+  final fixes for partition pruning in 2008-2009 with assistance from Sergey
+  Petrunia and Mattias Jonsson.
 
-  This version supports RANGE partitioning, LIST partitioning, HASH
+  The first version supports RANGE partitioning, LIST partitioning, HASH
   partitioning and composite partitioning (hereafter called subpartitioning)
   where each RANGE/LIST partitioning is HASH partitioned. The hash function
   can either be supplied by the user or by only a list of fields (also
   called KEY partitioning), where the MySQL server will use an internal
   hash function.
   There are quite a few defaults that can be used as well.
+
+  The second version introduces a new variant of RANGE and LIST partitioning
+  which is often referred to as column lists in the code variables. This
+  enables a user to specify a set of columns and their concatenated value
+  as the partition value. By comparing the concatenation of these values
+  the proper partition can be choosen.
 */
 
 /* Some general useful functions */
@@ -55,9 +68,11 @@ const LEX_STRING partition_keywords[]=
   { C_STRING_WITH_LEN("LIST") }, 
   { C_STRING_WITH_LEN("KEY") },
   { C_STRING_WITH_LEN("MAXVALUE") },
-  { C_STRING_WITH_LEN("LINEAR ") }
+  { C_STRING_WITH_LEN("LINEAR ") },
+  { C_STRING_WITH_LEN(" COLUMNS") }
 };
 static const char *part_str= "PARTITION";
+static const char *subpart_str= "SUBPARTITION";
 static const char *sub_str= "SUB";
 static const char *by_str= "BY";
 static const char *space_str= " ";
@@ -66,26 +81,23 @@ static const char *end_paren_str= ")";
 static const char *begin_paren_str= "(";
 static const char *comma_str= ",";
 
-static int get_part_id_charset_func_all(partition_info *part_info,
-                                        uint32 *part_id,
-                                        longlong *func_value);
-static int get_part_id_charset_func_part(partition_info *part_info,
-                                         uint32 *part_id,
-                                         longlong *func_value);
-static int get_part_id_charset_func_subpart(partition_info *part_info,
-                                            uint32 *part_id,
-                                            longlong *func_value);
-static int get_part_part_id_charset_func(partition_info *part_info,
-                                         uint32 *part_id,
-                                         longlong *func_value);
-static int get_subpart_id_charset_func(partition_info *part_info,
-                                       uint32 *part_id);
+int get_partition_id_list_col(partition_info *part_info,
+                              uint32 *part_id,
+                              longlong *func_value);
 int get_partition_id_list(partition_info *part_info,
                           uint32 *part_id,
                           longlong *func_value);
+int get_partition_id_range_col(partition_info *part_info,
+                               uint32 *part_id,
+                               longlong *func_value);
 int get_partition_id_range(partition_info *part_info,
                            uint32 *part_id,
                            longlong *func_value);
+static int get_part_id_charset_func_part(partition_info *part_info,
+                                         uint32 *part_id,
+                                         longlong *func_value);
+static int get_part_id_charset_func_subpart(partition_info *part_info,
+                                            uint32 *part_id);
 int get_partition_id_hash_nosub(partition_info *part_info,
                                 uint32 *part_id,
                                 longlong *func_value);
@@ -98,30 +110,9 @@ int get_partition_id_linear_hash_nosub(p
 int get_partition_id_linear_key_nosub(partition_info *part_info,
                                       uint32 *part_id,
                                       longlong *func_value);
-int get_partition_id_range_sub_hash(partition_info *part_info,
-                                    uint32 *part_id,
-                                    longlong *func_value);
-int get_partition_id_range_sub_key(partition_info *part_info,
-                                   uint32 *part_id,
-                                   longlong *func_value);
-int get_partition_id_range_sub_linear_hash(partition_info *part_info,
-                                           uint32 *part_id,
-                                           longlong *func_value);
-int get_partition_id_range_sub_linear_key(partition_info *part_info,
-                                          uint32 *part_id,
-                                          longlong *func_value);
-int get_partition_id_list_sub_hash(partition_info *part_info,
-                                   uint32 *part_id,
-                                   longlong *func_value);
-int get_partition_id_list_sub_key(partition_info *part_info,
-                                  uint32 *part_id,
-                                  longlong *func_value);
-int get_partition_id_list_sub_linear_hash(partition_info *part_info,
-                                          uint32 *part_id,
-                                          longlong *func_value);
-int get_partition_id_list_sub_linear_key(partition_info *part_info,
-                                         uint32 *part_id,
-                                         longlong *func_value);
+int get_partition_id_with_sub(partition_info *part_info,
+                              uint32 *part_id,
+                              longlong *func_value);
 int get_partition_id_hash_sub(partition_info *part_info,
                               uint32 *part_id); 
 int get_partition_id_key_sub(partition_info *part_info,
@@ -139,17 +130,64 @@ uint32 get_next_partition_id_range(PARTI
 uint32 get_next_partition_id_list(PARTITION_ITERATOR* part_iter);
 int get_part_iter_for_interval_via_mapping(partition_info *part_info,
                                            bool is_subpart,
+                                           uint32 *store_length_array,
                                            uchar *min_value, uchar *max_value,
+                                           uint min_len, uint max_len,
                                            uint flags,
                                            PARTITION_ITERATOR *part_iter);
+int get_part_iter_for_interval_cols_via_map(partition_info *part_info,
+                                            bool is_subpart,
+                                            uint32 *store_length_array,
+                                            uchar *min_value, uchar *max_value,
+                                            uint min_len, uint max_len,
+                                            uint flags,
+                                            PARTITION_ITERATOR *part_iter);
 int get_part_iter_for_interval_via_walking(partition_info *part_info,
                                            bool is_subpart,
+                                           uint32 *store_length_array,
                                            uchar *min_value, uchar *max_value,
+                                           uint min_len, uint max_len,
                                            uint flags,
                                            PARTITION_ITERATOR *part_iter);
+static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec);
+static int cmp_rec_and_tuple_prune(part_column_list_val *val,
+                                   uint32 n_vals_in_rec,
+                                   bool tail_is_min);
 
 #ifdef WITH_PARTITION_STORAGE_ENGINE
 /*
+  Convert constants in VALUES definition to the character set the
+  corresponding field uses.
+
+  SYNOPSIS
+    convert_charset_partition_constant()
+    item                                Item to convert
+    cs                                  Character set to convert to
+
+  RETURN VALUE
+    NULL                                Error
+    item                                New converted item
+*/
+
+Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs)
+{
+  THD *thd= current_thd;
+  Name_resolution_context *context= &thd->lex->current_select->context;
+  TABLE_LIST *save_list= context->table_list;
+  const char *save_where= thd->where;
+
+  item= item->safe_charset_converter(cs);
+  context->table_list= NULL;
+  thd->where= "convert character set partition constant";
+  if (!item || item->fix_fields(thd, (Item**)NULL))
+    item= NULL;
+  thd->where= save_where;
+  context->table_list= save_list;
+  return item;
+}
+
+
+/*
   A support function to check if a name is in a list of strings
 
   SYNOPSIS
@@ -166,7 +204,7 @@ bool is_name_in_list(char *name,
                           List<char> list_names)
 {
   List_iterator<char> names_it(list_names);
-  uint no_names= list_names.elements;
+  uint num_names= list_names.elements;
   uint i= 0;
 
   do
@@ -174,7 +212,7 @@ bool is_name_in_list(char *name,
     char *list_name= names_it++;
     if (!(my_strcasecmp(system_charset_info, name, list_name)))
       return TRUE;
-  } while (++i < no_names);
+  } while (++i < num_names);
   return FALSE;
 }
 
@@ -201,26 +239,26 @@ bool partition_default_handling(TABLE *t
 {
   DBUG_ENTER("partition_default_handling");
 
-  if (part_info->use_default_no_partitions)
+  if (part_info->use_default_num_partitions)
   {
     if (!is_create_table_ind &&
-        table->file->get_no_parts(normalized_path, &part_info->no_parts))
+        table->file->get_no_parts(normalized_path, &part_info->num_parts))
     {
       DBUG_RETURN(TRUE);
     }
   }
   else if (part_info->is_sub_partitioned() &&
-           part_info->use_default_no_subpartitions)
+           part_info->use_default_num_subpartitions)
   {
-    uint no_parts;
+    uint num_parts;
     if (!is_create_table_ind &&
-        (table->file->get_no_parts(normalized_path, &no_parts)))
+        (table->file->get_no_parts(normalized_path, &num_parts)))
     {
       DBUG_RETURN(TRUE);
     }
-    DBUG_ASSERT(part_info->no_parts > 0);
-    part_info->no_subparts= no_parts / part_info->no_parts;
-    DBUG_ASSERT((no_parts % part_info->no_parts) == 0);
+    DBUG_ASSERT(part_info->num_parts > 0);
+    part_info->num_subparts= num_parts / part_info->num_parts;
+    DBUG_ASSERT((num_parts % part_info->num_parts) == 0);
   }
   part_info->set_up_defaults_for_partitioning(table->file,
                                               (ulonglong)0, (uint)0);
@@ -253,8 +291,8 @@ bool check_reorganise_list(partition_inf
                            List<char> list_part_names)
 {
   uint new_count, old_count;
-  uint no_new_parts= new_part_info->partitions.elements;
-  uint no_old_parts= old_part_info->partitions.elements;
+  uint num_new_parts= new_part_info->partitions.elements;
+  uint num_old_parts= old_part_info->partitions.elements;
   List_iterator<partition_element> new_parts_it(new_part_info->partitions);
   bool same_part_info= (new_part_info == old_part_info);
   DBUG_ENTER("check_reorganise_list");
@@ -277,8 +315,8 @@ bool check_reorganise_list(partition_inf
         if (!is_name_in_list(old_name, list_part_names))
           DBUG_RETURN(TRUE);
       }
-    } while (old_count < no_old_parts);
-  } while (new_count < no_new_parts);
+    } while (old_count < num_old_parts);
+  } while (new_count < num_new_parts);
   DBUG_RETURN(FALSE);
 }
 
@@ -453,9 +491,10 @@ static bool set_up_field_array(TABLE *ta
                               bool is_sub_part)
 {
   Field **ptr, *field, **field_array;
-  uint no_fields= 0;
+  uint num_fields= 0;
   uint size_field_array;
   uint i= 0;
+  uint inx;
   partition_info *part_info= table->part_info;
   int result= FALSE;
   DBUG_ENTER("set_up_field_array");
@@ -464,9 +503,19 @@ static bool set_up_field_array(TABLE *ta
   while ((field= *(ptr++))) 
   {
     if (field->flags & GET_FIXED_FIELDS_FLAG)
-      no_fields++;
+      num_fields++;
   }
-  if (no_fields == 0)
+  if (num_fields > MAX_REF_PARTS)
+  {
+    char *ptr;
+    if (is_sub_part)
+      ptr= (char*)"subpartition function";
+    else
+      ptr= (char*)"partition function";
+    my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), ptr);
+    DBUG_RETURN(TRUE);
+  }
+  if (num_fields == 0)
   {
     /*
       We are using hidden key as partitioning field
@@ -474,8 +523,8 @@ static bool set_up_field_array(TABLE *ta
     DBUG_ASSERT(!is_sub_part);
     DBUG_RETURN(result);
   }
-  size_field_array= (no_fields+1)*sizeof(Field*);
-  field_array= (Field**)sql_alloc(size_field_array);
+  size_field_array= (num_fields+1)*sizeof(Field*);
+  field_array= (Field**)sql_calloc(size_field_array);
   if (unlikely(!field_array))
   {
     mem_alloc_error(size_field_array);
@@ -490,7 +539,32 @@ static bool set_up_field_array(TABLE *ta
       field->flags|= FIELD_IN_PART_FUNC_FLAG;
       if (likely(!result))
       {
-        field_array[i++]= field;
+        if (!is_sub_part && part_info->column_list)
+        {
+          List_iterator<char> it(part_info->part_field_list);
+          char *field_name;
+
+          DBUG_ASSERT(num_fields == part_info->part_field_list.elements);
+          inx= 0;
+          do
+          {
+            field_name= it++;
+            if (!my_strcasecmp(system_charset_info,
+                               field_name,
+                               field->field_name))
+              break;
+          } while (++inx < num_fields);
+          if (inx == num_fields)
+          {
+            mem_alloc_error(1);
+            result= TRUE;
+            continue;
+          }
+        }
+        else
+          inx= i;
+        field_array[inx]= field;
+        i++;
 
         /*
           We check that the fields are proper. It is required for each
@@ -508,16 +582,16 @@ static bool set_up_field_array(TABLE *ta
       }
     }
   }
-  field_array[no_fields]= 0;
+  field_array[num_fields]= 0;
   if (!is_sub_part)
   {
     part_info->part_field_array= field_array;
-    part_info->no_part_fields= no_fields;
+    part_info->num_part_fields= num_fields;
   }
   else
   {
     part_info->subpart_field_array= field_array;
-    part_info->no_subpart_fields= no_fields;
+    part_info->num_subpart_fields= num_fields;
   }
   DBUG_RETURN(result);
 }
@@ -556,36 +630,36 @@ static bool create_full_part_field_array
   if (!part_info->is_sub_partitioned())
   {
     part_info->full_part_field_array= part_info->part_field_array;
-    part_info->no_full_part_fields= part_info->no_part_fields;
+    part_info->num_full_part_fields= part_info->num_part_fields;
   }
   else
   {
     Field *field, **field_array;
-    uint no_part_fields=0, size_field_array;
+    uint num_part_fields=0, size_field_array;
     ptr= table->field;
     while ((field= *(ptr++)))
     {
       if (field->flags & FIELD_IN_PART_FUNC_FLAG)
-        no_part_fields++;
+        num_part_fields++;
     }
-    size_field_array= (no_part_fields+1)*sizeof(Field*);
-    field_array= (Field**)sql_alloc(size_field_array);
+    size_field_array= (num_part_fields+1)*sizeof(Field*);
+    field_array= (Field**)sql_calloc(size_field_array);
     if (unlikely(!field_array))
     {
       mem_alloc_error(size_field_array);
       result= TRUE;
       goto end;
     }
-    no_part_fields= 0;
+    num_part_fields= 0;
     ptr= table->field;
     while ((field= *(ptr++)))
     {
       if (field->flags & FIELD_IN_PART_FUNC_FLAG)
-        field_array[no_part_fields++]= field;
+        field_array[num_part_fields++]= field;
     }
-    field_array[no_part_fields]=0;
+    field_array[num_part_fields]=0;
     part_info->full_part_field_array= field_array;
-    part_info->no_full_part_fields= no_part_fields;
+    part_info->num_full_part_fields= num_part_fields;
   }
 
   /*
@@ -781,16 +855,16 @@ static bool handle_list_of_fields(List_i
       goto end;
     }
   }
-  if (is_list_empty)
+  if (is_list_empty && part_info->part_type == HASH_PARTITION)
   {
     uint primary_key= table->s->primary_key;
     if (primary_key != MAX_KEY)
     {
-      uint no_key_parts= table->key_info[primary_key].key_parts, i;
+      uint num_key_parts= table->key_info[primary_key].key_parts, i;
       /*
         In the case of an empty list we use primary key as partition key.
       */
-      for (i= 0; i < no_key_parts; i++)
+      for (i= 0; i < num_key_parts; i++)
       {
         Field *field= table->key_info[primary_key].key_part[i].field;
         field->flags|= GET_FIXED_FIELDS_FLAG;
@@ -854,7 +928,7 @@ int check_signed_flag(partition_info *pa
         error= ER_PARTITION_CONST_DOMAIN_ERROR;
         break;
       }
-    } while (++i < part_info->no_parts);
+    } while (++i < part_info->num_parts);
   }
   return error;
 }
@@ -952,7 +1026,6 @@ end_lex_with_single_table(THD *thd, TABL
     table                The table object
     part_info            Reference to partitioning data structure
     is_sub_part          Is the table subpartitioned as well
-    is_field_to_be_setup Flag if we are to set-up field arrays
 
   RETURN VALUE
     TRUE                 An error occurred, something was wrong with the
@@ -975,8 +1048,8 @@ end_lex_with_single_table(THD *thd, TABL
     on the field object.
 */
 
-bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
-                          bool is_sub_part, bool is_field_to_be_setup)
+static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
+                                 bool is_sub_part)
 {
   partition_info *part_info= table->part_info;
   bool result= TRUE;
@@ -1021,8 +1094,7 @@ bool fix_fields_part_func(THD *thd, Item
   if (unlikely(error))
   {
     DBUG_PRINT("info", ("Field in partition function not part of table"));
-    if (is_field_to_be_setup)
-      clear_field_flag(table);
+    clear_field_flag(table);
     goto end;
   }
   if (unlikely(func_expr->const_item()))
@@ -1033,11 +1105,7 @@ bool fix_fields_part_func(THD *thd, Item
   }
   if ((!is_sub_part) && (error= check_signed_flag(part_info)))
     goto end;
-  result= FALSE;
-  if (is_field_to_be_setup)
-    result= set_up_field_array(table, is_sub_part);
-  if (!is_sub_part)
-    part_info->fixed= TRUE;
+  result= set_up_field_array(table, is_sub_part);
 end:
   end_lex_with_single_table(thd, table, old_lex);
 #if !defined(DBUG_OFF)
@@ -1219,9 +1287,9 @@ void check_range_capable_PF(TABLE *table
 static bool set_up_partition_bitmap(THD *thd, partition_info *part_info)
 {
   uint32 *bitmap_buf;
-  uint bitmap_bits= part_info->no_subparts? 
-                     (part_info->no_subparts* part_info->no_parts):
-                      part_info->no_parts;
+  uint bitmap_bits= part_info->num_subparts? 
+                     (part_info->num_subparts* part_info->num_parts):
+                      part_info->num_parts;
   uint bitmap_bytes= bitmap_buffer_size(bitmap_bits);
   DBUG_ENTER("set_up_partition_bitmap");
 
@@ -1321,64 +1389,47 @@ static void set_up_partition_func_pointe
 
   if (part_info->is_sub_partitioned())
   {
+    part_info->get_partition_id= get_partition_id_with_sub;
     if (part_info->part_type == RANGE_PARTITION)
     {
-      part_info->get_part_partition_id= get_partition_id_range;
+      if (part_info->column_list)
+        part_info->get_part_partition_id= get_partition_id_range_col;
+      else
+        part_info->get_part_partition_id= get_partition_id_range;
       if (part_info->list_of_subpart_fields)
       {
         if (part_info->linear_hash_ind)
-        {
-          part_info->get_partition_id= get_partition_id_range_sub_linear_key;
           part_info->get_subpartition_id= get_partition_id_linear_key_sub;
-        }
         else
-        {
-          part_info->get_partition_id= get_partition_id_range_sub_key;
           part_info->get_subpartition_id= get_partition_id_key_sub;
-        }
       }
       else
       {
         if (part_info->linear_hash_ind)
-        {
-          part_info->get_partition_id= get_partition_id_range_sub_linear_hash;
           part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
-        }
         else
-        {
-          part_info->get_partition_id= get_partition_id_range_sub_hash;
           part_info->get_subpartition_id= get_partition_id_hash_sub;
-        }
       }
     }
     else /* LIST Partitioning */
     {
-      part_info->get_part_partition_id= get_partition_id_list;
+      if (part_info->column_list)
+        part_info->get_part_partition_id= get_partition_id_list_col;
+      else
+        part_info->get_part_partition_id= get_partition_id_list;
       if (part_info->list_of_subpart_fields)
       {
         if (part_info->linear_hash_ind)
-        {
-          part_info->get_partition_id= get_partition_id_list_sub_linear_key;
           part_info->get_subpartition_id= get_partition_id_linear_key_sub;
-        }
         else
-        {
-          part_info->get_partition_id= get_partition_id_list_sub_key;
           part_info->get_subpartition_id= get_partition_id_key_sub;
-        }
       }
       else
       {
         if (part_info->linear_hash_ind)
-        {
-          part_info->get_partition_id= get_partition_id_list_sub_linear_hash;
           part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
-        }
         else
-        {
-          part_info->get_partition_id= get_partition_id_list_sub_hash;
           part_info->get_subpartition_id= get_partition_id_hash_sub;
-        }
       }
     }
   }
@@ -1387,9 +1438,19 @@ static void set_up_partition_func_pointe
     part_info->get_part_partition_id= NULL;
     part_info->get_subpartition_id= NULL;
     if (part_info->part_type == RANGE_PARTITION)
-      part_info->get_partition_id= get_partition_id_range;
+    {
+      if (part_info->column_list)
+        part_info->get_partition_id= get_partition_id_range_col;
+      else
+        part_info->get_partition_id= get_partition_id_range;
+    }
     else if (part_info->part_type == LIST_PARTITION)
-      part_info->get_partition_id= get_partition_id_list;
+    {
+      if (part_info->column_list)
+        part_info->get_partition_id= get_partition_id_list_col;
+      else
+        part_info->get_partition_id= get_partition_id_list;
+    }
     else /* HASH partitioning */
     {
       if (part_info->list_of_part_fields)
@@ -1408,32 +1469,43 @@ static void set_up_partition_func_pointe
       }
     }
   }
-  if (part_info->full_part_charset_field_array)
-  {
-    DBUG_ASSERT(part_info->get_partition_id);
-    part_info->get_partition_id_charset= part_info->get_partition_id;
-    if (part_info->part_charset_field_array &&
-        part_info->subpart_charset_field_array)
-      part_info->get_partition_id= get_part_id_charset_func_all;
-    else if (part_info->part_charset_field_array)
-      part_info->get_partition_id= get_part_id_charset_func_part;
-    else
-      part_info->get_partition_id= get_part_id_charset_func_subpart;
-  }
-  if (part_info->part_charset_field_array &&
-      part_info->is_sub_partitioned())
+  /*
+    We need special functions to handle character sets since they require copy
+    of field pointers and restore afterwards. For subpartitioned tables we do
+    the copy and restore individually on the part and subpart parts. For non-
+    subpartitioned tables we use the same functions as used for the parts part
+    of subpartioning.
+    Thus for subpartitioned tables the get_partition_id is always
+    get_partition_id_with_sub, even when character sets exists.
+  */
+  if (part_info->part_charset_field_array)
   {
-    DBUG_ASSERT(part_info->get_part_partition_id);
-    part_info->get_part_partition_id_charset=
+    if (part_info->is_sub_partitioned())
+    {
+      DBUG_ASSERT(part_info->get_part_partition_id);
+      if (!part_info->column_list)
+      {
+        part_info->get_part_partition_id_charset=
           part_info->get_part_partition_id;
-    part_info->get_part_partition_id= get_part_part_id_charset_func;
+        part_info->get_part_partition_id= get_part_id_charset_func_part;
+      }
+    }
+    else
+    {
+      DBUG_ASSERT(part_info->get_partition_id);
+      if (!part_info->column_list)
+      {
+        part_info->get_part_partition_id_charset= part_info->get_partition_id;
+        part_info->get_part_partition_id= get_part_id_charset_func_part;
+      }
+    }
   }
   if (part_info->subpart_charset_field_array)
   {
     DBUG_ASSERT(part_info->get_subpartition_id);
     part_info->get_subpartition_id_charset=
           part_info->get_subpartition_id;
-    part_info->get_subpartition_id= get_subpart_id_charset_func;
+    part_info->get_subpartition_id= get_part_id_charset_func_subpart;
   }
   DBUG_VOID_RETURN;
 }
@@ -1441,22 +1513,22 @@ static void set_up_partition_func_pointe
 
 /*
   For linear hashing we need a mask which is on the form 2**n - 1 where
-  2**n >= no_parts. Thus if no_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
+  2**n >= num_parts. Thus if num_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
 
   SYNOPSIS
     set_linear_hash_mask()
     part_info            Reference to partitioning data structure
-    no_parts             Number of parts in linear hash partitioning
+    num_parts            Number of parts in linear hash partitioning
 
   RETURN VALUE
     NONE
 */
 
-void set_linear_hash_mask(partition_info *part_info, uint no_parts)
+void set_linear_hash_mask(partition_info *part_info, uint num_parts)
 {
   uint mask;
 
-  for (mask= 1; mask < no_parts; mask<<=1)
+  for (mask= 1; mask < num_parts; mask<<=1)
     ;
   part_info->linear_hash_mask= mask - 1;
 }
@@ -1470,7 +1542,7 @@ void set_linear_hash_mask(partition_info
     get_part_id_from_linear_hash()
     hash_value          Hash value calculated by HASH function or KEY function
     mask                Mask calculated previously by set_linear_hash_mask
-    no_parts            Number of partitions in HASH partitioned part
+    num_parts           Number of partitions in HASH partitioned part
 
   RETURN VALUE
     part_id             The calculated partition identity (starting at 0)
@@ -1483,12 +1555,12 @@ void set_linear_hash_mask(partition_info
 */
 
 static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask,
-                                           uint no_parts)
+                                           uint num_parts)
 {
   uint32 part_id= (uint32)(hash_value & mask);
   DBUG_ENTER("get_part_id_from_linear_hash");
 
-  if (part_id >= no_parts)
+  if (part_id >= num_parts)
   {
     uint new_mask= ((mask + 1) >> 1) - 1;
     part_id= (uint32)(hash_value & new_mask);
@@ -1632,7 +1704,7 @@ bool fix_partition_func(THD *thd, TABLE 
       function is correct.
     */
     if (part_info->linear_hash_ind)
-      set_linear_hash_mask(part_info, part_info->no_subparts);
+      set_linear_hash_mask(part_info, part_info->num_subparts);
     if (part_info->list_of_subpart_fields)
     {
       List_iterator<char> it(part_info->subpart_field_list);
@@ -1642,12 +1714,12 @@ bool fix_partition_func(THD *thd, TABLE 
     else
     {
       if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr,
-                                        table, TRUE, TRUE)))
+                                        table, TRUE)))
         goto end;
       if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT))
       {
-        my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0),
-                 "SUBPARTITION");
+        my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0),
+                 subpart_str);
         goto end;
       }
     }
@@ -1660,7 +1732,7 @@ bool fix_partition_func(THD *thd, TABLE 
   if (part_info->part_type == HASH_PARTITION)
   {
     if (part_info->linear_hash_ind)
-      set_linear_hash_mask(part_info, part_info->no_parts);
+      set_linear_hash_mask(part_info, part_info->num_parts);
     if (part_info->list_of_part_fields)
     {
       List_iterator<char> it(part_info->part_field_list);
@@ -1670,32 +1742,43 @@ bool fix_partition_func(THD *thd, TABLE 
     else
     {
       if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
-                                        table, FALSE, TRUE)))
+                                        table, FALSE)))
         goto end;
       if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
       {
-        my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str);
+        my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0), part_str);
         goto end;
       }
       part_info->part_result_type= INT_RESULT;
     }
+    part_info->fixed= TRUE;
   }
   else
   {
     const char *error_str;
-    if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
-                                      table, FALSE, TRUE)))
-      goto end;
+    if (part_info->column_list)
+    {
+      List_iterator<char> it(part_info->part_field_list);
+      if (unlikely(handle_list_of_fields(it, table, part_info, FALSE)))
+        goto end;
+    }
+    else
+    {
+      if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
+                                        table, FALSE)))
+        goto end;
+    }
+    part_info->fixed= TRUE;
     if (part_info->part_type == RANGE_PARTITION)
     {
       error_str= partition_keywords[PKW_RANGE].str; 
-      if (unlikely(part_info->check_range_constants()))
+      if (unlikely(part_info->check_range_constants(thd)))
         goto end;
     }
     else if (part_info->part_type == LIST_PARTITION)
     {
       error_str= partition_keywords[PKW_LIST].str; 
-      if (unlikely(part_info->check_list_constants()))
+      if (unlikely(part_info->check_list_constants(thd)))
         goto end;
     }
     else
@@ -1704,12 +1787,13 @@ bool fix_partition_func(THD *thd, TABLE 
       my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0));
       goto end;
     }
-    if (unlikely(part_info->no_parts < 1))
+    if (unlikely(part_info->num_parts < 1))
     {
       my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str);
       goto end;
     }
-    if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
+    if (unlikely(!part_info->column_list &&
+                  part_info->part_expr->result_type() != INT_RESULT))
     {
       my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str);
       goto end;
@@ -1717,7 +1801,8 @@ bool fix_partition_func(THD *thd, TABLE 
   }
   if (((part_info->part_type != HASH_PARTITION ||
       part_info->list_of_part_fields == FALSE) &&
-      check_part_func_fields(part_info->part_field_array, TRUE)) ||
+      (!part_info->column_list &&
+       check_part_func_fields(part_info->part_field_array, TRUE))) ||
       (part_info->list_of_subpart_fields == FALSE &&
        part_info->is_sub_partitioned() &&
        check_part_func_fields(part_info->subpart_field_array, TRUE)))
@@ -1740,6 +1825,11 @@ bool fix_partition_func(THD *thd, TABLE 
     my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
     goto end;
   }
+  if (unlikely(part_info->check_partition_field_length()))
+  {
+    my_error(ER_PARTITION_FIELDS_TOO_LONG, MYF(0));
+    goto end;
+  }
   check_range_capable_PF(table);
   set_up_partition_key_maps(table, part_info);
   set_up_partition_func_pointers(part_info);
@@ -1763,9 +1853,9 @@ end:
 
 static int add_write(File fptr, const char *buf, uint len)
 {
-  uint len_written= my_write(fptr, (const uchar*)buf, len, MYF(0));
+  uint ret_code= my_write(fptr, (const uchar*)buf, len, MYF(MY_FNABP));
 
-  if (likely(len == len_written))
+  if (likely(ret_code == 0))
     return 0;
   else
     return 1;
@@ -1814,14 +1904,8 @@ static int add_begin_parenthesis(File fp
 static int add_part_key_word(File fptr, const char *key_string)
 {
   int err= add_string(fptr, key_string);
-
   err+= add_space(fptr);
-  return err + add_begin_parenthesis(fptr);
-}
-
-static int add_hash(File fptr)
-{
-  return add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
+  return err;
 }
 
 static int add_partition(File fptr)
@@ -1852,16 +1936,16 @@ static int add_subpartition_by(File fptr
   return err + add_partition_by(fptr);
 }
 
-static int add_key_partition(File fptr, List<char> field_list)
+static int add_part_field_list(File fptr, List<char> field_list)
 {
-  uint i, no_fields;
-  int err;
+  uint i, num_fields;
+  int err= 0;
 
   List_iterator<char> part_it(field_list);
-  err= add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
-  no_fields= field_list.elements;
+  num_fields= field_list.elements;
   i= 0;
-  while (i < no_fields)
+  err+= add_begin_parenthesis(fptr);
+  while (i < num_fields)
   {
     const char *field_str= part_it++;
     String field_string("", 0, system_charset_info);
@@ -1872,10 +1956,11 @@ static int add_key_partition(File fptr, 
                       strlen(field_str));
     thd->options= save_options;
     err+= add_string_object(fptr, &field_string);
-    if (i != (no_fields-1))
+    if (i != (num_fields-1))
       err+= add_comma(fptr);
     i++;
   }
+  err+= add_end_parenthesis(fptr);
   return err;
 }
 
@@ -1985,37 +2070,269 @@ static int add_partition_options(File fp
   return err + add_engine(fptr,p_elem->engine_type);
 }
 
-static int add_partition_values(File fptr, partition_info *part_info, partition_element *p_elem)
+
+/*
+  Check partition fields for result type and if they need
+  to check the character set.
+
+  SYNOPSIS
+    check_part_field()
+    sql_type              Type provided by user
+    field_name            Name of field, used for error handling
+    result_type           Out value: Result type of field
+    need_cs_check         Out value: Do we need character set check
+
+  RETURN VALUES
+    TRUE                  Error
+    FALSE                 Ok
+*/
+
+static int check_part_field(enum_field_types sql_type,
+                            const char *field_name,
+                            Item_result *result_type,
+                            bool *need_cs_check)
+{
+  if (sql_type >= MYSQL_TYPE_TINY_BLOB &&
+      sql_type <= MYSQL_TYPE_BLOB)
+  {
+    my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
+    return TRUE;
+  }
+  switch (sql_type)
+  {
+    case MYSQL_TYPE_NEWDECIMAL:
+    case MYSQL_TYPE_DECIMAL:
+    case MYSQL_TYPE_TINY:
+    case MYSQL_TYPE_SHORT:
+    case MYSQL_TYPE_LONG:
+    case MYSQL_TYPE_LONGLONG:
+    case MYSQL_TYPE_INT24:
+      *result_type= INT_RESULT;
+      *need_cs_check= FALSE;
+      return FALSE;
+    case MYSQL_TYPE_NEWDATE:
+    case MYSQL_TYPE_DATE:
+    case MYSQL_TYPE_TIME:
+    case MYSQL_TYPE_DATETIME:
+      *result_type= STRING_RESULT;
+      *need_cs_check= TRUE;
+      return FALSE;
+    case MYSQL_TYPE_VARCHAR:
+    case MYSQL_TYPE_STRING:
+    case MYSQL_TYPE_VAR_STRING:
+      *result_type= STRING_RESULT;
+      *need_cs_check= TRUE;
+      return FALSE;
+    case MYSQL_TYPE_TIMESTAMP:
+    case MYSQL_TYPE_NULL:
+    case MYSQL_TYPE_FLOAT:
+    case MYSQL_TYPE_DOUBLE:
+    case MYSQL_TYPE_BIT:
+    case MYSQL_TYPE_ENUM:
+    case MYSQL_TYPE_SET:
+    case MYSQL_TYPE_GEOMETRY:
+      goto error;
+    default:
+      goto error;
+  }
+error:
+  my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
+           field_name);
+  return TRUE;
+}
+
+
+/*
+  Find the given field's Create_field object using name of field
+
+  SYNOPSIS
+    get_sql_field()
+    field_name                   Field name
+    alter_info                   Info from ALTER TABLE/CREATE TABLE
+
+  RETURN VALUE
+    sql_field                    Object filled in by parser about field
+    NULL                         No field found
+*/
+
+static Create_field* get_sql_field(char *field_name,
+                                   Alter_info *alter_info)
+{
+  List_iterator<Create_field> it(alter_info->create_list);
+  Create_field *sql_field;
+  DBUG_ENTER("get_sql_field");
+
+  while ((sql_field= it++))
+  {
+    if (!(my_strcasecmp(system_charset_info,
+                        sql_field->field_name,
+                        field_name)))
+    {
+      DBUG_RETURN(sql_field);
+    }
+  }
+  DBUG_RETURN(NULL);
+}
+
+
+static int add_column_list_values(File fptr, partition_info *part_info,
+                                  part_elem_value *list_value,
+                                  HA_CREATE_INFO *create_info,
+                                  Alter_info *alter_info)
+{
+  int err= 0;
+  uint i;
+  List_iterator<char> it(part_info->part_field_list);
+  uint num_elements= part_info->part_field_list.elements;
+  bool use_parenthesis= (part_info->part_type == LIST_PARTITION &&
+                         part_info->num_columns > 1U);
+
+  if (use_parenthesis)
+    err+= add_begin_parenthesis(fptr);
+  for (i= 0; i < num_elements; i++)
+  {
+    part_column_list_val *col_val= &list_value->col_val_array[i];
+    char *field_name= it++;
+    if (col_val->max_value)
+      err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
+    else if (col_val->null_value)
+      err+= add_string(fptr, "NULL");
+    else
+    {
+      char buffer[MAX_KEY_LENGTH];
+      String str(buffer, sizeof(buffer), &my_charset_bin);
+      Item *item_expr= col_val->item_expression;
+      if (item_expr->null_value)
+        err+= add_string(fptr, "NULL");
+      else
+      {
+        String *res;
+        CHARSET_INFO *field_cs;
+        bool need_cs_check= FALSE;
+        Item_result result_type= STRING_RESULT;
+
+        /*
+          This function is called at a very early stage, even before
+          we have prepared the sql_field objects. Thus we have to
+          find the proper sql_field object and get the character set
+          from that object.
+        */
+        if (create_info)
+        {
+          Create_field *sql_field;
+
+          if (!(sql_field= get_sql_field(field_name,
+                                         alter_info)))
+          {
+            my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
+            return 1;
+          }
+          if (check_part_field(sql_field->sql_type,
+                               sql_field->field_name,
+                               &result_type,
+                               &need_cs_check))
+            return 1;
+          if (need_cs_check)
+            field_cs= get_sql_field_charset(sql_field, create_info);
+          else
+            field_cs= NULL;
+        }
+        else
+        {
+          Field *field= part_info->part_field_array[i];
+          result_type= field->result_type();
+          if (check_part_field(field->real_type(),
+                               field->field_name,
+                               &result_type,
+                               &need_cs_check))
+            return 1;
+          DBUG_ASSERT(result_type == field->result_type());
+          if (need_cs_check)
+            field_cs= field->charset();
+          else
+            field_cs= NULL;
+        }
+        if (result_type != item_expr->result_type())
+        {
+          my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
+          return 1;
+        }
+        if (field_cs && field_cs != item_expr->collation.collation)
+        {
+          if (!(item_expr= convert_charset_partition_constant(item_expr,
+                                                              field_cs)))
+          {
+            my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+            return 1;
+          }
+        }
+        {
+          String val_conv;
+          val_conv.set_charset(system_charset_info);
+          res= item_expr->val_str(&str);
+          if (get_cs_converted_part_value_from_string(current_thd,
+                                                      item_expr, res,
+                                                      &val_conv, field_cs,
+                                                   (bool)(alter_info != NULL)))
+            return 1;
+          err+= add_string_object(fptr, &val_conv);
+        }
+      }
+    }
+    if (i != (num_elements - 1))
+      err+= add_string(fptr, comma_str);
+  }
+  if (use_parenthesis)
+    err+= add_end_parenthesis(fptr);
+  return err;
+}
+
+static int add_partition_values(File fptr, partition_info *part_info,
+                                partition_element *p_elem,
+                                HA_CREATE_INFO *create_info,
+                                Alter_info *alter_info)
 {
   int err= 0;
 
   if (part_info->part_type == RANGE_PARTITION)
   {
     err+= add_string(fptr, " VALUES LESS THAN ");
-    if (!p_elem->max_value)
+    if (part_info->column_list)
     {
+      List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
+      part_elem_value *list_value= list_val_it++;
       err+= add_begin_parenthesis(fptr);
-      if (p_elem->signed_flag)
-        err+= add_int(fptr, p_elem->range_value);
-      else
-        err+= add_uint(fptr, p_elem->range_value);
+      err+= add_column_list_values(fptr, part_info, list_value,
+                                   create_info, alter_info);
       err+= add_end_parenthesis(fptr);
     }
     else
-      err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
+    {
+      if (!p_elem->max_value)
+      {
+        err+= add_begin_parenthesis(fptr);
+        if (p_elem->signed_flag)
+          err+= add_int(fptr, p_elem->range_value);
+        else
+          err+= add_uint(fptr, p_elem->range_value);
+        err+= add_end_parenthesis(fptr);
+      }
+      else
+        err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
+    }
   }
   else if (part_info->part_type == LIST_PARTITION)
   {
     uint i;
     List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
     err+= add_string(fptr, " VALUES IN ");
-    uint no_items= p_elem->list_val_list.elements;
+    uint num_items= p_elem->list_val_list.elements;
 
     err+= add_begin_parenthesis(fptr);
     if (p_elem->has_null_value)
     {
       err+= add_string(fptr, "NULL");
-      if (no_items == 0)
+      if (num_items == 0)
       {
         err+= add_end_parenthesis(fptr);
         goto end;
@@ -2027,13 +2344,19 @@ static int add_partition_values(File fpt
     {
       part_elem_value *list_value= list_val_it++;
 
-      if (!list_value->unsigned_flag)
-        err+= add_int(fptr, list_value->value);
+      if (part_info->column_list)
+        err+= add_column_list_values(fptr, part_info, list_value,
+                                     create_info, alter_info);
       else
-        err+= add_uint(fptr, list_value->value);
-      if (i != (no_items-1))
+      {
+        if (!list_value->unsigned_flag)
+          err+= add_int(fptr, list_value->value);
+        else
+          err+= add_uint(fptr, list_value->value);
+      }
+      if (i != (num_items-1))
         err+= add_comma(fptr);
-    } while (++i < no_items);
+    } while (++i < num_items);
     err+= add_end_parenthesis(fptr);
   }
 end:
@@ -2052,6 +2375,8 @@ end:
     use_sql_alloc              Allocate buffer from sql_alloc if true
                                otherwise use my_malloc
     show_partition_options     Should we display partition options
+    create_info                Info generated by parser
+    alter_info                 Info generated by parser
 
   RETURN VALUES
     NULL error
@@ -2080,9 +2405,11 @@ end:
 char *generate_partition_syntax(partition_info *part_info,
                                 uint *buf_length,
                                 bool use_sql_alloc,
-                                bool show_partition_options)
+                                bool show_partition_options,
+                                HA_CREATE_INFO *create_info,
+                                Alter_info *alter_info)
 {
-  uint i,j, tot_no_parts, no_subparts;
+  uint i,j, tot_num_parts, num_subparts;
   partition_element *part_elem;
   ulonglong buffer_length;
   char path[FN_REFLEN];
@@ -2113,9 +2440,12 @@ char *generate_partition_syntax(partitio
       if (part_info->linear_hash_ind)
         err+= add_string(fptr, partition_keywords[PKW_LINEAR].str);
       if (part_info->list_of_part_fields)
-        err+= add_key_partition(fptr, part_info->part_field_list);
+      {
+        err+= add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
+        err+= add_part_field_list(fptr, part_info->part_field_list);
+      }
       else
-        err+= add_hash(fptr);
+        err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
       break;
     default:
       DBUG_ASSERT(0);
@@ -2124,15 +2454,23 @@ char *generate_partition_syntax(partitio
       DBUG_RETURN(NULL);
   }
   if (part_info->part_expr)
+  {
+    err+= add_begin_parenthesis(fptr);
     err+= add_string_len(fptr, part_info->part_func_string,
                          part_info->part_func_len);
-  err+= add_end_parenthesis(fptr);
-  if ((!part_info->use_default_no_partitions) &&
+    err+= add_end_parenthesis(fptr);
+  }
+  else if (part_info->column_list)
+  {
+    err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str);
+    err+= add_part_field_list(fptr, part_info->part_field_list);
+  }
+  if ((!part_info->use_default_num_partitions) &&
        part_info->use_default_partitions)
   {
     err+= add_string(fptr, "\n");
     err+= add_string(fptr, "PARTITIONS ");
-    err+= add_int(fptr, part_info->no_parts);
+    err+= add_int(fptr, part_info->num_parts);
   }
   if (part_info->is_sub_partitioned())
   {
@@ -2142,23 +2480,29 @@ char *generate_partition_syntax(partitio
     if (part_info->linear_hash_ind)
       err+= add_string(fptr, partition_keywords[PKW_LINEAR].str);
     if (part_info->list_of_subpart_fields)
-      err+= add_key_partition(fptr, part_info->subpart_field_list);
+    {
+      add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
+      add_part_field_list(fptr, part_info->subpart_field_list);
+    }
     else
-      err+= add_hash(fptr);
+      err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
     if (part_info->subpart_expr)
+    {
+      err+= add_begin_parenthesis(fptr);
       err+= add_string_len(fptr, part_info->subpart_func_string,
                            part_info->subpart_func_len);
-    err+= add_end_parenthesis(fptr);
-    if ((!part_info->use_default_no_subpartitions) && 
+      err+= add_end_parenthesis(fptr);
+    }
+    if ((!part_info->use_default_num_subpartitions) && 
           part_info->use_default_subpartitions)
     {
       err+= add_string(fptr, "\n");
       err+= add_string(fptr, "SUBPARTITIONS ");
-      err+= add_int(fptr, part_info->no_subparts);
+      err+= add_int(fptr, part_info->num_subparts);
     }
   }
-  tot_no_parts= part_info->partitions.elements;
-  no_subparts= part_info->no_subparts;
+  tot_num_parts= part_info->partitions.elements;
+  num_subparts= part_info->num_subparts;
 
   if (!part_info->use_default_partitions)
   {
@@ -2181,7 +2525,8 @@ char *generate_partition_syntax(partitio
         first= FALSE;
         err+= add_partition(fptr);
         err+= add_name_string(fptr, part_elem->partition_name);
-        err+= add_partition_values(fptr, part_info, part_elem);
+        err+= add_partition_values(fptr, part_info, part_elem,
+                                   create_info, alter_info);
         if (!part_info->is_sub_partitioned() ||
             part_info->use_default_subpartitions)
         {
@@ -2202,7 +2547,7 @@ char *generate_partition_syntax(partitio
             err+= add_name_string(fptr, part_elem->partition_name);
             if (show_partition_options)
               err+= add_partition_options(fptr, part_elem);
-            if (j != (no_subparts-1))
+            if (j != (num_subparts-1))
             {
               err+= add_comma(fptr);
               err+= add_string(fptr, "\n");
@@ -2211,12 +2556,12 @@ char *generate_partition_syntax(partitio
             }
             else
               err+= add_end_parenthesis(fptr);
-          } while (++j < no_subparts);
+          } while (++j < num_subparts);
         }
       }
-      if (i == (tot_no_parts-1))
+      if (i == (tot_num_parts-1))
         err+= add_end_parenthesis(fptr);
-    } while (++i < tot_no_parts);
+    } while (++i < tot_num_parts);
   }
   if (err)
     goto close_file;
@@ -2336,14 +2681,14 @@ static inline int part_val_int(Item *ite
     get_part_id_for_sub()
     loc_part_id             Local partition id
     sub_part_id             Subpartition id
-    no_subparts             Number of subparts
+    num_subparts            Number of subparts
 */
 
 inline
 static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
-                                  uint no_subparts)
+                                  uint num_subparts)
 {
-  return (uint32)((loc_part_id * no_subparts) + sub_part_id);
+  return (uint32)((loc_part_id * num_subparts) + sub_part_id);
 }
 
 
@@ -2352,7 +2697,7 @@ static uint32 get_part_id_for_sub(uint32
 
   SYNOPSIS
     get_part_id_hash()
-    no_parts                 Number of hash partitions
+    num_parts                Number of hash partitions
     part_expr                Item tree of hash function
     out:part_id              The returned partition id
     out:func_value           Value of hash function
@@ -2362,7 +2707,7 @@ static uint32 get_part_id_for_sub(uint32
     FALSE                         Success
 */
 
-static int get_part_id_hash(uint no_parts,
+static int get_part_id_hash(uint num_parts,
                             Item *part_expr,
                             uint32 *part_id,
                             longlong *func_value)
@@ -2373,7 +2718,7 @@ static int get_part_id_hash(uint no_part
   if (part_val_int(part_expr, func_value))
     DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
 
-  int_hash_id= *func_value % no_parts;
+  int_hash_id= *func_value % num_parts;
 
   *part_id= int_hash_id < 0 ? (uint32) -int_hash_id : (uint32) int_hash_id;
   DBUG_RETURN(FALSE);
@@ -2387,7 +2732,7 @@ static int get_part_id_hash(uint no_part
     get_part_id_linear_hash()
     part_info           A reference to the partition_info struct where all the
                         desired information is given
-    no_parts            Number of hash partitions
+    num_parts           Number of hash partitions
     part_expr           Item tree of hash function
     out:part_id         The returned partition id
     out:func_value      Value of hash function
@@ -2398,7 +2743,7 @@ static int get_part_id_hash(uint no_part
 */
 
 static int get_part_id_linear_hash(partition_info *part_info,
-                                   uint no_parts,
+                                   uint num_parts,
                                    Item *part_expr,
                                    uint32 *part_id,
                                    longlong *func_value)
@@ -2410,7 +2755,7 @@ static int get_part_id_linear_hash(parti
 
   *part_id= get_part_id_from_linear_hash(*func_value,
                                          part_info->linear_hash_mask,
-                                         no_parts);
+                                         num_parts);
   DBUG_RETURN(FALSE);
 }
 
@@ -2422,7 +2767,7 @@ static int get_part_id_linear_hash(parti
     get_part_id_key()
     file                Handle to storage engine
     field_array         Array of fields for PARTTION KEY
-    no_parts            Number of KEY partitions
+    num_parts           Number of KEY partitions
     func_value          Returns hash value calculated
 
   RETURN VALUE
@@ -2432,12 +2777,12 @@ static int get_part_id_linear_hash(parti
 inline
 static uint32 get_part_id_key(handler *file,
                               Field **field_array,
-                              uint no_parts,
+                              uint num_parts,
                               longlong *func_value)
 {
   DBUG_ENTER("get_part_id_key");
   *func_value= file->calculate_key_hash_value(field_array);
-  DBUG_RETURN((uint32) (*func_value % no_parts));
+  DBUG_RETURN((uint32) (*func_value % num_parts));
 }
 
 
@@ -2449,7 +2794,7 @@ static uint32 get_part_id_key(handler *f
     part_info           A reference to the partition_info struct where all the
                         desired information is given
     field_array         Array of fields for PARTTION KEY
-    no_parts            Number of KEY partitions
+    num_parts            Number of KEY partitions
 
   RETURN VALUE
     Calculated partition id
@@ -2458,15 +2803,15 @@ static uint32 get_part_id_key(handler *f
 inline
 static uint32 get_part_id_linear_key(partition_info *part_info,
                                      Field **field_array,
-                                     uint no_parts,
+                                     uint num_parts,
                                      longlong *func_value)
 {
-  DBUG_ENTER("get_partition_id_linear_key");
+  DBUG_ENTER("get_part_id_linear_key");
 
   *func_value= part_info->table->file->calculate_key_hash_value(field_array);
   DBUG_RETURN(get_part_id_from_linear_hash(*func_value,
                                            part_info->linear_hash_mask,
-                                           no_parts));
+                                           num_parts));
 }
 
 /*
@@ -2500,7 +2845,8 @@ static void copy_to_part_field_buffers(F
     if (!field->maybe_null() || !field->is_null())
     {
       CHARSET_INFO *cs= ((Field_str*)field)->charset();
-      uint len= field->pack_length();
+      uint max_len= field->pack_length();
+      uint data_len= field->data_length();
       uchar *field_buf= *field_bufs;
       /*
          We only use the field buffer for VARCHAR and CHAR strings
@@ -2512,17 +2858,17 @@ static void copy_to_part_field_buffers(F
       if (field->type() == MYSQL_TYPE_VARCHAR)
       {
         uint len_bytes= ((Field_varstring*)field)->length_bytes;
-        my_strnxfrm(cs, field_buf + len_bytes, (len - len_bytes),
-                    field->ptr + len_bytes, field->field_length);
+        my_strnxfrm(cs, field_buf + len_bytes, max_len,
+                    field->ptr + len_bytes, data_len);
         if (len_bytes == 1)
-          *field_buf= (uchar) field->field_length;
+          *field_buf= (uchar) data_len;
         else
-          int2store(field_buf, field->field_length);
+          int2store(field_buf, data_len);
       }
       else
       {
-        my_strnxfrm(cs, field_buf, len,
-                    field->ptr, field->field_length);
+        my_strnxfrm(cs, field_buf, max_len,
+                    field->ptr, max_len);
       }
       field->ptr= field_buf;
     }
@@ -2552,6 +2898,44 @@ static void restore_part_field_pointers(
   return;
 }
 
+/*
+  This function is used to calculate the partition id where all partition
+  fields have been prepared to point to a record where the partition field
+  values are bound.
+
+  SYNOPSIS
+    get_partition_id()
+    part_info           A reference to the partition_info struct where all the
+                        desired information is given
+    out:part_id         The partition id is returned through this pointer
+    out:func_value      Value of partition function (longlong)
+
+  RETURN VALUE
+    part_id                     Partition id of partition that would contain
+                                row with given values of PF-fields
+    HA_ERR_NO_PARTITION_FOUND   The fields of the partition function didn't
+                                fit into any partition and thus the values of 
+                                the PF-fields are not allowed.
+
+  DESCRIPTION
+    A routine used from write_row, update_row and delete_row from any
+    handler supporting partitioning. It is also a support routine for
+    get_partition_set used to find the set of partitions needed to scan
+    for a certain index scan or full table scan.
+    
+    It is actually 9 different variants of this function which are called
+    through a function pointer.
+
+    get_partition_id_list
+    get_partition_id_list_col
+    get_partition_id_range
+    get_partition_id_range_col
+    get_partition_id_hash_nosub
+    get_partition_id_key_nosub
+    get_partition_id_linear_hash_nosub
+    get_partition_id_linear_key_nosub
+    get_partition_id_with_sub
+*/
 
 /*
   This function is used to calculate the main partition to use in the case of
@@ -2573,71 +2957,26 @@ static void restore_part_field_pointers(
 
   DESCRIPTION
     
-    It is actually 6 different variants of this function which are called
+    It is actually 8 different variants of this function which are called
     through a function pointer.
 
     get_partition_id_list
+    get_partition_id_list_col
     get_partition_id_range
+    get_partition_id_range_col
     get_partition_id_hash_nosub
     get_partition_id_key_nosub
     get_partition_id_linear_hash_nosub
     get_partition_id_linear_key_nosub
 */
 
-static int get_part_id_charset_func_subpart(partition_info *part_info,
-                                            uint32 *part_id,
-                                            longlong *func_value)
-{
-  int res;
-  DBUG_ENTER("get_part_id_charset_func_subpart");
-  copy_to_part_field_buffers(part_info->subpart_charset_field_array,
-                             part_info->subpart_field_buffers,
-                             part_info->restore_subpart_field_ptrs);
-  res= part_info->get_partition_id_charset(part_info, part_id, func_value);
-  restore_part_field_pointers(part_info->subpart_charset_field_array,
-                              part_info->restore_subpart_field_ptrs);
-  DBUG_RETURN(res);
-}
-
-
 static int get_part_id_charset_func_part(partition_info *part_info,
                                          uint32 *part_id,
                                          longlong *func_value)
 {
   int res;
   DBUG_ENTER("get_part_id_charset_func_part");
-  copy_to_part_field_buffers(part_info->part_charset_field_array,
-                             part_info->part_field_buffers,
-                             part_info->restore_part_field_ptrs);
-  res= part_info->get_partition_id_charset(part_info, part_id, func_value);
-  restore_part_field_pointers(part_info->part_charset_field_array,
-                              part_info->restore_part_field_ptrs);
-  DBUG_RETURN(res);
-}
-
 
-static int get_part_id_charset_func_all(partition_info *part_info,
-                                        uint32 *part_id,
-                                        longlong *func_value)
-{
-  int res;
-  DBUG_ENTER("get_part_id_charset_func_all");
-  copy_to_part_field_buffers(part_info->full_part_field_array,
-                             part_info->full_part_field_buffers,
-                             part_info->restore_full_part_field_ptrs);
-  res= part_info->get_partition_id_charset(part_info, part_id, func_value);
-  restore_part_field_pointers(part_info->full_part_field_array,
-                              part_info->restore_full_part_field_ptrs);
-  DBUG_RETURN(res);
-}
-
-
-static int get_part_part_id_charset_func(partition_info *part_info,
-                                         uint32 *part_id,
-                                         longlong *func_value)
-{
-  int res;
-  DBUG_ENTER("get_part_part_id_charset_func");
   copy_to_part_field_buffers(part_info->part_charset_field_array,
                              part_info->part_field_buffers,
                              part_info->restore_part_field_ptrs);
@@ -2649,11 +2988,12 @@ static int get_part_part_id_charset_func
 }
 
 
-static int get_subpart_id_charset_func(partition_info *part_info,
-                                       uint32 *part_id)
+static int get_part_id_charset_func_subpart(partition_info *part_info,
+                                            uint32 *part_id)
 {
   int res;
-  DBUG_ENTER("get_subpart_id_charset_func");
+  DBUG_ENTER("get_part_id_charset_func_subpart");
+
   copy_to_part_field_buffers(part_info->subpart_charset_field_array,
                              part_info->subpart_field_buffers,
                              part_info->restore_subpart_field_ptrs);
@@ -2663,6 +3003,41 @@ static int get_subpart_id_charset_func(p
   DBUG_RETURN(res);
 }
 
+int get_partition_id_list_col(partition_info *part_info,
+                              uint32 *part_id,
+                              longlong *func_value)
+{
+  part_column_list_val *list_col_array= part_info->list_col_array;
+  uint num_columns= part_info->part_field_list.elements;
+  int list_index, cmp;
+  int min_list_index= 0;
+  int max_list_index= part_info->num_list_values - 1;
+  DBUG_ENTER("get_partition_id_list_col");
+
+  while (max_list_index >= min_list_index)
+  {
+    list_index= (max_list_index + min_list_index) >> 1;
+    cmp= cmp_rec_and_tuple(list_col_array + list_index*num_columns,
+                          num_columns);
+    if (cmp > 0)
+      min_list_index= list_index + 1;
+    else if (cmp < 0)
+    {
+      if (!list_index)
+        goto notfound;
+      max_list_index= list_index - 1;
+    }
+    else
+    {
+      *part_id= (uint32)list_col_array[list_index].partition_id;
+      DBUG_RETURN(0);
+    }
+  }
+notfound:
+  *part_id= 0;
+  DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
+}
+
 
 int get_partition_id_list(partition_info *part_info,
                           uint32 *part_id,
@@ -2671,7 +3046,7 @@ int get_partition_id_list(partition_info
   LIST_PART_ENTRY *list_array= part_info->list_array;
   int list_index;
   int min_list_index= 0;
-  int max_list_index= part_info->no_list_values - 1;
+  int max_list_index= part_info->num_list_values - 1;
   longlong part_func_value;
   int error= part_val_int(part_info->part_expr, &part_func_value);
   longlong list_value;
@@ -2741,7 +3116,7 @@ notfound:
        index idx.
        The function returns first number idx, such that 
        list_array[idx].list_value is NOT contained within the passed interval.
-       If all array elements are contained, part_info->no_list_values is
+       If all array elements are contained, part_info->num_list_values is
        returned.
 
   NOTE
@@ -2755,6 +3130,44 @@ notfound:
     The edge of corresponding sub-array of part_info->list_array
 */
 
+uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
+                                               bool left_endpoint,
+                                               bool include_endpoint,
+                                               uint32 nparts)
+{
+  part_column_list_val *list_col_array= part_info->list_col_array;
+  uint num_columns= part_info->part_field_list.elements;
+  int list_index, cmp;
+  uint min_list_index= 0;
+  uint max_list_index= part_info->num_list_values - 1;
+  bool tailf= !(left_endpoint ^ include_endpoint);
+  DBUG_ENTER("get_partition_id_cols_list_for_endpoint");
+
+  do
+  {
+    list_index= (max_list_index + min_list_index) >> 1;
+    cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns,
+                                 nparts, tailf);
+    if (cmp > 0)
+      min_list_index= list_index + 1;
+    else if (cmp < 0)
+    {
+      if (!list_index)
+        goto notfound;
+      max_list_index= list_index - 1;
+    }
+    else 
+    {
+      DBUG_RETURN(list_index + test(!tailf));
+    }
+  } while (max_list_index >= min_list_index);
+  if (cmp > 0)
+    list_index++;
+notfound:
+  DBUG_RETURN(list_index);
+}
+
+
 uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info,
                                                bool left_endpoint,
                                                bool include_endpoint)
@@ -2777,7 +3190,7 @@ uint32 get_list_array_idx_for_endpoint(p
 {
   LIST_PART_ENTRY *list_array= part_info->list_array;
   uint list_index;
-  uint min_list_index= 0, max_list_index= part_info->no_list_values - 1;
+  uint min_list_index= 0, max_list_index= part_info->num_list_values - 1;
   longlong list_value;
   /* Get the partitioning function value for the endpoint */
   longlong part_func_value= 
@@ -2807,7 +3220,7 @@ uint32 get_list_array_idx_for_endpoint(p
 
   if (unsigned_flag)
     part_func_value-= 0x8000000000000000ULL;
-  DBUG_ASSERT(part_info->no_list_values);
+  DBUG_ASSERT(part_info->num_list_values);
   do
   {
     list_index= (max_list_index + min_list_index) >> 1;
@@ -2832,12 +3245,49 @@ notfound:
 }
 
 
+int get_partition_id_range_col(partition_info *part_info,
+                               uint32 *part_id,
+                               longlong *func_value)
+{
+  part_column_list_val *range_col_array= part_info->range_col_array;
+  uint num_columns= part_info->part_field_list.elements;
+  uint max_partition= part_info->num_parts - 1;
+  uint min_part_id= 0;
+  uint max_part_id= max_partition;
+  uint loc_part_id;
+  DBUG_ENTER("get_partition_id_range_col");
+
+  while (max_part_id > min_part_id)
+  {
+    loc_part_id= (max_part_id + min_part_id + 1) >> 1;
+    if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
+                          num_columns) >= 0)
+      min_part_id= loc_part_id + 1;
+    else
+      max_part_id= loc_part_id - 1;
+  }
+  loc_part_id= max_part_id;
+  if (loc_part_id != max_partition)
+    if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
+                          num_columns) >= 0)
+      loc_part_id++;
+  *part_id= (uint32)loc_part_id;
+  if (loc_part_id == max_partition &&
+      (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
+                         num_columns) >= 0))
+    DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
+
+  DBUG_PRINT("exit",("partition: %d", *part_id));
+  DBUG_RETURN(0);
+}
+
+
 int get_partition_id_range(partition_info *part_info,
                            uint32 *part_id,
                            longlong *func_value)
 {
   longlong *range_array= part_info->range_int_array;
-  uint max_partition= part_info->no_parts - 1;
+  uint max_partition= part_info->num_parts - 1;
   uint min_part_id= 0;
   uint max_part_id= max_partition;
   uint loc_part_id;
@@ -2914,7 +3364,7 @@ int get_partition_id_range(partition_inf
        represented by range_int_array[idx] has EMPTY intersection with the
        passed interval.
        If the interval represented by the last array element has non-empty 
-       intersection with the passed interval, part_info->no_parts is
+       intersection with the passed interval, part_info->num_parts is
        returned.
        
   RETURN
@@ -2943,7 +3393,7 @@ uint32 get_partition_id_range_for_endpoi
                                            bool include_endpoint)
 {
   longlong *range_array= part_info->range_int_array;
-  uint max_partition= part_info->no_parts - 1;
+  uint max_partition= part_info->num_parts - 1;
   uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
   /* Get the partitioning function value for the endpoint */
   longlong part_func_value= 
@@ -3003,277 +3453,87 @@ uint32 get_partition_id_range_for_endpoi
       the maximum value is in the current partition.
     */
     if (part_func_value > bound ||
-        (part_func_value == bound &&
-         (!part_info->defined_max_value || loc_part_id < max_partition)))
-      loc_part_id++;
-  }
-  else 
-  {
-    if (loc_part_id < max_partition)
-    {
-      if (part_func_value == range_array[loc_part_id])
-        loc_part_id += test(include_endpoint);
-      else if (part_func_value > range_array[loc_part_id])
-        loc_part_id++;
-    }
-    loc_part_id++;
-  }
-  DBUG_RETURN(loc_part_id);
-}
-
-
-int get_partition_id_hash_nosub(partition_info *part_info,
-                                uint32 *part_id,
-                                longlong *func_value)
-{
-  return get_part_id_hash(part_info->no_parts, part_info->part_expr,
-                          part_id, func_value);
-}
-
-
-int get_partition_id_linear_hash_nosub(partition_info *part_info,
-                                       uint32 *part_id,
-                                       longlong *func_value)
-{
-  return get_part_id_linear_hash(part_info, part_info->no_parts,
-                                 part_info->part_expr, part_id, func_value);
-}
-
-
-int get_partition_id_key_nosub(partition_info *part_info,
-                                uint32 *part_id,
-                                longlong *func_value)
-{
-  *part_id= get_part_id_key(part_info->table->file,
-                            part_info->part_field_array,
-                            part_info->no_parts, func_value);
-  return 0;
-}
-
-
-int get_partition_id_linear_key_nosub(partition_info *part_info,
-                                       uint32 *part_id,
-                                       longlong *func_value)
-{
-  *part_id= get_part_id_linear_key(part_info,
-                                   part_info->part_field_array,
-                                   part_info->no_parts, func_value);
-  return 0;
-}
-
-
-int get_partition_id_range_sub_hash(partition_info *part_info,
-                                     uint32 *part_id,
-                                     longlong *func_value)
-{
-  uint32 loc_part_id, sub_part_id;
-  uint no_subparts;
-  longlong local_func_value;
-  int error;
-  DBUG_ENTER("get_partition_id_range_sub_hash");
-  LINT_INIT(loc_part_id);
-  LINT_INIT(sub_part_id);
-
-  if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
-                                              func_value))))
-  {
-    DBUG_RETURN(error);
-  }
-  no_subparts= part_info->no_subparts;
-  if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
-                                        &sub_part_id, &local_func_value))))
-  {
-    DBUG_RETURN(error);
-  }
-
-  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
-  DBUG_RETURN(0);
-}
-
-
-int get_partition_id_range_sub_linear_hash(partition_info *part_info,
-                                            uint32 *part_id,
-                                            longlong *func_value)
-{
-  uint32 loc_part_id, sub_part_id;
-  uint no_subparts;
-  longlong local_func_value;
-  int error;
-  DBUG_ENTER("get_partition_id_range_sub_linear_hash");
-  LINT_INIT(loc_part_id);
-  LINT_INIT(sub_part_id);
-
-  if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
-                                              func_value))))
-  {
-    DBUG_RETURN(error);
+        (part_func_value == bound &&
+         (!part_info->defined_max_value || loc_part_id < max_partition)))
+      loc_part_id++;
   }
-  no_subparts= part_info->no_subparts;
-  if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
-                                               part_info->subpart_expr,
-                                               &sub_part_id,
-                                               &local_func_value))))
+  else 
   {
-    DBUG_RETURN(error);
+    if (loc_part_id < max_partition)
+    {
+      if (part_func_value == range_array[loc_part_id])
+        loc_part_id += test(include_endpoint);
+      else if (part_func_value > range_array[loc_part_id])
+        loc_part_id++;
+    }
+    loc_part_id++;
   }
-
-  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
-  DBUG_RETURN(0);
+  DBUG_RETURN(loc_part_id);
 }
 
 
-int get_partition_id_range_sub_key(partition_info *part_info,
-                                    uint32 *part_id,
-                                    longlong *func_value)
+int get_partition_id_hash_nosub(partition_info *part_info,
+                                uint32 *part_id,
+                                longlong *func_value)
 {
-  uint32 loc_part_id, sub_part_id;
-  uint no_subparts;
-  longlong local_func_value;
-  int error;
-  DBUG_ENTER("get_partition_id_range_sub_key");
-  LINT_INIT(loc_part_id);
-
-  if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
-                                              func_value))))
-  {
-    DBUG_RETURN(error);
-  }
-  no_subparts= part_info->no_subparts;
-  sub_part_id= get_part_id_key(part_info->table->file,
-                               part_info->subpart_field_array,
-                               no_subparts, &local_func_value);
-  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
-  DBUG_RETURN(0);
+  return get_part_id_hash(part_info->num_parts, part_info->part_expr,
+                          part_id, func_value);
 }
 
 
-int get_partition_id_range_sub_linear_key(partition_info *part_info,
-                                           uint32 *part_id,
-                                           longlong *func_value)
+int get_partition_id_linear_hash_nosub(partition_info *part_info,
+                                       uint32 *part_id,
+                                       longlong *func_value)
 {
-  uint32 loc_part_id, sub_part_id;
-  uint no_subparts;
-  longlong local_func_value;
-  int error;
-  DBUG_ENTER("get_partition_id_range_sub_linear_key");
-  LINT_INIT(loc_part_id);
-
-  if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
-                                              func_value))))
-  {
-    DBUG_RETURN(error);
-  }
-  no_subparts= part_info->no_subparts;
-  sub_part_id= get_part_id_linear_key(part_info,
-                                      part_info->subpart_field_array,
-                                      no_subparts, &local_func_value);
-  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
-  DBUG_RETURN(0);
+  return get_part_id_linear_hash(part_info, part_info->num_parts,
+                                 part_info->part_expr, part_id, func_value);
 }
 
 
-int get_partition_id_list_sub_hash(partition_info *part_info,
-                                    uint32 *part_id,
-                                    longlong *func_value)
+int get_partition_id_key_nosub(partition_info *part_info,
+                                uint32 *part_id,
+                                longlong *func_value)
 {
-  uint32 loc_part_id, sub_part_id;
-  uint no_subparts;
-  longlong local_func_value;
-  int error;
-  DBUG_ENTER("get_partition_id_list_sub_hash");
-  LINT_INIT(sub_part_id);
-
-  if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
-                                             func_value))))
-  {
-    DBUG_RETURN(error);
-  }
-  no_subparts= part_info->no_subparts;
-  if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
-                                        &sub_part_id, &local_func_value))))
-  {
-    DBUG_RETURN(error);
-  }
-
-  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
-  DBUG_RETURN(0);
+  *part_id= get_part_id_key(part_info->table->file,
+                            part_info->part_field_array,
+                            part_info->num_parts, func_value);
+  return 0;
 }
 
 
-int get_partition_id_list_sub_linear_hash(partition_info *part_info,
-                                           uint32 *part_id,
-                                           longlong *func_value)
+int get_partition_id_linear_key_nosub(partition_info *part_info,
+                                      uint32 *part_id,
+                                      longlong *func_value)
 {
-  uint32 loc_part_id, sub_part_id;
-  uint no_subparts;
-  longlong local_func_value;
-  int error;
-  DBUG_ENTER("get_partition_id_list_sub_linear_hash");
-  LINT_INIT(sub_part_id);
-
-  if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
-                                             func_value))))
-  {
-    DBUG_RETURN(error);
-  }
-  no_subparts= part_info->no_subparts;
-  if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
-                                               part_info->subpart_expr,
-                                               &sub_part_id,
-                                               &local_func_value))))
-  {
-    DBUG_RETURN(error);
-  }
-   
-  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
-  DBUG_RETURN(0);
+  *part_id= get_part_id_linear_key(part_info,
+                                   part_info->part_field_array,
+                                   part_info->num_parts, func_value);
+  return 0;
 }
 
 
-int get_partition_id_list_sub_key(partition_info *part_info,
-                                   uint32 *part_id,
-                                   longlong *func_value)
+int get_partition_id_with_sub(partition_info *part_info,
+                              uint32 *part_id,
+                              longlong *func_value)
 {
   uint32 loc_part_id, sub_part_id;
-  uint no_subparts;
-  longlong local_func_value;
+  uint num_subparts;
   int error;
-  DBUG_ENTER("get_partition_id_range_sub_key");
+  DBUG_ENTER("get_partition_id_with_sub");
 
-  if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
-                                             func_value))))
+  if (unlikely((error= part_info->get_part_partition_id(part_info,
+                                                        &loc_part_id,
+                                                        func_value))))
   {
     DBUG_RETURN(error);
   }
-  no_subparts= part_info->no_subparts;
-  sub_part_id= get_part_id_key(part_info->table->file,
-                               part_info->subpart_field_array,
-                               no_subparts, &local_func_value);
-  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
-  DBUG_RETURN(0);
-}
-
-
-int get_partition_id_list_sub_linear_key(partition_info *part_info,
-                                          uint32 *part_id,
-                                          longlong *func_value)
-{
-  uint32 loc_part_id, sub_part_id;
-  uint no_subparts;
-  longlong local_func_value;
-  int error;
-  DBUG_ENTER("get_partition_id_list_sub_linear_key");
-
-  if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
-                                             func_value))))
+  num_subparts= part_info->num_subparts;
+  if (unlikely((error= part_info->get_subpartition_id(part_info,
+                                                      &sub_part_id))))
   {
     DBUG_RETURN(error);
-  }
-  no_subparts= part_info->no_subparts;
-  sub_part_id= get_part_id_linear_key(part_info,
-                                      part_info->subpart_field_array,
-                                      no_subparts, &local_func_value);
-  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
+  } 
+  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, num_subparts);
   DBUG_RETURN(0);
 }
 
@@ -3306,7 +3566,7 @@ int get_partition_id_hash_sub(partition_
                               uint32 *part_id)
 {
   longlong func_value;
-  return get_part_id_hash(part_info->no_subparts, part_info->subpart_expr,
+  return get_part_id_hash(part_info->num_subparts, part_info->subpart_expr,
                           part_id, &func_value);
 }
 
@@ -3315,7 +3575,7 @@ int get_partition_id_linear_hash_sub(par
                                      uint32 *part_id)
 {
   longlong func_value;
-  return get_part_id_linear_hash(part_info, part_info->no_subparts,
+  return get_part_id_linear_hash(part_info, part_info->num_subparts,
                                  part_info->subpart_expr, part_id,
                                  &func_value);
 }
@@ -3327,7 +3587,7 @@ int get_partition_id_key_sub(partition_i
   longlong func_value;
   *part_id= get_part_id_key(part_info->table->file,
                             part_info->subpart_field_array,
-                            part_info->no_subparts, &func_value);
+                            part_info->num_subparts, &func_value);
   return FALSE;
 }
 
@@ -3337,8 +3597,8 @@ int get_partition_id_linear_key_sub(part
 {
   longlong func_value;
   *part_id= get_part_id_linear_key(part_info,
-                                part_info->subpart_field_array,
-                                part_info->no_subparts, &func_value);
+                                   part_info->subpart_field_array,
+                                   part_info->num_subparts, &func_value);
   return FALSE;
 }
 
@@ -3637,16 +3897,16 @@ void get_partition_set(const TABLE *tabl
                        const key_range *key_spec, part_id_range *part_spec)
 {
   partition_info *part_info= table->part_info;
-  uint no_parts= part_info->get_tot_partitions();
+  uint num_parts= part_info->get_tot_partitions();
   uint i, part_id;
-  uint sub_part= no_parts;
-  uint32 part_part= no_parts;
+  uint sub_part= num_parts;
+  uint32 part_part= num_parts;
   KEY *key_info= NULL;
   bool found_part_field= FALSE;
   DBUG_ENTER("get_partition_set");
 
   part_spec->start_part= 0;
-  part_spec->end_part= no_parts - 1;
+  part_spec->end_part= num_parts - 1;
   if ((index < MAX_KEY) && 
        key_spec && key_spec->flag == (uint)HA_READ_KEY_EXACT &&
        part_info->some_fields_in_PF.is_set(index))
@@ -3683,7 +3943,7 @@ void get_partition_set(const TABLE *tabl
         {
           if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
           {
-            part_spec->start_part= no_parts;
+            part_spec->start_part= num_parts;
             DBUG_VOID_RETURN;
           }
         }
@@ -3697,7 +3957,7 @@ void get_partition_set(const TABLE *tabl
               allowed values. Thus it is certain that the result of this
               scan will be empty.
             */
-            part_spec->start_part= no_parts;
+            part_spec->start_part= num_parts;
             DBUG_VOID_RETURN;
           }
         }
@@ -3735,7 +3995,7 @@ void get_partition_set(const TABLE *tabl
           {
             if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
             {
-              part_spec->start_part= no_parts;
+              part_spec->start_part= num_parts;
               clear_indicator_in_key_fields(key_info);
               DBUG_VOID_RETURN;
             }
@@ -3744,7 +4004,7 @@ void get_partition_set(const TABLE *tabl
           {
             if (get_part_id_from_key(table,buf,key_info,key_spec,&part_part))
             {
-              part_spec->start_part= no_parts;
+              part_spec->start_part= num_parts;
               clear_indicator_in_key_fields(key_info);
               DBUG_VOID_RETURN;
             }
@@ -3765,29 +4025,29 @@ void get_partition_set(const TABLE *tabl
     nothing or we have discovered a range of partitions with possible holes
     in it. We need a bitvector to further the work here.
   */
-  if (!(part_part == no_parts && sub_part == no_parts))
+  if (!(part_part == num_parts && sub_part == num_parts))
   {
     /*
       We can only arrive here if we are using subpartitioning.
     */
-    if (part_part != no_parts)
+    if (part_part != num_parts)
     {
       /*
         We know the top partition and need to scan all underlying
         subpartitions. This is a range without holes.
       */
-      DBUG_ASSERT(sub_part == no_parts);
-      part_spec->start_part= part_part * part_info->no_subparts;
-      part_spec->end_part= part_spec->start_part+part_info->no_subparts - 1;
+      DBUG_ASSERT(sub_part == num_parts);
+      part_spec->start_part= part_part * part_info->num_subparts;
+      part_spec->end_part= part_spec->start_part+part_info->num_subparts - 1;
     }
     else
     {
-      DBUG_ASSERT(sub_part != no_parts);
+      DBUG_ASSERT(sub_part != num_parts);
       part_spec->start_part= sub_part;
       part_spec->end_part=sub_part+
-                           (part_info->no_subparts*(part_info->no_parts-1));
-      for (i= 0, part_id= sub_part; i < part_info->no_parts;
-           i++, part_id+= part_info->no_subparts)
+                           (part_info->num_subparts*(part_info->num_parts-1));
+      for (i= 0, part_id= sub_part; i < part_info->num_parts;
+           i++, part_id+= part_info->num_subparts)
         ; //Set bit part_id in bit array
     }
   }
@@ -3894,10 +4154,12 @@ bool mysql_unpack_partition(THD *thd,
     mem_alloc_error(sizeof(partition_info));
     goto end;
   }
-  lex.part_info->part_state= part_state;
-  lex.part_info->part_state_len= part_state_len;
+  part_info= lex.part_info;
+  part_info->part_state= part_state;
+  part_info->part_state_len= part_state_len;
   DBUG_PRINT("info", ("Parse: %s", part_buf));
-  if (parse_sql(thd, & parser_state, NULL))
+  if (parse_sql(thd, & parser_state, NULL) ||
+      part_info->fix_parser_data(thd))
   {
     thd->free_items();
     goto end;
@@ -3918,7 +4180,6 @@ bool mysql_unpack_partition(THD *thd,
   */
 
   DBUG_PRINT("info", ("Successful parse"));
-  part_info= lex.part_info;
   DBUG_PRINT("info", ("default engine = %s, default_db_type = %s",
              ha_resolve_storage_engine_name(part_info->default_engine_type),
              ha_resolve_storage_engine_name(default_db_type)));
@@ -4022,9 +4283,9 @@ set_engine_all_partitions(partition_info
         partition_element *sub_elem= sub_it++;
 
         sub_elem->engine_type= engine_type;
-      } while (++j < part_info->no_subparts);
+      } while (++j < part_info->num_subparts);
     }
-  } while (++i < part_info->no_parts);
+  } while (++i < part_info->num_parts);
 }
 /*
   SYNOPSIS
@@ -4164,7 +4425,7 @@ uint set_part_state(Alter_info *alter_in
                enum partition_state part_state)
 {
   uint part_count= 0;
-  uint no_parts_found= 0;
+  uint num_parts_found= 0;
   List_iterator<partition_element> part_it(tab_part_info->partitions);
 
   do
@@ -4179,15 +4440,15 @@ uint set_part_state(Alter_info *alter_in
         I.e mark the partition as a partition to be "changed" by
         analyzing/optimizing/rebuilding/checking/repairing/...
       */
-      no_parts_found++;
+      num_parts_found++;
       part_elem->part_state= part_state;
       DBUG_PRINT("info", ("Setting part_state to %u for partition %s",
                           part_state, part_elem->partition_name));
     }
     else
       part_elem->part_state= PART_NORMAL;
-  } while (++part_count < tab_part_info->no_parts);
-  return no_parts_found;
+  } while (++part_count < tab_part_info->num_parts);
+  return num_parts_found;
 }
 
 
@@ -4253,6 +4514,11 @@ uint prep_alter_part_table(THD *thd, TAB
     partition_info *tab_part_info= table->part_info;
     partition_info *alt_part_info= thd->work_part_info;
     uint flags= 0;
+    bool is_last_partition_reorged;
+    part_elem_value *tab_max_elem_val= NULL;
+    part_elem_value *alt_max_elem_val= NULL;
+    longlong tab_max_range= 0, alt_max_range= 0;
+
     if (!tab_part_info)
     {
       my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
@@ -4263,7 +4529,7 @@ uint prep_alter_part_table(THD *thd, TAB
       DBUG_ASSERT(table->s->db_type()->partition_flags);
       /* 'ALTER TABLE t REORG PARTITION' only allowed with auto partition */
       if (tab_part_info->part_type != HASH_PARTITION ||
-          !tab_part_info->use_default_no_partitions ||
+          !tab_part_info->use_default_num_partitions ||
           (table->s->db_type()->partition_flags &&
            !(table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)))
       {
@@ -4290,34 +4556,73 @@ uint prep_alter_part_table(THD *thd, TAB
       ((flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE)) != 0);
     DBUG_PRINT("info", ("*fast_alter_partition: %d  flags: 0x%x",
                         *fast_alter_partition, flags));
-    if (((alter_info->flags & ALTER_ADD_PARTITION) ||
-         (alter_info->flags & ALTER_REORGANIZE_PARTITION)) &&
-         (thd->work_part_info->part_type != tab_part_info->part_type) &&
-         (thd->work_part_info->part_type != NOT_A_PARTITION))
+    if ((alter_info->flags & ALTER_ADD_PARTITION) ||
+         (alter_info->flags & ALTER_REORGANIZE_PARTITION))
     {
-      if (thd->work_part_info->part_type == RANGE_PARTITION)
-      {
-        my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
-                 "RANGE", "LESS THAN");
-      }
-      else if (thd->work_part_info->part_type == LIST_PARTITION)
+      if (thd->work_part_info->part_type != tab_part_info->part_type)
       {
-        DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION);
-        my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
-                 "LIST", "IN");
+        if (thd->work_part_info->part_type == NOT_A_PARTITION)
+        {
+          if (tab_part_info->part_type == RANGE_PARTITION)
+          {
+            my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "RANGE");
+            DBUG_RETURN(TRUE);
+          }
+          else if (tab_part_info->part_type == LIST_PARTITION)
+          {
+            my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "LIST");
+            DBUG_RETURN(TRUE);
+          }
+          /*
+            Hash partitions can be altered without parser finds out about
+            that it is HASH partitioned. So no error here.
+          */
+        }
+        else
+        {
+          if (thd->work_part_info->part_type == RANGE_PARTITION)
+          {
+            my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
+                     "RANGE", "LESS THAN");
+          }
+          else if (thd->work_part_info->part_type == LIST_PARTITION)
+          {
+            DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION);
+            my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
+                     "LIST", "IN");
+          }
+          else if (tab_part_info->part_type == RANGE_PARTITION)
+          {
+            my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
+                     "RANGE", "LESS THAN");
+          }
+          else
+          {
+            DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION);
+            my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
+                     "LIST", "IN");
+          }
+          DBUG_RETURN(TRUE);
+        }
       }
-      else if (tab_part_info->part_type == RANGE_PARTITION)
+      if ((tab_part_info->column_list &&
+          alt_part_info->num_columns != tab_part_info->num_columns) ||
+          (!tab_part_info->column_list &&
+            (tab_part_info->part_type == RANGE_PARTITION ||
+             tab_part_info->part_type == LIST_PARTITION) &&
+            alt_part_info->num_columns != 1U) ||
+          (!tab_part_info->column_list &&
+            tab_part_info->part_type == HASH_PARTITION &&
+            alt_part_info->num_columns != 0))
       {
-        my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
-                 "RANGE", "LESS THAN");
+        my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
+        DBUG_RETURN(TRUE);
       }
-      else
+      alt_part_info->column_list= tab_part_info->column_list;
+      if (alt_part_info->fix_parser_data(thd))
       {
-        DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION);
-        my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
-                 "LIST", "IN");
+        DBUG_RETURN(TRUE);
       }
-      DBUG_RETURN(TRUE);
     }
     if (alter_info->flags & ALTER_ADD_PARTITION)
     {
@@ -4327,9 +4632,9 @@ uint prep_alter_part_table(THD *thd, TAB
         partitioning scheme as currently set-up.
         Partitions are always added at the end in ADD PARTITION.
       */
-      uint no_new_partitions= alt_part_info->no_parts;
-      uint no_orig_partitions= tab_part_info->no_parts;
-      uint check_total_partitions= no_new_partitions + no_orig_partitions;
+      uint num_new_partitions= alt_part_info->num_parts;
+      uint num_orig_partitions= tab_part_info->num_parts;
+      uint check_total_partitions= num_new_partitions + num_orig_partitions;
       uint new_total_partitions= check_total_partitions;
       /*
         We allow quite a lot of values to be supplied by defaults, however we
@@ -4346,22 +4651,22 @@ uint prep_alter_part_table(THD *thd, TAB
         my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
         DBUG_RETURN(TRUE);
       }
-      if (no_new_partitions == 0)
+      if (num_new_partitions == 0)
       {
         my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
         DBUG_RETURN(TRUE);
       }
       if (tab_part_info->is_sub_partitioned())
       {
-        if (alt_part_info->no_subparts == 0)
-          alt_part_info->no_subparts= tab_part_info->no_subparts;
-        else if (alt_part_info->no_subparts != tab_part_info->no_subparts)
+        if (alt_part_info->num_subparts == 0)
+          alt_part_info->num_subparts= tab_part_info->num_subparts;
+        else if (alt_part_info->num_subparts != tab_part_info->num_subparts)
         {
           my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0));
           DBUG_RETURN(TRUE);
         }
         check_total_partitions= new_total_partitions*
-                                alt_part_info->no_subparts;
+                                alt_part_info->num_subparts;
       }
       if (check_total_partitions > MAX_PARTITIONS)
       {
@@ -4371,8 +4676,8 @@ uint prep_alter_part_table(THD *thd, TAB
       alt_part_info->part_type= tab_part_info->part_type;
       alt_part_info->subpart_type= tab_part_info->subpart_type;
       if (alt_part_info->set_up_defaults_for_partitioning(table->file,
-                                                          0ULL, 
-                                                          tab_part_info->no_parts))
+                                                    0ULL, 
+                                                    tab_part_info->num_parts))
       {
         DBUG_RETURN(TRUE);
       }
@@ -4447,7 +4752,7 @@ that are reorganised.
         uint lower_2n= upper_2n >> 1;
         bool all_parts= TRUE;
         if (tab_part_info->linear_hash_ind &&
-            no_new_partitions < upper_2n)
+            num_new_partitions < upper_2n)
         {
           /*
             An analysis of which parts needs reorganisation shows that it is
@@ -4456,7 +4761,7 @@ that are reorganised.
             onwards it starts again from partition 0 and goes on until
             it reaches p(upper_2n - 1). If the last new partition reaches
             beyond upper_2n - 1 then the first interval will end with
-            p(lower_2n - 1) and start with p(no_orig_partitions - lower_2n).
+            p(lower_2n - 1) and start with p(num_orig_partitions - lower_2n).
             If lower_2n partitions are added then p0 to p(lower_2n - 1) will
             be reorganised which means that the two interval becomes one
             interval at this point. Thus only when adding less than
@@ -4484,7 +4789,7 @@ that are reorganised.
             to TRUE. In this case we don't get into this if-part at all.
           */
           all_parts= FALSE;
-          if (no_new_partitions >= lower_2n)
+          if (num_new_partitions >= lower_2n)
           {
             /*
               In this case there is only one interval since the two intervals
@@ -4500,8 +4805,8 @@ that are reorganised.
               Also in this case there is only one interval since we are not
               going over a 2**n boundary
             */
-            start_part= no_orig_partitions - lower_2n;
-            end_part= start_part + (no_new_partitions - 1);
+            start_part= num_orig_partitions - lower_2n;
+            end_part= start_part + (num_new_partitions - 1);
           }
           else
           {
@@ -4510,7 +4815,7 @@ that are reorganised.
                new parts that would ensure that the intervals become
                overlapping.
             */
-            start_part= no_orig_partitions - lower_2n;
+            start_part= num_orig_partitions - lower_2n;
             end_part= upper_2n - 1;
             start_sec_part= 0;
             end_sec_part= new_total_partitions - (upper_2n + 1);
@@ -4527,7 +4832,7 @@ that are reorganised.
           {
             p_elem->part_state= PART_CHANGED;
           }
-        } while (++part_no < no_orig_partitions);
+        } while (++part_no < num_orig_partitions);
       }
       /*
         Need to concatenate the lists here to make it possible to check the
@@ -4550,8 +4855,8 @@ that are reorganised.
             mem_alloc_error(1);
             DBUG_RETURN(TRUE);
           }
-        } while (++part_count < no_new_partitions);
-        tab_part_info->no_parts+= no_new_partitions;
+        } while (++part_count < num_new_partitions);
+        tab_part_info->num_parts+= num_new_partitions;
       }
       /*
         If we specify partitions explicitly we don't use defaults anymore.
@@ -4566,7 +4871,7 @@ that are reorganised.
           DBUG_PRINT("info", ("part_info: %p", tab_part_info));
           tab_part_info->use_default_partitions= FALSE;
         }
-        tab_part_info->use_default_no_partitions= FALSE;
+        tab_part_info->use_default_num_partitions= FALSE;
         tab_part_info->is_auto_partitioned= FALSE;
       }
     }
@@ -4580,8 +4885,8 @@ that are reorganised.
         command to drop the partition failed in the middle.
       */
       uint part_count= 0;
-      uint no_parts_dropped= alter_info->partition_names.elements;
-      uint no_parts_found= 0;
+      uint num_parts_dropped= alter_info->partition_names.elements;
+      uint num_parts_found= 0;
       List_iterator<partition_element> part_it(tab_part_info->partitions);
 
       tab_part_info->is_auto_partitioned= FALSE;
@@ -4591,7 +4896,7 @@ that are reorganised.
         my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
         DBUG_RETURN(TRUE);
       }
-      if (no_parts_dropped >= tab_part_info->no_parts)
+      if (num_parts_dropped >= tab_part_info->num_parts)
       {
         my_error(ER_DROP_LAST_PARTITION, MYF(0));
         DBUG_RETURN(TRUE);
@@ -4605,11 +4910,11 @@ that are reorganised.
           /*
             Set state to indicate that the partition is to be dropped.
           */
-          no_parts_found++;
+          num_parts_found++;
           part_elem->part_state= PART_TO_BE_DROPPED;
         }
-      } while (++part_count < tab_part_info->no_parts);
-      if (no_parts_found != no_parts_dropped)
+      } while (++part_count < tab_part_info->num_parts);
+      if (num_parts_found != num_parts_dropped)
       {
         my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP");
         DBUG_RETURN(TRUE);
@@ -4619,14 +4924,14 @@ that are reorganised.
         my_error(ER_ROW_IS_REFERENCED, MYF(0));
         DBUG_RETURN(TRUE);
       }
-      tab_part_info->no_parts-= no_parts_dropped;
+      tab_part_info->num_parts-= num_parts_dropped;
     }
     else if (alter_info->flags & ALTER_REBUILD_PARTITION)
     {
-      uint no_parts_found;
-      uint no_parts_opt= alter_info->partition_names.elements;
-      no_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED);
-      if (no_parts_found != no_parts_opt &&
+      uint num_parts_found;
+      uint num_parts_opt= alter_info->partition_names.elements;
+      num_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED);
+      if (num_parts_found != num_parts_opt &&
           (!(alter_info->flags & ALTER_ALL_PARTITION)))
       {
         my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
@@ -4640,20 +4945,20 @@ that are reorganised.
     }
     else if (alter_info->flags & ALTER_COALESCE_PARTITION)
     {
-      uint no_parts_coalesced= alter_info->no_parts;
-      uint no_parts_remain= tab_part_info->no_parts - no_parts_coalesced;
+      uint num_parts_coalesced= alter_info->num_parts;
+      uint num_parts_remain= tab_part_info->num_parts - num_parts_coalesced;
       List_iterator<partition_element> part_it(tab_part_info->partitions);
       if (tab_part_info->part_type != HASH_PARTITION)
       {
         my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0));
         DBUG_RETURN(TRUE);
       }
-      if (no_parts_coalesced == 0)
+      if (num_parts_coalesced == 0)
       {
         my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0));
         DBUG_RETURN(TRUE);
       }
-      if (no_parts_coalesced >= tab_part_info->no_parts)
+      if (num_parts_coalesced >= tab_part_info->num_parts)
       {
         my_error(ER_DROP_LAST_PARTITION, MYF(0));
         DBUG_RETURN(TRUE);
@@ -4701,21 +5006,21 @@ state of p1.
           uint upper_2n= tab_part_info->linear_hash_mask + 1;
           uint lower_2n= upper_2n >> 1;
           all_parts= FALSE;
-          if (no_parts_coalesced >= lower_2n)
+          if (num_parts_coalesced >= lower_2n)
           {
             all_parts= TRUE;
           }
-          else if (no_parts_remain >= lower_2n)
+          else if (num_parts_remain >= lower_2n)
           {
-            end_part= tab_part_info->no_parts - (lower_2n + 1);
-            start_part= no_parts_remain - lower_2n;
+            end_part= tab_part_info->num_parts - (lower_2n + 1);
+            start_part= num_parts_remain - lower_2n;
           }
           else
           {
             start_part= 0;
-            end_part= tab_part_info->no_parts - (lower_2n + 1);
+            end_part= tab_part_info->num_parts - (lower_2n + 1);
             end_sec_part= (lower_2n >> 1) - 1;
-            start_sec_part= end_sec_part - (lower_2n - (no_parts_remain + 1));
+            start_sec_part= end_sec_part - (lower_2n - (num_parts_remain + 1));
           }
         }
         do
@@ -4726,19 +5031,19 @@ state of p1.
               (part_count >= start_part && part_count <= end_part) ||
               (part_count >= start_sec_part && part_count <= end_sec_part)))
             p_elem->part_state= PART_CHANGED;
-          if (++part_count > no_parts_remain)
+          if (++part_count > num_parts_remain)
           {
             if (*fast_alter_partition)
               p_elem->part_state= PART_REORGED_DROPPED;
             else
               part_it.remove();
           }
-        } while (part_count < tab_part_info->no_parts);
-        tab_part_info->no_parts= no_parts_remain;
+        } while (part_count < tab_part_info->num_parts);
+        tab_part_info->num_parts= num_parts_remain;
       }
       if (!(alter_info->flags & ALTER_TABLE_REORG))
       {
-        tab_part_info->use_default_no_partitions= FALSE;
+        tab_part_info->use_default_num_partitions= FALSE;
         tab_part_info->is_auto_partitioned= FALSE;
       }
     }
@@ -4755,33 +5060,32 @@ state of p1.
         range as those changed from.
         This command can be used on RANGE and LIST partitions.
       */
-      uint no_parts_reorged= alter_info->partition_names.elements;
-      uint no_parts_new= thd->work_part_info->partitions.elements;
-      partition_info *alt_part_info= thd->work_part_info;
+      uint num_parts_reorged= alter_info->partition_names.elements;
+      uint num_parts_new= thd->work_part_info->partitions.elements;
       uint check_total_partitions;
 
       tab_part_info->is_auto_partitioned= FALSE;
-      if (no_parts_reorged > tab_part_info->no_parts)
+      if (num_parts_reorged > tab_part_info->num_parts)
       {
         my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0));
         DBUG_RETURN(TRUE);
       }
       if (!(tab_part_info->part_type == RANGE_PARTITION ||
             tab_part_info->part_type == LIST_PARTITION) &&
-           (no_parts_new != no_parts_reorged))
+           (num_parts_new != num_parts_reorged))
       {
         my_error(ER_REORG_HASH_ONLY_ON_SAME_NO, MYF(0));
         DBUG_RETURN(TRUE);
       }
       if (tab_part_info->is_sub_partitioned() &&
-          alt_part_info->no_subparts &&
-          alt_part_info->no_subparts != tab_part_info->no_subparts)
+          alt_part_info->num_subparts &&
+          alt_part_info->num_subparts != tab_part_info->num_subparts)
       {
         my_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR, MYF(0));
         DBUG_RETURN(TRUE);
       }
-      check_total_partitions= tab_part_info->no_parts + no_parts_new;
-      check_total_partitions-= no_parts_reorged;
+      check_total_partitions= tab_part_info->num_parts + num_parts_new;
+      check_total_partitions-= num_parts_reorged;
       if (check_total_partitions > MAX_PARTITIONS)
       {
         my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
@@ -4789,7 +5093,7 @@ state of p1.
       }
       alt_part_info->part_type= tab_part_info->part_type;
       alt_part_info->subpart_type= tab_part_info->subpart_type;
-      alt_part_info->no_subparts= tab_part_info->no_subparts;
+      alt_part_info->num_subparts= tab_part_info->num_subparts;
       DBUG_ASSERT(!alt_part_info->use_default_partitions);
       if (alt_part_info->set_up_defaults_for_partitioning(table->file,
                                                           0ULL, 
@@ -4837,9 +5141,7 @@ the generated partition syntax in a corr
         uint part_count= 0;
         bool found_first= FALSE;
         bool found_last= FALSE;
-        bool is_last_partition_reorged;
         uint drop_count= 0;
-        longlong tab_max_range= 0, alt_max_range= 0;
         do
         {
           partition_element *part_elem= tab_it++;
@@ -4849,7 +5151,13 @@ the generated partition syntax in a corr
           {
             is_last_partition_reorged= TRUE;
             drop_count++;
-            tab_max_range= part_elem->range_value;
+            if (tab_part_info->column_list)
+            {
+              List_iterator<part_elem_value> p(part_elem->list_val_list);
+              tab_max_elem_val= p++;
+            }
+            else
+              tab_max_range= part_elem->range_value;
             if (*fast_alter_partition &&
                 tab_part_info->temp_partitions.push_back(part_elem))
             {
@@ -4861,20 +5169,28 @@ the generated partition syntax in a corr
             if (!found_first)
             {
               uint alt_part_count= 0;
-              found_first= TRUE;
+              partition_element *alt_part_elem;
               List_iterator<partition_element>
                                  alt_it(alt_part_info->partitions);
+              found_first= TRUE;
               do
               {
-                partition_element *alt_part_elem= alt_it++;
-                alt_max_range= alt_part_elem->range_value;
+                alt_part_elem= alt_it++;
+                if (tab_part_info->column_list)
+                {
+                  List_iterator<part_elem_value> p(alt_part_elem->list_val_list);
+                  alt_max_elem_val= p++;
+                }
+                else
+                  alt_max_range= alt_part_elem->range_value;
+
                 if (*fast_alter_partition)
                   alt_part_elem->part_state= PART_TO_BE_ADDED;
                 if (alt_part_count == 0)
                   tab_it.replace(alt_part_elem);
                 else
                   tab_it.after(alt_part_elem);
-              } while (++alt_part_count < no_parts_new);
+              } while (++alt_part_count < num_parts_new);
             }
             else if (found_last)
             {
@@ -4889,32 +5205,13 @@ the generated partition syntax in a corr
             if (found_first)
               found_last= TRUE;
           }
-        } while (++part_count < tab_part_info->no_parts);
-        if (drop_count != no_parts_reorged)
+        } while (++part_count < tab_part_info->num_parts);
+        if (drop_count != num_parts_reorged)
         {
           my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE");
           DBUG_RETURN(TRUE);
         }
-        if (tab_part_info->part_type == RANGE_PARTITION &&
-            ((is_last_partition_reorged &&
-               alt_max_range < tab_max_range) ||
-              (!is_last_partition_reorged &&
-               alt_max_range != tab_max_range)))
-        {
-          /*
-            For range partitioning the total resulting range before and
-            after the change must be the same except in one case. This is
-            when the last partition is reorganised, in this case it is
-            acceptable to increase the total range.
-            The reason is that it is not allowed to have "holes" in the
-            middle of the ranges and thus we should not allow to reorganise
-            to create "holes". Also we should not allow using REORGANIZE
-            to drop data.
-          */
-          my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
-          DBUG_RETURN(TRUE);
-        }
-        tab_part_info->no_parts= check_total_partitions;
+        tab_part_info->num_parts= check_total_partitions;
       }
     }
     else
@@ -4930,13 +5227,45 @@ the generated partition syntax in a corr
           !alt_part_info->use_default_subpartitions)
       {
         tab_part_info->use_default_subpartitions= FALSE;
-        tab_part_info->use_default_no_subpartitions= FALSE;
+        tab_part_info->use_default_num_subpartitions= FALSE;
       }
       if (tab_part_info->check_partition_info(thd, (handlerton**)NULL,
-                                              table->file, 0ULL, FALSE))
+                                              table->file, 0ULL, TRUE))
       {
         DBUG_RETURN(TRUE);
       }
+      /*
+        The check below needs to be performed after check_partition_info
+        since this function "fixes" the item trees of the new partitions
+        to reorganize into
+      */
+      if (alter_info->flags == ALTER_REORGANIZE_PARTITION &&
+          tab_part_info->part_type == RANGE_PARTITION &&
+          ((is_last_partition_reorged &&
+            (tab_part_info->column_list ?
+             (tab_part_info->compare_column_values(
+                              alt_max_elem_val->col_val_array,
+                              tab_max_elem_val->col_val_array) < 0) :
+             alt_max_range < tab_max_range)) ||
+            (!is_last_partition_reorged &&
+             (tab_part_info->column_list ?
+              (tab_part_info->compare_column_values(
+                              alt_max_elem_val->col_val_array,
+                              tab_max_elem_val->col_val_array) != 0) :
+              alt_max_range != tab_max_range))))
+      {
+        /*
+          For range partitioning the total resulting range before and
+          after the change must be the same except in one case. This is
+          when the last partition is reorganised, in this case it is
+          acceptable to increase the total range.
+          The reason is that it is not allowed to have "holes" in the
+          middle of the ranges and thus we should not allow to reorganise
+          to create "holes".
+        */
+        my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
+        DBUG_RETURN(TRUE);
+      }
     }
   }
   else
@@ -5050,6 +5379,10 @@ the generated partition syntax in a corr
       {
         DBUG_PRINT("info", ("partition changed"));
         *partition_changed= TRUE;
+        if (thd->work_part_info->fix_parser_data(thd))
+        {
+          DBUG_RETURN(TRUE);
+        }
       }
       /*
         Set up partition default_engine_type either from the create_info
@@ -5207,8 +5540,8 @@ static bool mysql_drop_partitions(ALTER_
       part_it.remove();
       remove_count++;
     }
-  } while (++i < part_info->no_parts);
-  part_info->no_parts-= remove_count;
+  } while (++i < part_info->num_parts);
+  part_info->num_parts-= remove_count;
   DBUG_RETURN(FALSE);
 }
 
@@ -5330,7 +5663,7 @@ static bool write_log_changed_partitions
   char normal_path[FN_REFLEN];
   List_iterator<partition_element> part_it(part_info->partitions);
   uint temp_partitions= part_info->temp_partitions.elements;
-  uint no_elements= part_info->partitions.elements;
+  uint num_elements= part_info->partitions.elements;
   uint i= 0;
   DBUG_ENTER("write_log_changed_partitions");
 
@@ -5343,7 +5676,7 @@ static bool write_log_changed_partitions
       if (part_info->is_sub_partitioned())
       {
         List_iterator<partition_element> sub_it(part_elem->subpartitions);
-        uint no_subparts= part_info->no_subparts;
+        uint num_subparts= part_info->num_subparts;
         uint j= 0;
         do
         {
@@ -5372,7 +5705,7 @@ static bool write_log_changed_partitions
           *next_entry= log_entry->entry_pos;
           sub_elem->log_entry= log_entry;
           insert_part_info_log_entry_list(part_info, log_entry);
-        } while (++j < no_subparts);
+        } while (++j < num_subparts);
       }
       else
       {
@@ -5400,7 +5733,7 @@ static bool write_log_changed_partitions
         insert_part_info_log_entry_list(part_info, log_entry);
       }
     }
-  } while (++i < no_elements);
+  } while (++i < num_elements);
   DBUG_RETURN(FALSE);
 }
 
@@ -5426,14 +5759,14 @@ static bool write_log_dropped_partitions
   char tmp_path[FN_LEN];
   List_iterator<partition_element> part_it(part_info->partitions);
   List_iterator<partition_element> temp_it(part_info->temp_partitions);
-  uint no_temp_partitions= part_info->temp_partitions.elements;
-  uint no_elements= part_info->partitions.elements;
+  uint num_temp_partitions= part_info->temp_partitions.elements;
+  uint num_elements= part_info->partitions.elements;
   DBUG_ENTER("write_log_dropped_partitions");
 
   ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
   if (temp_list)
-    no_elements= no_temp_partitions;
-  while (no_elements--)
+    num_elements= num_temp_partitions;
+  while (num_elements--)
   {
     partition_element *part_elem;
     if (temp_list)
@@ -5447,14 +5780,14 @@ static bool write_log_dropped_partitions
       uint name_variant;
       if (part_elem->part_state == PART_CHANGED ||
           (part_elem->part_state == PART_TO_BE_ADDED &&
-           no_temp_partitions))
+           num_temp_partitions))
         name_variant= TEMP_PART_NAME;
       else
         name_variant= NORMAL_PART_NAME;
       if (part_info->is_sub_partitioned())
       {
         List_iterator<partition_element> sub_it(part_elem->subpartitions);
-        uint no_subparts= part_info->no_subparts;
+        uint num_subparts= part_info->num_subparts;
         uint j= 0;
         do
         {
@@ -5474,7 +5807,7 @@ static bool write_log_dropped_partitions
           *next_entry= log_entry->entry_pos;
           sub_elem->log_entry= log_entry;
           insert_part_info_log_entry_list(part_info, log_entry);
-        } while (++j < no_subparts);
+        } while (++j < num_subparts);
       }
       else
       {
@@ -6574,16 +6907,19 @@ void make_used_partitions_str(partition_
   IMPLEMENTATION
     There are two available interval analyzer functions:
     (1) get_part_iter_for_interval_via_mapping 
-    (2) get_part_iter_for_interval_via_walking
+    (2) get_part_iter_for_interval_cols_via_map 
+    (3) get_part_iter_for_interval_via_walking
 
     They both have limited applicability:
     (1) is applicable for "PARTITION BY <RANGE|LIST>(func(t.field))", where
     func is a monotonic function.
-    
-    (2) is applicable for 
+
+    (2) is applicable for "PARTITION BY <RANGE|LIST> COLUMNS (field_list)
+
+    (3) is applicable for 
       "[SUB]PARTITION BY <any-partitioning-type>(any_func(t.integer_field))"
       
-    If both are applicable, (1) is preferred over (2).
+    If both (1) and (3) are applicable, (1) is preferred over (3).
     
     This function sets part_info::get_part_iter_for_interval according to
     this criteria, and also sets some auxilary fields that the function
@@ -6603,10 +6939,19 @@ static void set_up_range_analysis_info(p
   switch (part_info->part_type) {
   case RANGE_PARTITION:
   case LIST_PARTITION:
-    if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
+    if (!part_info->column_list)
+    {
+      if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
+      {
+        part_info->get_part_iter_for_interval=
+          get_part_iter_for_interval_via_mapping;
+        goto setup_subparts;
+      }
+    }
+    else
     {
       part_info->get_part_iter_for_interval=
-        get_part_iter_for_interval_via_mapping;
+        get_part_iter_for_interval_cols_via_map;
       goto setup_subparts;
     }
   default:
@@ -6617,7 +6962,7 @@ static void set_up_range_analysis_info(p
     Check if get_part_iter_for_interval_via_walking() can be used for
     partitioning
   */
-  if (part_info->no_part_fields == 1)
+  if (part_info->num_part_fields == 1)
   {
     Field *field= part_info->part_field_array[0];
     switch (field->type()) {
@@ -6639,7 +6984,7 @@ setup_subparts:
     Check if get_part_iter_for_interval_via_walking() can be used for
     subpartitioning
   */
-  if (part_info->no_subpart_fields == 1)
+  if (part_info->num_subpart_fields == 1)
   {
     Field *field= part_info->subpart_field_array[0];
     switch (field->type()) {
@@ -6657,9 +7002,118 @@ setup_subparts:
 }
 
 
+/*
+  This function takes a memory of packed fields in opt-range format
+  and stores it in record format. To avoid having to worry about how
+  the length of fields are calculated in opt-range format we send
+  an array of lengths used for each field in store_length_array.
+
+  SYNOPSIS
+  store_tuple_to_record()
+  pfield                         Field array
+  store_length_array             Array of field lengths
+  value                          Memory where fields are stored
+  value_end                      End of memory
+
+  RETURN VALUE
+  nparts                         Number of fields assigned
+*/
+uint32 store_tuple_to_record(Field **pfield,
+                             uint32 *store_length_array,
+                             uchar *value,
+                             uchar *value_end)
+{
+  /* This function is inspired by store_key_image_rec. */
+  uint32 nparts= 0;
+  uchar *loc_value;
+  while (value < value_end)
+  {
+    loc_value= value;
+    if ((*pfield)->real_maybe_null())
+    {
+      if (*loc_value)
+        (*pfield)->set_null();
+      else
+        (*pfield)->set_notnull();
+      loc_value++;
+    }
+    uint len= (*pfield)->pack_length();
+    (*pfield)->set_key_image(loc_value, len);
+    value+= *store_length_array;
+    store_length_array++;
+    nparts++;
+    pfield++;
+  }
+  return nparts;
+}
+
+/*
+  RANGE(columns) partitioning: compare value bound and probe tuple.
+
+  The value bound always is a full tuple (but may include the MAXVALUE
+  special value).
+
+  The probe tuple may be a prefix of partitioning tuple. The tail_is_min
+  parameter specifies whether the suffix components should be assumed to
+  hold MAXVALUE
+*/
+
+static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec)
+{
+  partition_info *part_info= val->part_info;
+  Field **field= part_info->part_field_array;
+  Field **fields_end= field + nvals_in_rec;
+  int res;
+
+  for (; field != fields_end; field++, val++)
+  {
+    if (val->max_value)
+      return -1;
+    if ((*field)->is_null())
+    {
+      if (val->null_value)
+        continue;
+      return -1;
+    }
+    if (val->null_value)
+      return +1;
+    res= (*field)->cmp((const uchar*)val->column_value);
+    if (res)
+      return res;
+  }
+  return 0;
+}
+
+
+static int cmp_rec_and_tuple_prune(part_column_list_val *val,
+                                   uint32 n_vals_in_rec,
+                                   bool tail_is_min)
+{
+  int cmp;
+  Field **field;
+  partition_info *part_info;
+  if ((cmp= cmp_rec_and_tuple(val, n_vals_in_rec)))
+    return cmp;
+  part_info= val->part_info;
+  field= part_info->part_field_array + n_vals_in_rec;
+  for (; *field; field++, val++)
+  {
+    if (tail_is_min)
+      return -1;
+    if (!tail_is_min && !val->max_value)
+      return +1;
+  }
+  return 0;
+}
+
+
 typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
                                     bool include_endpoint);
 
+typedef uint32 (*get_col_endpoint_func)(partition_info*, bool left_endpoint,
+                                        bool include_endpoint,
+                                        uint32 num_parts);
+
 /*
   Partitioning Interval Analysis: Initialize the iterator for "mapping" case
 
@@ -6695,9 +7149,132 @@ typedef uint32 (*get_endpoint_func)(part
    -1 - All partitions would match (iterator not initialized)
 */
 
+uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info,
+                                                bool left_endpoint,
+                                                bool include_endpoint,
+                                                uint32 nparts)
+{
+  uint max_partition= part_info->num_parts - 1;
+  uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
+  part_column_list_val *range_col_array= part_info->range_col_array;
+  uint num_columns= part_info->part_field_list.elements;
+  bool tailf= !(left_endpoint ^ include_endpoint);
+  DBUG_ENTER("get_partition_id_cols_range_for_endpoint");
+
+  /* Get the partitioning function value for the endpoint */
+  while (max_part_id > min_part_id)
+  {
+    loc_part_id= (max_part_id + min_part_id + 1) >> 1;
+    if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns,
+                                nparts, tailf) >= 0)
+      min_part_id= loc_part_id + 1;
+    else
+      max_part_id= loc_part_id - 1;
+  }
+  loc_part_id= max_part_id;
+  if (loc_part_id < max_partition && 
+      cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*num_columns,
+                              nparts, tailf) >= 0
+      )
+  {
+     loc_part_id++;
+  }
+  if (left_endpoint)
+  {
+    if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns,
+                                nparts, tailf) >= 0)
+      loc_part_id++;
+  }
+  else 
+  {
+    if (loc_part_id < max_partition)
+    {
+      int res= cmp_rec_and_tuple_prune(range_col_array +
+                                       loc_part_id * num_columns,
+                                       nparts, tailf);
+      if (!res)
+        loc_part_id += test(include_endpoint);
+      else if (res > 0)
+        loc_part_id++;
+    }
+    loc_part_id++;
+  }
+  DBUG_RETURN(loc_part_id);
+}
+
+
+int get_part_iter_for_interval_cols_via_map(partition_info *part_info,
+                                            bool is_subpart,
+                                            uint32 *store_length_array,
+                                            uchar *min_value, uchar *max_value,
+                                            uint min_len, uint max_len, 
+                                            uint flags,
+                                            PARTITION_ITERATOR *part_iter)
+{
+  uint32 nparts;
+  get_col_endpoint_func  get_col_endpoint;
+  DBUG_ENTER("get_part_iter_for_interval_cols_via_map");
+
+  if (part_info->part_type == RANGE_PARTITION)
+  {
+    get_col_endpoint= get_partition_id_cols_range_for_endpoint;
+    part_iter->get_next= get_next_partition_id_range;
+  }
+  else if (part_info->part_type == LIST_PARTITION)
+  {
+    get_col_endpoint= get_partition_id_cols_list_for_endpoint;
+    part_iter->get_next= get_next_partition_id_list;
+    part_iter->part_info= part_info;
+    DBUG_ASSERT(part_info->num_list_values);
+  }
+  else
+    assert(0);
+
+  if (flags & NO_MIN_RANGE)
+    part_iter->part_nums.start= part_iter->part_nums.cur= 0;
+  else
+  {
+    // Copy from min_value to record
+    nparts= store_tuple_to_record(part_info->part_field_array,
+                                  store_length_array,
+                                  min_value,
+                                  min_value + min_len);
+    part_iter->part_nums.start= part_iter->part_nums.cur=
+      get_col_endpoint(part_info, TRUE, !(flags & NEAR_MIN),
+                       nparts);
+  }
+  if (flags & NO_MAX_RANGE)
+  {
+    if (part_info->part_type == RANGE_PARTITION)
+      part_iter->part_nums.end= part_info->num_parts;
+    else /* LIST_PARTITION */
+    {
+      DBUG_ASSERT(part_info->part_type == LIST_PARTITION);
+      part_iter->part_nums.end= part_info->num_list_values;
+    }
+  }
+  else
+  {
+    // Copy from max_value to record
+    nparts= store_tuple_to_record(part_info->part_field_array,
+                                  store_length_array,
+                                  max_value,
+                                  max_value + max_len);
+    part_iter->part_nums.end= get_col_endpoint(part_info, FALSE,
+                                               !(flags & NEAR_MAX),
+                                               nparts);
+  }
+  if (part_iter->part_nums.start == part_iter->part_nums.end)
+    DBUG_RETURN(0);
+  DBUG_RETURN(1);
+}
+
+
 int get_part_iter_for_interval_via_mapping(partition_info *part_info,
                                            bool is_subpart,
+                                           uint32 *store_length_array, /* ignored */
                                            uchar *min_value, uchar *max_value,
+                                           uint min_len, uint max_len, /* ignored */
                                            uint flags,
                                            PARTITION_ITERATOR *part_iter)
 {
@@ -6708,6 +7285,9 @@ int get_part_iter_for_interval_via_mappi
   uint field_len= field->pack_length_in_rec();
   DBUG_ENTER("get_part_iter_for_interval_via_mapping");
   DBUG_ASSERT(!is_subpart);
+  (void) store_length_array;
+  (void)min_len;
+  (void)max_len;
   part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
 
   if (part_info->part_type == RANGE_PARTITION)
@@ -6716,7 +7296,7 @@ int get_part_iter_for_interval_via_mappi
       get_endpoint=        get_partition_id_range_for_endpoint_charset;
     else
       get_endpoint=        get_partition_id_range_for_endpoint;
-    max_endpoint_val=    part_info->no_parts;
+    max_endpoint_val=    part_info->num_parts;
     part_iter->get_next= get_next_partition_id_range;
   }
   else if (part_info->part_type == LIST_PARTITION)
@@ -6726,7 +7306,7 @@ int get_part_iter_for_interval_via_mappi
       get_endpoint=        get_list_array_idx_for_endpoint_charset;
     else
       get_endpoint=        get_list_array_idx_for_endpoint;
-    max_endpoint_val=    part_info->no_list_values;
+    max_endpoint_val=    part_info->num_list_values;
     part_iter->get_next= get_next_partition_id_list;
     part_iter->part_info= part_info;
     if (max_endpoint_val == 0)
@@ -6771,7 +7351,7 @@ int get_part_iter_for_interval_via_mappi
   {
     part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
     part_iter->part_nums.start= part_iter->part_nums.cur= 0;
-    if (*max_value && !(flags & NO_MAX_RANGE))
+    if (!(flags & NO_MAX_RANGE) && *max_value)
     {
       /* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */
       part_iter->part_nums.end= 0;
@@ -6871,26 +7451,32 @@ int get_part_iter_for_interval_via_mappi
 */
 
 int get_part_iter_for_interval_via_walking(partition_info *part_info,
-                                           bool is_subpart,
-                                           uchar *min_value, uchar *max_value,
-                                           uint flags,
-                                           PARTITION_ITERATOR *part_iter)
+                                      bool is_subpart,
+                                      uint32 *store_length_array, /* ignored */
+                                      uchar *min_value, uchar *max_value,
+                                      uint min_len, uint max_len, /* ignored */
+                                      uint flags,
+                                      PARTITION_ITERATOR *part_iter)
 {
   Field *field;
   uint total_parts;
   partition_iter_func get_next_func;
   DBUG_ENTER("get_part_iter_for_interval_via_walking");
+  (void)store_length_array;
+  (void)min_len;
+  (void)max_len;
+
   part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
   if (is_subpart)
   {
     field= part_info->subpart_field_array[0];
-    total_parts= part_info->no_subparts;
+    total_parts= part_info->num_subparts;
     get_next_func=  get_next_subpartition_via_walking;
   }
   else
   {
     field= part_info->part_field_array[0];
-    total_parts= part_info->no_parts;
+    total_parts= part_info->num_parts;
     get_next_func=  get_next_partition_via_walking;
   }
 
@@ -7032,8 +7618,9 @@ uint32 get_next_partition_id_range(PARTI
 
   DESCRIPTION
     This implementation of PARTITION_ITERATOR::get_next() is special for 
-    LIST partitioning: it enumerates partition ids in 
-    part_info->list_array[i] where i runs over [min_idx, max_idx] interval.
+    LIST partitioning: it enumerates partition ids in
+    part_info->list_array[i] (list_col_array[i] for COLUMNS LIST
+    partitioning) where i runs over [min_idx, max_idx] interval.
     The function conforms to partition_iter_func type.
 
   RETURN 
@@ -7055,8 +7642,13 @@ uint32 get_next_partition_id_list(PARTIT
     return NOT_A_PARTITION_ID;
   }
   else
-    return part_iter->part_info->list_array[part_iter->
-                                            part_nums.cur++].partition_id;
+  {
+    partition_info *part_info= part_iter->part_info;
+    uint32 num_part= part_iter->part_nums.cur++;
+    return part_info->column_list ?
+           part_info->list_col_array[num_part].partition_id :
+           part_info->list_array[num_part].partition_id;
+  }
 }
 
 
@@ -7197,5 +7789,17 @@ void create_subpartition_name(char *out,
     strxmov(out, in1, "#P#", transl_part_name,
             "#SP#", transl_subpart_name, "#REN#", NullS);
 }
+
+uint get_partition_field_store_length(Field *field)
+{
+  uint store_length;
+
+  store_length= field->key_length();
+  if (field->real_maybe_null())
+    store_length+= HA_KEY_NULL_LENGTH;
+  if (field->real_type() == MYSQL_TYPE_VARCHAR)
+    store_length+= HA_KEY_BLOB_LENGTH;
+  return store_length;
+}
 #endif
 

=== modified file 'sql/sql_partition.h'
--- a/sql/sql_partition.h	2009-10-26 14:02:26 +0000
+++ b/sql/sql_partition.h	2009-11-03 11:26:54 +0000
@@ -1,7 +1,7 @@
 #ifndef SQL_PARTITION_INCLUDED
 #define SQL_PARTITION_INCLUDED
 
-/* Copyright (C) 2006 MySQL AB
+/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -68,15 +68,19 @@ int get_part_for_delete(const uchar *buf
 void prune_partition_set(const TABLE *table, part_id_range *part_spec);
 bool check_partition_info(partition_info *part_info,handlerton **eng_type,
                           TABLE *table, handler *file, HA_CREATE_INFO *info);
-void set_linear_hash_mask(partition_info *part_info, uint no_parts);
+void set_linear_hash_mask(partition_info *part_info, uint num_parts);
 bool fix_partition_func(THD *thd, TABLE *table, bool create_table_ind);
-char *generate_partition_syntax(partition_info *part_info,
-                                uint *buf_length, bool use_sql_alloc,
-                                bool show_partition_options);
 bool partition_key_modified(TABLE *table, const MY_BITMAP *fields);
 void get_partition_set(const TABLE *table, uchar *buf, const uint index,
                        const key_range *key_spec,
                        part_id_range *part_spec);
+uint get_partition_field_store_length(Field *field);
+int get_cs_converted_part_value_from_string(THD *thd,
+                                            Item *item,
+                                            String *input_str,
+                                            String *output_str,
+                                            CHARSET_INFO *cs,
+                                            bool use_hex);
 void get_full_part_id_from_key(const TABLE *table, uchar *buf,
                                KEY *key_info,
                                const key_range *key_spec,
@@ -99,6 +103,7 @@ bool fix_fields_part_func(THD *thd, Item
 
 bool check_part_func_fields(Field **ptr, bool ok_with_charsets);
 bool field_is_partition_charset(Field *field);
+Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs);
 
 /*
   A "Get next" function for partition iterator.
@@ -175,13 +180,16 @@ typedef struct st_partition_iter
 
   SYNOPSIS
     get_partitions_in_range_iter()
-      part_info   Partitioning info
-      is_subpart  
-      min_val     Left edge,  field value in opt_range_key format.
-      max_val     Right edge, field value in opt_range_key format. 
-      flags       Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
-                  NO_MAX_RANGE.
-      part_iter   Iterator structure to be initialized
+      part_info            Partitioning info
+      is_subpart
+      store_length_array   Length of fields packed in opt_range_key format
+      min_val              Left edge,  field value in opt_range_key format
+      max_val              Right edge, field value in opt_range_key format
+      min_len              Length of minimum value
+      max_len              Length of maximum value
+      flags                Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
+                           NO_MAX_RANGE
+      part_iter            Iterator structure to be initialized
 
   DESCRIPTION
     Functions with this signature are used to perform "Partitioning Interval
@@ -194,8 +202,9 @@ typedef struct st_partition_iter
     The set of partitions is returned by initializing an iterator in *part_iter
 
   NOTES
-    There are currently two functions of this type:
+    There are currently three functions of this type:
      - get_part_iter_for_interval_via_walking
+     - get_part_iter_for_interval_cols_via_map
      - get_part_iter_for_interval_via_mapping
 
   RETURN 
@@ -206,7 +215,9 @@ typedef struct st_partition_iter
 
 typedef int (*get_partitions_in_range_iter)(partition_info *part_info,
                                             bool is_subpart,
+                                            uint32 *store_length_array,
                                             uchar *min_val, uchar *max_val,
+                                            uint min_len, uint max_len,
                                             uint flags,
                                             PARTITION_ITERATOR *part_iter);
 

=== added file 'sql/sql_plugin_services.h'
--- a/sql/sql_plugin_services.h	1970-01-01 00:00:00 +0000
+++ b/sql/sql_plugin_services.h	2009-11-02 20:05:42 +0000
@@ -0,0 +1,44 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/* support for Services */
+#include <service_versions.h>
+
+struct st_service_ref {
+  const char *name;
+  uint version;
+  void *service;
+};
+
+static struct my_snprintf_service_st my_snprintf_handler = {
+  my_snprintf,
+  my_vsnprintf
+};
+
+static struct thd_alloc_service_st thd_alloc_handler= {
+  thd_alloc,
+  thd_calloc,
+  thd_strdup,
+  thd_strmake,
+  thd_memdup,
+  thd_make_lex_string
+};
+
+static struct st_service_ref list_of_services[]=
+{
+  { "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler },
+  { "thd_alloc_service",   VERSION_thd_alloc,   &thd_alloc_handler }
+};
+

=== removed file 'sql/sql_plugin_services.h'
--- a/sql/sql_plugin_services.h	2009-10-23 06:24:37 +0000
+++ b/sql/sql_plugin_services.h	1970-01-01 00:00:00 +0000
@@ -1,51 +0,0 @@
-#ifndef SQL_PLUGIN_SERVICES_INCLUDED
-#define SQL_PLUGIN_SERVICES_INCLUDED
-
-/* Copyright (C) 2009 Sun Microsystems, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-/* support for Services */
-
-#include <service_versions.h>
-
-struct st_service_ref {
-  const char *name;
-  uint version;
-  void *service;
-};
-
-#ifdef HAVE_DLOPEN
-static struct my_snprintf_service_st my_snprintf_handler = {
-  my_snprintf,
-  my_vsnprintf
-};
-
-static struct thd_alloc_service_st thd_alloc_handler= {
-  thd_alloc,
-  thd_calloc,
-  thd_strdup,
-  thd_strmake,
-  thd_memdup,
-  thd_make_lex_string
-};
-
-static struct st_service_ref list_of_services[]=
-{
-  { "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler },
-  { "thd_alloc_service",   VERSION_thd_alloc,   &thd_alloc_handler }
-};
-#endif /* HAVE_DLOPEN */
-
-#endif /* SQL_PLUGIN_SERVICES_INCLUDED */

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2009-11-03 18:07:29 +0000
+++ b/sql/sql_select.cc	2009-11-06 16:34:09 +0000

@@ -7312,8 +7312,8 @@ greedy_search(JOIN      *join,
       the interleaving state to the one of the non-extended partial plan 
       on exit.
     */
-    IF_DBUG(bool is_interleave_error= )
-    check_interleaving_with_nj (best_table);
+    bool is_interleave_error __attribute__((unused))= 
+      check_interleaving_with_nj (best_table);
     /* This has been already checked by best_extension_by_limited_search */
     DBUG_ASSERT(!is_interleave_error);
 
@@ -20477,7 +20477,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA
   Item *pos;
   List_iterator_fast<Item> li(all_fields);
   Copy_field *copy= NULL;
-  IF_DBUG(Copy_field *copy_start);
+  Copy_field *copy_start __attribute__((unused));
   res_selected_fields.empty();
   res_all_fields.empty();
   List_iterator_fast<Item> itr(res_all_fields);
@@ -20490,7 +20490,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PA
     goto err2;
 
   param->copy_funcs.empty();
-  IF_DBUG(copy_start= copy);
+  copy_start= copy;
   for (i= 0; (pos= li++); i++)
   {
     Field *field;

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2009-11-02 15:16:58 +0000
+++ b/sql/sql_show.cc	2009-11-04 09:02:10 +0000
@@ -26,6 +26,7 @@
 #include "sql_trigger.h"
 #include "authors.h"
 #include "contributors.h"
+#include "sql_partition.h"
 #ifdef HAVE_EVENT_SCHEDULER
 #include "events.h"
 #include "event_data_objects.h"
@@ -78,6 +79,12 @@ static TYPELIB grant_types = { sizeof(gr
 static void store_key_options(THD *thd, String *packet, TABLE *table,
                               KEY *key_info);
 
+static void get_cs_converted_string_value(THD *thd,
+                                          String *input_str,
+                                          String *output_str,
+                                          CHARSET_INFO *cs,
+                                          bool use_hex);
+
 static void
 append_algorithm(TABLE_LIST *table, String *buff);
 
@@ -1523,7 +1530,8 @@ int store_create_info(THD *thd, TABLE_LI
         ((part_syntax= generate_partition_syntax(table->part_info,
                                                   &part_syntax_len,
                                                   FALSE,
-                                                  show_table_options))))
+                                                  show_table_options,
+                                                  NULL, NULL))))
     {
        packet->append(STRING_WITH_LEN("\n/*!50100"));
        packet->append(part_syntax, part_syntax_len);
@@ -5359,6 +5367,57 @@ static void collect_partition_expr(List<
   }
   return;
 }
+
+
+/*
+  Convert a string in a given character set to a string which can be
+  used for FRM file storage in which case use_hex is TRUE and we store
+  the character constants as hex strings in the character set encoding
+  their field have. In the case of SHOW CREATE TABLE and the
+  PARTITIONS information schema table we instead provide utf8 strings
+  to the user and convert to the utf8 character set.
+
+  SYNOPSIS
+    get_cs_converted_part_value_from_string()
+    item                           Item from which constant comes
+    input_str                      String as provided by val_str after
+                                   conversion to character set
+    output_str                     Out value: The string created
+    cs                             Character set string is encoded in
+                                   NULL for INT_RESULT's here
+    use_hex                        TRUE => hex string created
+                                   FALSE => utf8 constant string created
+
+  RETURN VALUES
+    TRUE                           Error
+    FALSE                          Ok
+*/
+
+int get_cs_converted_part_value_from_string(THD *thd,
+                                            Item *item,
+                                            String *input_str,
+                                            String *output_str,
+                                            CHARSET_INFO *cs,
+                                            bool use_hex)
+{
+  if (item->result_type() == INT_RESULT)
+  {
+    longlong value= item->val_int();
+    output_str->set(value, system_charset_info);
+    return FALSE;
+  }
+  if (!input_str)
+  {
+    my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+    return TRUE;
+  }
+  get_cs_converted_string_value(thd,
+                                input_str,
+                                output_str,
+                                cs,
+                                use_hex);
+  return FALSE;
+}
 #endif
 
 
@@ -5440,6 +5499,49 @@ static void store_schema_partitions_reco
   return;
 }
 
+static int
+get_partition_column_description(THD *thd,
+                                 partition_info *part_info,
+                                 part_elem_value *list_value,
+                                 String &tmp_str)
+{
+  uint num_elements= part_info->part_field_list.elements;
+  uint i;
+  DBUG_ENTER("get_partition_column_description");
+
+  for (i= 0; i < num_elements; i++)
+  {
+    part_column_list_val *col_val= &list_value->col_val_array[i];
+    if (col_val->max_value)
+      tmp_str.append(partition_keywords[PKW_MAXVALUE].str);
+    else if (col_val->null_value)
+      tmp_str.append("NULL");
+    else
+    {
+      char buffer[MAX_KEY_LENGTH];
+      String str(buffer, sizeof(buffer), &my_charset_bin);
+      String val_conv;
+      Item *item= col_val->item_expression;
+
+      if (!(item= part_info->get_column_item(item,
+                              part_info->part_field_array[i])))
+      {
+        DBUG_RETURN(1);
+      }
+      String *res= item->val_str(&str);
+      if (get_cs_converted_part_value_from_string(thd, item, res, &val_conv,
+                              part_info->part_field_array[i]->charset(),
+                              FALSE))
+      {
+        DBUG_RETURN(1);
+      }
+      tmp_str.append(val_conv);
+    }
+    if (i != num_elements - 1)
+      tmp_str.append(",");
+  }
+  DBUG_RETURN(0);
+}
 
 static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
                                         TABLE *table, bool res,
@@ -5482,12 +5584,18 @@ static int get_schema_partitions_record(
     /* Partition method*/
     switch (part_info->part_type) {
     case RANGE_PARTITION:
-      table->field[7]->store(partition_keywords[PKW_RANGE].str,
-                             partition_keywords[PKW_RANGE].length, cs);
-      break;
     case LIST_PARTITION:
-      table->field[7]->store(partition_keywords[PKW_LIST].str,
-                             partition_keywords[PKW_LIST].length, cs);
+      tmp_res.length(0);
+      if (part_info->part_type == RANGE_PARTITION)
+        tmp_res.append(partition_keywords[PKW_RANGE].str,
+                       partition_keywords[PKW_RANGE].length);
+      else
+        tmp_res.append(partition_keywords[PKW_LIST].str,
+                       partition_keywords[PKW_LIST].length);
+      if (part_info->column_list)
+        tmp_res.append(partition_keywords[PKW_COLUMNS].str,
+                       partition_keywords[PKW_COLUMNS].length);
+      table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs);
       break;
     case HASH_PARTITION:
       tmp_res.length(0);
@@ -5564,36 +5672,70 @@ static int get_schema_partitions_record(
       /* Partition description */
       if (part_info->part_type == RANGE_PARTITION)
       {
-        if (part_elem->range_value != LONGLONG_MAX)
-          table->field[11]->store((longlong) part_elem->range_value, FALSE);
+        if (part_info->column_list)
+        {
+          List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
+          part_elem_value *list_value= list_val_it++;
+          tmp_str.length(0);
+          if (get_partition_column_description(thd,
+                                               part_info,
+                                               list_value,
+                                               tmp_str))
+          {
+            DBUG_RETURN(1);
+          }
+          table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
+        }
         else
-          table->field[11]->store(partition_keywords[PKW_MAXVALUE].str,
+        {
+          if (part_elem->range_value != LONGLONG_MAX)
+            table->field[11]->store((longlong) part_elem->range_value, FALSE);
+          else
+            table->field[11]->store(partition_keywords[PKW_MAXVALUE].str,
                                  partition_keywords[PKW_MAXVALUE].length, cs);
+        }
         table->field[11]->set_notnull();
       }
       else if (part_info->part_type == LIST_PARTITION)
       {
         List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
         part_elem_value *list_value;
-        uint no_items= part_elem->list_val_list.elements;
+        uint num_items= part_elem->list_val_list.elements;
         tmp_str.length(0);
         tmp_res.length(0);
         if (part_elem->has_null_value)
         {
           tmp_str.append("NULL");
-          if (no_items > 0)
+          if (num_items > 0)
             tmp_str.append(",");
         }
         while ((list_value= list_val_it++))
         {
-          if (!list_value->unsigned_flag)
-            tmp_res.set(list_value->value, cs);
+          if (part_info->column_list)
+          {
+            if (part_info->part_field_list.elements > 1U)
+              tmp_str.append("(");
+            if (get_partition_column_description(thd,
+                                                 part_info,
+                                                 list_value,
+                                                 tmp_str))
+            {
+              DBUG_RETURN(1);
+            }
+            if (part_info->part_field_list.elements > 1U)
+              tmp_str.append(")");
+          }
           else
-            tmp_res.set((ulonglong)list_value->value, cs);
-          tmp_str.append(tmp_res);
-          if (--no_items != 0)
+          {
+            if (!list_value->unsigned_flag)
+              tmp_res.set(list_value->value, cs);
+            else
+              tmp_res.set((ulonglong)list_value->value, cs);
+            tmp_str.append(tmp_res);
+          }
+          if (--num_items != 0)
             tmp_str.append(",");
-        };
+        }
         table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs);
         table->field[11]->set_notnull();
       }
@@ -7110,7 +7252,7 @@ ST_FIELD_INFO partitions_fields_info[]=
    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
   {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
    (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
-  {"PARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
+  {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
   {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
   {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
   {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0,
@@ -7770,3 +7912,95 @@ bool show_create_trigger(THD *thd, const
     status and client connection will be closed.
   */
 }
+
+/*
+  Convert a string in character set in column character set format
+  to utf8 character set if possible, the utf8 character set string
+  will later possibly be converted to character set used by client.
+  Thus we attempt conversion from column character set to both
+  utf8 and to character set client.
+
+  Examples of strings that should fail conversion to utf8 are unassigned
+  characters as e.g. 0x81 in cp1250 (Windows character set for for countries
+  like Czech and Poland). Example of string that should fail conversion to
+  character set on client (e.g. if this is latin1) is 0x2020 (daggger) in
+  ucs2.
+
+  If the conversion fails we will as a fall back convert the string to
+  hex encoded format. The caller of the function can also ask for hex
+  encoded format of output string unconditionally.
+
+  SYNOPSIS
+    get_cs_converted_string_value()
+    thd                             Thread object
+    input_str                       Input string in cs character set
+    output_str                      Output string to be produced in utf8
+    cs                              Character set of input string
+    use_hex                         Use hex string unconditionally
+ 
+
+  RETURN VALUES
+    No return value
+*/
+
+static void get_cs_converted_string_value(THD *thd,
+                                          String *input_str,
+                                          String *output_str,
+                                          CHARSET_INFO *cs,
+                                          bool use_hex)
+{
+
+  output_str->length(0);
+  if (input_str->length() == 0)
+  {
+    output_str->append("''");
+    return;
+  }
+  if (!use_hex)
+  {
+    String try_val;
+    uint try_conv_error= 0;
+
+    try_val.copy(input_str->ptr(), input_str->length(), cs,
+                 thd->variables.character_set_client, &try_conv_error);
+    if (!try_conv_error)
+    {
+      String val;
+      uint conv_error= 0;
+
+      val.copy(input_str->ptr(), input_str->length(), cs,
+               system_charset_info, &conv_error);
+      if (!conv_error)
+      {
+        append_unescaped(output_str, val.ptr(), val.length());
+        return;
+      }
+    }
+    /* We had a conversion error, use hex encoded string for safety */
+  }
+  {
+    const uchar *ptr;
+    uint i, len;
+    char buf[3];
+
+    output_str->append("_");
+    output_str->append(cs->csname);
+    output_str->append(" ");
+    output_str->append("0x");
+    len= input_str->length();
+    ptr= (uchar*)input_str->ptr();
+    for (i= 0; i < len; i++)
+    {
+      uint high, low;
+
+      high= (*ptr) >> 4;
+      low= (*ptr) & 0x0F;
+      buf[0]= _dig_vec_upper[high];
+      buf[1]= _dig_vec_upper[low];
+      buf[2]= 0;
+      output_str->append((const char*)buf);
+      ptr++;
+    }
+  }
+  return;
+}

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2009-11-03 09:42:49 +0000
+++ b/sql/sql_table.cc	2009-11-06 16:34:09 +0000
@@ -1587,7 +1587,9 @@ bool mysql_write_frm(ALTER_PARTITION_PAR
       {
         if (!(part_syntax_buf= generate_partition_syntax(part_info,
                                                          &syntax_len,
-                                                         TRUE, TRUE)))
+                                                         TRUE, TRUE,
+                                                         lpt->create_info,
+                                                         lpt->alter_info)))
         {
           DBUG_RETURN(TRUE);
         }
@@ -1679,7 +1681,9 @@ bool mysql_write_frm(ALTER_PARTITION_PAR
       char *tmp_part_syntax_str;
       if (!(part_syntax_buf= generate_partition_syntax(part_info,
                                                        &syntax_len,
-                                                       TRUE, TRUE)))
+                                                       TRUE, TRUE,
+                                                       lpt->create_info,
+                                                       lpt->alter_info)))
       {
         error= 1;
         goto err;
@@ -2585,6 +2589,39 @@ int prepare_create_field(Create_field *s
   DBUG_RETURN(0);
 }
 
+
+/*
+  Get character set from field object generated by parser using
+  default values when not set.
+
+  SYNOPSIS
+    get_sql_field_charset()
+    sql_field                 The sql_field object
+    create_info               Info generated by parser
+
+  RETURN VALUES
+    cs                        Character set
+*/
+
+CHARSET_INFO* get_sql_field_charset(Create_field *sql_field,
+                                    HA_CREATE_INFO *create_info)
+{
+  CHARSET_INFO *cs= sql_field->charset;
+
+  if (!cs)
+    cs= create_info->default_table_charset;
+  /*
+    table_charset is set only in ALTER TABLE t1 CONVERT TO CHARACTER SET csname
+    if we want change character set for all varchar/char columns.
+    But the table charset must not affect the BLOB fields, so don't
+    allow to change my_charset_bin to somethig else.
+  */
+  if (create_info->table_charset && cs != &my_charset_bin)
+    cs= create_info->table_charset;
+  return cs;
+}
+
+
 /*
   Preparation for table creation
 
@@ -2648,18 +2685,8 @@ mysql_prepare_create_table(THD *thd, HA_
       executing a prepared statement for the second time.
     */
     sql_field->length= sql_field->char_length;
-    if (!sql_field->charset)
-      sql_field->charset= create_info->default_table_charset;
-    /*
-      table_charset is set in ALTER TABLE if we want change character set
-      for all varchar/char columns.
-      But the table charset must not affect the BLOB fields, so don't
-      allow to change my_charset_bin to somethig else.
-    */
-    if (create_info->table_charset && sql_field->charset != &my_charset_bin)
-      sql_field->charset= create_info->table_charset;
-
-    save_cs= sql_field->charset;
+    save_cs= sql_field->charset= get_sql_field_charset(sql_field,
+                                                       create_info);
     if ((sql_field->flags & BINCMP_FLAG) &&
         !(sql_field->charset= get_charset_by_csname(sql_field->charset->csname,
                                                     MY_CS_BINSORT,MYF(0))))
@@ -3706,6 +3733,9 @@ bool mysql_create_table_no_lock(THD *thd
   }
   if (check_engine(thd, table_name, create_info))
     DBUG_RETURN(TRUE);
+
+  set_table_default_charset(thd, create_info, (char*) db);
+
   db_options= create_info->table_options;
   if (create_info->row_type != ROW_TYPE_FIXED &&
       create_info->row_type != ROW_TYPE_DEFAULT)
@@ -3800,7 +3830,7 @@ bool mysql_create_table_no_lock(THD *thd
              ha_resolve_storage_engine_name(part_info->default_engine_type),
              ha_resolve_storage_engine_name(create_info->db_type)));
     if (part_info->check_partition_info(thd, &engine_type, file,
-                                        create_info, TRUE))
+                                        create_info, FALSE))
       goto err;
     part_info->default_engine_type= engine_type;
 
@@ -3810,7 +3840,9 @@ bool mysql_create_table_no_lock(THD *thd
     */
     if (!(part_syntax_buf= generate_partition_syntax(part_info,
                                                      &syntax_len,
-                                                     TRUE, TRUE)))
+                                                     TRUE, TRUE,
+                                                     create_info,
+                                                     alter_info)))
       goto err;
     part_info->part_info_string= part_syntax_buf;
     part_info->part_info_len= syntax_len;
@@ -3836,9 +3868,9 @@ bool mysql_create_table_no_lock(THD *thd
         creates a proper .par file. The current part_info object is
         only used to create the frm-file and .par-file.
       */
-      if (part_info->use_default_no_partitions &&
-          part_info->no_parts &&
-          (int)part_info->no_parts !=
+      if (part_info->use_default_num_partitions &&
+          part_info->num_parts &&
+          (int)part_info->num_parts !=
           file->get_default_no_partitions(create_info))
       {
         uint i;
@@ -3849,13 +3881,13 @@ bool mysql_create_table_no_lock(THD *thd
           (part_it++)->part_state= PART_TO_BE_DROPPED;
       }
       else if (part_info->is_sub_partitioned() &&
-               part_info->use_default_no_subpartitions &&
-               part_info->no_subparts &&
-               (int)part_info->no_subparts !=
+               part_info->use_default_num_subpartitions &&
+               part_info->num_subparts &&
+               (int)part_info->num_subparts !=
                  file->get_default_no_partitions(create_info))
       {
         DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
-        part_info->no_subparts= file->get_default_no_partitions(create_info);
+        part_info->num_subparts= file->get_default_no_partitions(create_info);
       }
     }
     else if (create_info->db_type != engine_type)
@@ -3877,8 +3909,6 @@ bool mysql_create_table_no_lock(THD *thd
   }
 #endif
 
-  set_table_default_charset(thd, create_info, (char*) db);
-
   if (mysql_prepare_create_table(thd, create_info, alter_info,
                                  internal_tmp_table,
                                  &db_options, file,
@@ -4569,11 +4599,11 @@ static bool mysql_admin_table(THD* thd, 
             my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
             DBUG_RETURN(TRUE);
           }
-          uint no_parts_found;
-          uint no_parts_opt= alter_info->partition_names.elements;
-          no_parts_found= set_part_state(alter_info, table->table->part_info,
-                                         PART_ADMIN);
-          if (no_parts_found != no_parts_opt &&
+          uint num_parts_found;
+          uint num_parts_opt= alter_info->partition_names.elements;
+          num_parts_found= set_part_state(alter_info, table->table->part_info,
+                                          PART_ADMIN);
+          if (num_parts_found != num_parts_opt &&
               (!(alter_info->flags & ALTER_ALL_PARTITION)))
           {
             char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE];
@@ -5245,7 +5275,7 @@ bool mysql_create_like_table(THD* thd, T
                        MYSQL_OPEN_REOPEN))
           goto err;
 
-        IF_DBUG(int result=)
+        int result __attribute__((unused))=
           store_create_info(thd, table, &query,
                             create_info, FALSE /* show_database */);
 

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2009-11-03 09:42:49 +0000
+++ b/sql/sql_yacc.yy	2009-11-06 16:34:09 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -1295,9 +1295,6 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %type <ulonglong_number>
         ulonglong_num real_ulonglong_num size_number
 
-%type <p_elem_value>
-        part_bit_expr
-
 %type <lock_type>
         replace_lock_option opt_low_priority insert_lock_option load_data_lock
         transactional_lock_mode
@@ -1443,6 +1440,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
         view_check_option trigger_tail sp_tail sf_tail udf_tail event_tail
         install uninstall partition_entry binlog_base64_event
         init_key_options key_options key_opts key_opt key_using_alg
+        part_column_list
         server_def server_options_list server_option
         definer_opt no_definer definer opt_compression
         opt_compression_algorithm
@@ -4186,25 +4184,28 @@ partition_entry:
         ;
 
 partition:
-          BY part_type_def opt_no_parts opt_sub_part part_defs
+          BY part_type_def opt_num_parts opt_sub_part part_defs
         ;
 
 part_type_def:
           opt_linear KEY_SYM '(' part_field_list ')'
           {
-            LEX *lex= Lex;
-            lex->part_info->list_of_part_fields= TRUE;
-            lex->part_info->part_type= HASH_PARTITION;
+            partition_info *part_info= Lex->part_info;
+            part_info->list_of_part_fields= TRUE;
+            part_info->column_list= FALSE;
+            part_info->part_type= HASH_PARTITION;
           }
         | opt_linear HASH_SYM
           { Lex->part_info->part_type= HASH_PARTITION; }
           part_func {}
-        | RANGE_SYM
+        | RANGE_SYM part_func
           { Lex->part_info->part_type= RANGE_PARTITION; }
-          part_func {}
-        | LIST_SYM
+        | RANGE_SYM part_column_list
+          { Lex->part_info->part_type= RANGE_PARTITION; }
+        | LIST_SYM part_func
+          { Lex->part_info->part_type= LIST_PARTITION; }
+        | LIST_SYM part_column_list
           { Lex->part_info->part_type= LIST_PARTITION; }
-          part_func {}
         ;
 
 opt_linear:
@@ -4226,59 +4227,66 @@ part_field_item_list:
 part_field_item:
           ident
           {
-            if (Lex->part_info->part_field_list.push_back($1.str))
+            partition_info *part_info= Lex->part_info;
+            part_info->num_columns++;
+            if (part_info->part_field_list.push_back($1.str))
             {
               mem_alloc_error(1);
               MYSQL_YYABORT;
             }
+            if (part_info->num_columns > MAX_REF_PARTS)
+            {
+              my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0),
+                       "list of partition fields");
+              MYSQL_YYABORT;
+            }
+          }
+        ;
+
+part_column_list:
+          COLUMNS '(' part_field_list ')'
+          {
+            partition_info *par