List:Internals« Previous MessageNext Message »
From:mikael Date:April 5 2005 5:34pm
Subject:bk commit into 5.0 tree (mronstrom:1.1873)
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of mikron. When mikron does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1873 05/04/05 17:34:22 mronstrom@stripped +26 -0
  Manual merge

  sql/unireg.cc
    1.57 05/04/05 17:34:13 mronstrom@stripped +9 -8
    Manual merge

  sql/sql_yacc.yy
    1.350 05/04/05 17:34:13 mronstrom@stripped +0 -1
    Manual merge

  sql/share/errmsg.txt
    1.25 05/04/05 17:34:13 mronstrom@stripped +8 -12
    Manual merge

  sql/mysql_priv.h
    1.257 05/04/05 17:34:13 mronstrom@stripped +2 -3
    Manual merge

  sql/handler.h
    1.143 05/04/05 17:34:13 mronstrom@stripped +1 -1
    Manual merge

  BitKeeper/deleted/.del-errmsg.txt~ef53c33ac0ff8a84
    1.125 05/04/05 17:34:12 mronstrom@stripped +1 -2
    Manual merge

  BitKeeper/deleted/.del-errmsg.txt~8ed1999cbd481dc4
    1.90 05/04/05 17:34:12 mronstrom@stripped +1 -2
    Manual merge

  sql/table.h
    1.93 05/04/05 15:01:20 mronstrom@stripped +0 -0
    Auto merged

  sql/table.cc
    1.174 05/04/05 15:01:20 mronstrom@stripped +0 -0
    Auto merged

  sql/sql_update.cc
    1.154 05/04/05 15:01:19 mronstrom@stripped +0 -0
    Auto merged

  sql/sql_table.cc
    1.217 05/04/05 15:01:18 mronstrom@stripped +0 -0
    Auto merged

  sql/sql_select.cc
    1.309 05/04/05 15:01:17 mronstrom@stripped +0 -0
    Auto merged

  sql/sql_lex.h
    1.164 05/04/05 15:01:15 mronstrom@stripped +0 -0
    Auto merged

  sql/sql_lex.cc
    1.134 05/04/05 15:01:15 mronstrom@stripped +0 -0
    Auto merged

  sql/sql_base.cc
    1.209 05/04/05 15:01:14 mronstrom@stripped +0 -0
    Auto merged

  sql/set_var.cc
    1.87 05/04/05 15:01:13 mronstrom@stripped +0 -0
    Auto merged

  sql/mysqld.cc
    1.422 05/04/05 15:01:12 mronstrom@stripped +0 -0
    Auto merged

  sql/handler.cc
    1.142 05/04/05 15:01:09 mronstrom@stripped +0 -0
    Auto merged

  sql/ha_ndbcluster.h
    1.80 05/04/05 15:01:09 mronstrom@stripped +0 -0
    Auto merged

  sql/ha_ndbcluster.cc
    1.170 05/04/05 15:01:08 mronstrom@stripped +0 -0
    Auto merged

  sql/field.h
    1.141 05/04/05 15:01:08 mronstrom@stripped +0 -0
    Auto merged

  sql/field.cc
    1.226 05/04/05 15:01:07 mronstrom@stripped +0 -0
    Auto merged

  sql/Makefile.am
    1.104 05/04/05 15:01:06 mronstrom@stripped +0 -0
    Auto merged

  BitKeeper/deleted/.del-errmsg.txt~f96b7055cac394e
    1.136 05/04/05 15:01:06 mronstrom@stripped +0 -0
    Auto merged

  configure.in
    1.252 05/04/05 15:01:05 mronstrom@stripped +0 -0
    Auto merged

  BitKeeper/etc/logging_ok
    1.304 05/04/05 14:59:10 mronstrom@stripped +0 -0
    auto-union

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	mronstrom
# Host:	mikael-ronstr-ms-dator.local
# Root:	/Users/mikron/wl1354_new/RESYNC

--- 1.251/configure.in	Tue Mar  1 22:38:49 2005
+++ 1.252/configure.in	Tue Apr  5 15:01:05 2005
@@ -6,7 +6,7 @@
 AC_INIT(sql/mysqld.cc)
 AC_CANONICAL_SYSTEM
 # Don't forget to also update the NDB lines below.
-AM_INIT_AUTOMAKE(mysql, 5.0.3-alpha)
+AM_INIT_AUTOMAKE(mysql, 5.0.4-beta)
 AM_CONFIG_HEADER(config.h)
 
 PROTOCOL_VERSION=10
@@ -17,8 +17,8 @@
 # ndb version
 NDB_VERSION_MAJOR=5
 NDB_VERSION_MINOR=0
-NDB_VERSION_BUILD=3
-NDB_VERSION_STATUS="alpha"
+NDB_VERSION_BUILD=4
+NDB_VERSION_STATUS="beta"
 
 # Set all version vars based on $VERSION. How do we do this more elegant ?
 # Remember that regexps needs to quote [ and ] since this is run through m4
@@ -37,6 +37,7 @@
 sinclude(config/ac-macros/compiler_flag.m4)
 sinclude(config/ac-macros/ha_archive.m4)
 sinclude(config/ac-macros/ha_berkeley.m4)
+sinclude(config/ac-macros/ha_blackhole.m4)
 sinclude(config/ac-macros/ha_example.m4)
 sinclude(config/ac-macros/ha_federated.m4)
 sinclude(config/ac-macros/ha_innodb.m4)
@@ -46,7 +47,6 @@
 sinclude(config/ac-macros/ha_tina.m4)
 sinclude(config/ac-macros/large_file.m4)
 sinclude(config/ac-macros/misc.m4)
-sinclude(config/ac-macros/mysqlfs.m4)
 sinclude(config/ac-macros/openssl.m4)
 sinclude(config/ac-macros/readline.m4)
 sinclude(config/ac-macros/zlib.m4)
@@ -352,10 +352,21 @@
 
   if echo $CXX | grep gcc > /dev/null 2>&1
   then
-    if $CXX -v 2>&1 | grep 'version 3' > /dev/null 2>&1
-    then
-      CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL"
-    fi
+    GCC_VERSION=`gcc -v 2>&1 | grep version | sed -e 's/[[^0-9. ]]//g; s/^ *//g;
s/ .*//g'`
+    echo "Using gcc version '$GCC_VERSION'"
+    case "$GCC_VERSION" in
+      3.4.*|3.5.*)
+        # Statically link the language support function's found in libsupc++.a
+        LIBS="$LIBS -lsupc++"
+	echo "Using -libsupc++ for static linking with gcc"
+      ;;
+      *)
+        # Using -lsupc++ doesn't work in gcc 3.3 on SuSE 9.2
+        # (causes link failures when linking things staticly)
+        CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL"
+	echo "Using MYSYS_NEW for static linking with gcc"
+      ;;
+    esac
   fi
 fi
 
@@ -581,18 +592,6 @@
     )
 AC_SUBST(MYSQL_SERVER_SUFFIX)
 
-# Set flags if we wants to have MIT threads.
-AC_ARG_WITH(mit-threads,
-    [  --with-mit-threads      Always use included thread lib.],
-    [ with_mit_threads=$withval ],
-    [ with_mit_threads=no ]
-    )
-
-if test "$with_mit_threads" = "yes"
-then
-  enable_largefile="no"		# Will not work on Linux.
-fi
-
 # Set flags if we want to force to use pthreads
 AC_ARG_WITH(pthread,
     [  --with-pthread          Force use of pthread library.],
@@ -649,20 +648,6 @@
 fi
 
 
-AC_MSG_CHECKING(if we should use RAID)
-AC_ARG_WITH(raid,
-    [  --with-raid             Enable RAID Support],
-    [   USE_RAID=$withval ],
-    [   USE_RAID=no ]
-    )
-if test "$USE_RAID" = "yes"
-then
-  AC_MSG_RESULT([yes])
-  AC_DEFINE([USE_RAID], [1], [Use MySQL RAID])
-else
-  AC_MSG_RESULT([no])
-fi
-
 # Use this to set the place used for unix socket used to local communication.
 AC_ARG_WITH(unix-socket-path,
     [  --with-unix-socket-path=SOCKET
@@ -857,7 +842,7 @@
     [ USE_PSTACK=no ])
   pstack_libs=
   pstack_dirs=
-  if test "$USE_PSTACK" = yes -a "$IS_LINUX" = "true" -a "$BASE_MACHINE_TYPE" = "i386" -a
"$with_mit_threads" = "no"
+  if test "$USE_PSTACK" = yes -a "$IS_LINUX" = "true" -a "$BASE_MACHINE_TYPE" = "i386"
   then
     have_libiberty= have_libbfd=
     my_save_LIBS="$LIBS"
@@ -1240,7 +1225,7 @@
 
 with_posix_threads="no"
 # Hack for DEC-UNIX (OSF1)
-if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
+if test "$with_named_thread" = "no"
 then
   # Look for LinuxThreads.
   AC_MSG_CHECKING("LinuxThreads")
@@ -1471,7 +1456,7 @@
 fi
 
 # Hack for Siemens UNIX
-if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
+if test "$with_named_thread" = "no"
 then
   AC_MSG_CHECKING("Siemens threads")
   if test -f /usr/lib/libxnet.so -a "$SYSTEM_TYPE" = "sni-sysv4"
@@ -1499,7 +1484,7 @@
 # Hack for Solaris >= 2.5
 # We want both the new and the old interface
  
-if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
+if test "$with_named_thread" = "no"
 then
   AC_MSG_CHECKING("Solaris threads")
   if test -f /usr/lib/libpthread.so -a -f /usr/lib/libthread.so
@@ -1517,14 +1502,21 @@
 then
   LIBS="$with_named_thread $LIBS $with_named_thread"
   with_posix_threads="yes"
-  with_mit_threads="no"
   AC_MSG_RESULT("$with_named_thread")
 else
   AC_MSG_RESULT("no")
-  if test "$with_mit_threads" = "no"
+  # pthread_create is in standard libraries (As in BSDI 3.0)
+  AC_MSG_CHECKING("for pthread_create in -libc");
+  AC_TRY_LINK(
+  [#include <pthread.h>],
+  [ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
+  with_posix_threads=yes, with_posix_threads=no)
+  AC_MSG_RESULT("$with_posix_threads")
+  if test "$with_posix_threads" = "no"
   then
-    # pthread_create is in standard libraries (As in BSDI 3.0)
-    AC_MSG_CHECKING("for pthread_create in -libc");
+    AC_MSG_CHECKING("for pthread_create in -lpthread");
+    ac_save_LIBS="$LIBS"
+    LIBS="$LIBS -lpthread"
     AC_TRY_LINK(
     [#include <pthread.h>],
     [ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
@@ -1532,39 +1524,23 @@
     AC_MSG_RESULT("$with_posix_threads")
     if test "$with_posix_threads" = "no"
     then
-      AC_MSG_CHECKING("for pthread_create in -lpthread");
-      ac_save_LIBS="$LIBS"
-      LIBS="$LIBS -lpthread"
+      LIBS=" $ac_save_LIBS -lpthreads"
+      AC_MSG_CHECKING("for pthread_create in -lpthreads");
       AC_TRY_LINK(
       [#include <pthread.h>],
-      [ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
+      [ pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
       with_posix_threads=yes, with_posix_threads=no)
       AC_MSG_RESULT("$with_posix_threads")
       if test "$with_posix_threads" = "no"
       then
-        LIBS=" $ac_save_LIBS -lpthreads"
-        AC_MSG_CHECKING("for pthread_create in -lpthreads");
+        # This is for FreeBSD
+        LIBS="$ac_save_LIBS -pthread"
+        AC_MSG_CHECKING("for pthread_create in -pthread");
         AC_TRY_LINK(
         [#include <pthread.h>],
         [ pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
         with_posix_threads=yes, with_posix_threads=no)
         AC_MSG_RESULT("$with_posix_threads")
-        if test "$with_posix_threads" = "no"
-        then
-	  # This is for FreeBSD
-	  LIBS="$ac_save_LIBS -pthread"
-	  AC_MSG_CHECKING("for pthread_create in -pthread");
-	  AC_TRY_LINK(
-	  [#include <pthread.h>],
-	  [ pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
-	  with_posix_threads=yes, with_posix_threads=no)
-          AC_MSG_RESULT("$with_posix_threads")
-          if test "$with_posix_threads" = "no"
-	  then
-	    with_mit_threads="yes"
-	    LIBS="$ac_save_LIBS"
-	  fi
-	fi
       fi
     fi
   fi
@@ -1816,7 +1792,13 @@
 AC_TYPE_SIGNAL
 AC_CHECK_FUNCS(re_comp regcomp strdup)
 
-AC_CHECK_HEADERS(vis.h)
+dnl Sun compilers have their own vis.h that is about something
+dnl totally different. So, not to change the libedit source, we
+dnl do some additional checks before we define HAVE_VIS_H.
+AC_CHECK_HEADER(vis.h,
+  [AC_CHECK_FUNC(strvis,
+    [AC_DEFINE([HAVE_VIS_H], [1],[Found vis.h and the strvis() function])])])
+
 AC_CHECK_FUNCS(strlcat strlcpy)
 AC_CHECK_FUNCS(issetugid)
 AC_CHECK_FUNCS(fgetln)
@@ -2043,11 +2025,9 @@
 fi
 
 
-if test "$with_mit_threads" = "no"
-then
-  # Check definition of pthread_getspecific
-  AC_CACHE_CHECK("args to pthread_getspecific", mysql_cv_getspecific_args,
-  AC_TRY_COMPILE(
+# Check definition of pthread_getspecific
+AC_CACHE_CHECK("args to pthread_getspecific", mysql_cv_getspecific_args,
+AC_TRY_COMPILE(
 [#if !defined(SCO) && !defined(__osf__) && !defined(_REENTRANT)
 #define _REENTRANT
 #endif
@@ -2080,7 +2060,6 @@
     AC_DEFINE([HAVE_NONPOSIX_PTHREAD_MUTEX_INIT], [1],
               [For some non posix threads])
   fi
-fi
 #---END:
 
 #---START: Used in for client configure
@@ -2257,7 +2236,6 @@
 AC_SUBST(tools_dirs)
 
 #MYSQL_CHECK_CPU
-MYSQL_CHECK_MYSQLFS
 MYSQL_CHECK_VIO
 MYSQL_CHECK_OPENSSL
 
@@ -2407,11 +2385,13 @@
 AC_SUBST(readline_link)
 AC_SUBST(readline_h_ln_cmd)
 
+MYSQL_CHECK_BIG_TABLES
 MYSQL_CHECK_BDB
 MYSQL_CHECK_INNODB
 MYSQL_CHECK_EXAMPLEDB
 MYSQL_CHECK_ARCHIVEDB
 MYSQL_CHECK_CSVDB
+MYSQL_CHECK_BLACKHOLEDB
 MYSQL_CHECK_NDBCLUSTER
 MYSQL_CHECK_FEDERATED
 MYSQL_CHECK_PARTITIONDB
@@ -2573,28 +2553,6 @@
   #
   sql_server_dirs="$sql_server_dirs myisam myisammrg heap vio sql"
 
-  if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes"
-  then
-    # MIT user level threads
-    thread_dirs="mit-pthreads"
-    AC_DEFINE([HAVE_mit_thread], [1], [Do we use user level threads])
-    MT_INCLUDES="-I\$(top_srcdir)/mit-pthreads/include"
-    AC_SUBST(MT_INCLUDES)
-    if test -n "$OVERRIDE_MT_LD_ADD"
-    then 
-      MT_LD_ADD="$OVERRIDE_MT_LD_ADD"
-    else
-      MT_LD_ADD="-L \$(top_srcdir)/mit-pthreads/obj/ -lpthread"
-    fi
-    AC_SUBST(MT_LD_ADD)
-    echo ""
-    echo "Configuring MIT Pthreads"
-    # We will never install so installation paths are not needed.
-    (cd mit-pthreads && sh ./configure) || exit 1
-    echo "End of MIT Pthreads configuration"
-    echo ""
-    LIBS="$MT_LD_ADD $LIBS"
-  fi
 fi
 
 # IMPORTANT - do not modify LIBS past this line - this hack is the only way
@@ -2621,12 +2579,6 @@
   fi
 done
 AC_SUBST(sql_union_dirs)
-
-#if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes"
-#then
-  # MIT pthreads does now support connecting with unix sockets
-  # AC_DEFINE([HAVE_THREADS_WITHOUT_SOCKETS], [], [MIT pthreads does not support
connecting with unix sockets])
-#fi
 
 # Some usefull subst
 AC_SUBST(CC)

--- 1.103/sql/Makefile.am	Sat Feb 12 19:22:54 2005
+++ 1.104/sql/Makefile.am	Tue Apr  5 15:01:06 2005
@@ -19,7 +19,7 @@
 MYSQLDATAdir =		$(localstatedir)
 MYSQLSHAREdir =		$(pkgdatadir)
 MYSQLBASEdir=		$(prefix)
-INCLUDES =		@MT_INCLUDES@ @ZLIB_INCLUDES@ \
+INCLUDES =		@ZLIB_INCLUDES@ \
 			@bdb_includes@ @innodb_includes@ @ndbcluster_includes@ \
 			-I$(top_srcdir)/include -I$(top_srcdir)/regex \
 			-I$(srcdir) $(openssl_includes) -I$(top_builddir)/include
@@ -49,7 +49,7 @@
 			mysql_priv.h item_geofunc.h sql_bitmap.h \
 			procedure.h sql_class.h sql_lex.h sql_list.h \
 			sql_manager.h sql_map.h sql_string.h unireg.h \
-			field.h handler.h mysqld_suffix.h \
+			sql_error.h field.h handler.h mysqld_suffix.h \
 			ha_myisammrg.h\
 			ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \
 			ha_ndbcluster.h opt_range.h protocol.h \
@@ -62,9 +62,8 @@
 			sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
 			parse_file.h sql_view.h	sql_trigger.h \
 			examples/ha_example.h examples/ha_archive.h \
-			examples/ha_tina.h \
+			examples/ha_tina.h ha_blackhole.h  \
 			ha_federated.h ha_partition.h
-
 mysqld_SOURCES =	sql_lex.cc sql_handler.cc \
 			item.cc item_sum.cc item_buff.cc item_func.cc \
 			item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -99,7 +98,7 @@
 			sp_head.cc sp_pcontext.cc  sp_rcontext.cc sp.cc \
 			sp_cache.cc parse_file.cc sql_trigger.cc \
 			examples/ha_example.cc examples/ha_archive.cc \
-			examples/ha_tina.cc \
+			examples/ha_tina.cc ha_blackhole.cc \
 			ha_federated.cc ha_partition.cc
 
 gen_lex_hash_SOURCES =	gen_lex_hash.cc

--- 1.225/sql/field.cc	Tue Mar  1 22:38:49 2005
+++ 1.226/sql/field.cc	Tue Apr  5 15:01:07 2005
@@ -48,6 +48,936 @@
 
 #define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE 320
 
+/*
+  Rules for merging different types of fields in UNION
+
+  NOTE: to avoid 256*256 table, gap in table types numeration is skiped
+  following #defines describe that gap and how to canculate number of fields
+  and index of field in thia array.
+*/
+#define FIELDTYPE_TEAR_FROM (MYSQL_TYPE_BIT + 1)
+#define FIELDTYPE_TEAR_TO   (MYSQL_TYPE_NEWDECIMAL - 1)
+#define FIELDTYPE_NUM (FIELDTYPE_TEAR_FROM + (255 - FIELDTYPE_TEAR_TO))
+inline int field_type2index (enum_field_types field_type)
+{
+  return (field_type < FIELDTYPE_TEAR_FROM ?
+          field_type :
+          ((int)FIELDTYPE_TEAR_FROM) + (field_type - FIELDTYPE_TEAR_TO) - 1);
+}
+
+static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
+{
+  /* MYSQL_TYPE_DECIMAL -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_NEWDECIMAL,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_NEWDECIMAL,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_DECIMAL,     MYSQL_TYPE_DECIMAL,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_TINY -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_TINY,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_SHORT,       MYSQL_TYPE_LONG,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_FLOAT,       MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_TINY,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_LONGLONG,    MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_SHORT -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_SHORT,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_SHORT,       MYSQL_TYPE_LONG,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_FLOAT,       MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_SHORT,       MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_LONGLONG,    MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_SHORT,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_LONG -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_LONG,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_LONG,        MYSQL_TYPE_LONG,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_LONG,         MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_LONGLONG,    MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_LONG,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_FLOAT -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_FLOAT,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_FLOAT,       MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_FLOAT,       MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_FLOAT,       MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_FLOAT,       MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_FLOAT,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_DOUBLE -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_NULL -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_TINY,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_SHORT,       MYSQL_TYPE_LONG,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_FLOAT,       MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_NULL,        MYSQL_TYPE_TIMESTAMP,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_LONGLONG,    MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_TIME,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_YEAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_BIT,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_ENUM,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_SET,         MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_GEOMETRY
+  },
+  /* MYSQL_TYPE_TIMESTAMP -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_TIMESTAMP,   MYSQL_TYPE_TIMESTAMP,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_DATETIME,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_LONGLONG -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_LONGLONG,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_LONGLONG,    MYSQL_TYPE_LONGLONG,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_LONGLONG,    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_LONGLONG,    MYSQL_TYPE_LONG,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_LONGLONG,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_INT24 -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_INT24,       MYSQL_TYPE_LONG,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_FLOAT,       MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_INT24,       MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_LONGLONG,    MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL    MYSQL_TYPE_ENUM
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_DATE -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_DATETIME,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_DATETIME,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,  MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_TIME -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_TIME,        MYSQL_TYPE_DATETIME,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_TIME,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_DATETIME -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_DATETIME,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_DATETIME,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_YEAR -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_DECIMAL,     MYSQL_TYPE_TINY,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_SHORT,       MYSQL_TYPE_LONG,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_FLOAT,       MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_YEAR,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_LONGLONG,    MYSQL_TYPE_INT24,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_YEAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_NEWDATE -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_DATETIME,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_DATETIME,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_DATETIME,    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_NEWDATE,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_VARCHAR -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_BIT -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_BIT,         MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_BIT,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_NEWDECIMAL -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_NEWDECIMAL,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_NEWDECIMAL,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_DOUBLE,      MYSQL_TYPE_DOUBLE,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_NEWDECIMAL,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_NEWDECIMAL,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_NEWDECIMAL,  MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_ENUM -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_ENUM,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_SET -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_SET,         MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_TINY_BLOB -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_TINY_BLOB,   MYSQL_TYPE_TINY_BLOB
+  },
+  /* MYSQL_TYPE_MEDIUM_BLOB -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB
+  },
+  /* MYSQL_TYPE_LONG_BLOB -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_LONG_BLOB,   MYSQL_TYPE_LONG_BLOB
+  },
+  /* MYSQL_TYPE_BLOB -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_BLOB
+  },
+  /* MYSQL_TYPE_VAR_STRING -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR
+  },
+  /* MYSQL_TYPE_STRING -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_STRING,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_STRING,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_STRING,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_STRING,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_STRING,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_STRING,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_STRING,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_STRING,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_STRING,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_STRING
+  },
+  /* MYSQL_TYPE_GEOMETRY -> */
+  {
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+    MYSQL_TYPE_GEOMETRY,    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_BIT          <16>-<245>
+    MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+    MYSQL_TYPE_VARCHAR,     MYSQL_TYPE_TINY_BLOB,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+    MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+    MYSQL_TYPE_BLOB,        MYSQL_TYPE_VARCHAR,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+    MYSQL_TYPE_STRING,      MYSQL_TYPE_GEOMETRY
+  }
+};
+
+/*
+  Return type of which can carry value of both given types in UNION result
+
+  SYNOPSIS
+    Field::field_type_merge()
+    a, b  types for merging
+
+  RETURN
+    type of field
+*/
+
+enum_field_types Field::field_type_merge(enum_field_types a,
+                                         enum_field_types b)
+{
+  DBUG_ASSERT(a < FIELDTYPE_TEAR_FROM || a > FIELDTYPE_TEAR_TO);
+  DBUG_ASSERT(b < FIELDTYPE_TEAR_FROM || b > FIELDTYPE_TEAR_TO);
+  return field_types_merge_rules[field_type2index(a)]
+                                [field_type2index(b)];
+}
+
+
+static Item_result field_types_result_type [FIELDTYPE_NUM]=
+{
+  //MYSQL_TYPE_DECIMAL      MYSQL_TYPE_TINY
+  DECIMAL_RESULT,           INT_RESULT,
+  //MYSQL_TYPE_SHORT        MYSQL_TYPE_LONG
+  INT_RESULT,               INT_RESULT,
+  //MYSQL_TYPE_FLOAT        MYSQL_TYPE_DOUBLE
+  REAL_RESULT,              REAL_RESULT,
+  //MYSQL_TYPE_NULL         MYSQL_TYPE_TIMESTAMP
+  STRING_RESULT,            STRING_RESULT,
+  //MYSQL_TYPE_LONGLONG     MYSQL_TYPE_INT24
+  INT_RESULT,               INT_RESULT,
+  //MYSQL_TYPE_DATE         MYSQL_TYPE_TIME
+  STRING_RESULT,            STRING_RESULT,
+  //MYSQL_TYPE_DATETIME     MYSQL_TYPE_YEAR
+  STRING_RESULT,            INT_RESULT,
+  //MYSQL_TYPE_NEWDATE      MYSQL_TYPE_VARCHAR
+  STRING_RESULT,            STRING_RESULT,
+  //MYSQL_TYPE_BIT          <16>-<245>
+  STRING_RESULT,
+  //MYSQL_TYPE_NEWDECIMAL   MYSQL_TYPE_ENUM
+  DECIMAL_RESULT,           STRING_RESULT,
+  //MYSQL_TYPE_SET          MYSQL_TYPE_TINY_BLOB
+  STRING_RESULT,            STRING_RESULT,
+  //MYSQL_TYPE_MEDIUM_BLOB  MYSQL_TYPE_LONG_BLOB
+  STRING_RESULT,            STRING_RESULT,
+  //MYSQL_TYPE_BLOB         MYSQL_TYPE_VAR_STRING
+  STRING_RESULT,            STRING_RESULT,
+  //MYSQL_TYPE_STRING       MYSQL_TYPE_GEOMETRY
+  STRING_RESULT,            STRING_RESULT
+};
+
+
+/*
+  Detect Item_result by given field type of UNION merge result
+
+  SYNOPSIS
+    Field::result_merge_type()
+    field_type  given field type
+
+  RETURN
+    Item_result (type of internal MySQL expression result)
+*/
+
+Item_result Field::result_merge_type(enum_field_types field_type)
+{
+  DBUG_ASSERT(field_type < FIELDTYPE_TEAR_FROM || field_type
+              > FIELDTYPE_TEAR_TO);
+  return field_types_result_type[field_type2index(field_type)];
+}
+
 /*****************************************************************************
   Static help functions
 *****************************************************************************/
@@ -229,164 +1159,6 @@
 
 
 /*
- Tables of filed type compatibility.
-
- There are tables for every type, table consist of list of types in which
- given type can be converted without data lost, list should be ended with
- FIELD_CAST_STOP
-*/
-static Field::field_cast_enum field_cast_decimal[]=
-{Field::FIELD_CAST_DECIMAL,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_new_decimal[]=
-{Field::FIELD_CAST_NEWDECIMAL,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_tiny[]=
-{Field::FIELD_CAST_TINY,
- Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG,
- Field::FIELD_CAST_LONGLONG,
- Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_short[]=
-{Field::FIELD_CAST_SHORT,
- Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG,
- Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_medium[]=
-{Field::FIELD_CAST_MEDIUM,
- Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG,
- Field::FIELD_CAST_DOUBLE,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_long[]=
-{Field::FIELD_CAST_LONG,
- Field::FIELD_CAST_LONGLONG,
- Field::FIELD_CAST_DOUBLE,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_longlong[]=
-{Field::FIELD_CAST_LONGLONG,
- Field::FIELD_CAST_DOUBLE,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_float[]=
-{Field::FIELD_CAST_FLOAT,
- Field::FIELD_CAST_DOUBLE,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_double[]=
-{Field::FIELD_CAST_DOUBLE,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_null[]=
-{Field::FIELD_CAST_NULL,
- Field::FIELD_CAST_DECIMAL, Field::FIELD_CAST_TINY, Field::FIELD_CAST_SHORT,
- Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG,
- Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
- Field::FIELD_CAST_TIMESTAMP, Field::FIELD_CAST_YEAR,
- Field::FIELD_CAST_DATE, Field::FIELD_CAST_NEWDATE,
- Field::FIELD_CAST_TIME, Field::FIELD_CAST_DATETIME,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB,
- Field::FIELD_CAST_GEOM, Field::FIELD_CAST_ENUM, Field::FIELD_CAST_SET,
- Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_timestamp[]=
-{Field::FIELD_CAST_TIMESTAMP,
- Field::FIELD_CAST_DATETIME,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_year[]=
-{Field::FIELD_CAST_YEAR,
- Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG,
- Field::FIELD_CAST_LONGLONG,
- Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_date[]=
-{Field::FIELD_CAST_DATE,
- Field::FIELD_CAST_DATETIME,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_newdate[]=
-{Field::FIELD_CAST_NEWDATE,
- Field::FIELD_CAST_DATE,
- Field::FIELD_CAST_DATETIME,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_time[]=
-{Field::FIELD_CAST_TIME,
- Field::FIELD_CAST_DATETIME,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_datetime[]=
-{Field::FIELD_CAST_DATETIME,
- Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_string[]=
-{Field::FIELD_CAST_STRING,
- Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_varstring[]=
-{Field::FIELD_CAST_VARSTRING,
- Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_blob[]=
-{Field::FIELD_CAST_BLOB,
- Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_bit[]=
-{Field::FIELD_CAST_BIT,
- Field::FIELD_CAST_STOP};
-/*
-  Geometrical, enum and set fields can be casted only to expressions
-*/
-static Field::field_cast_enum field_cast_geom[]=
-{Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_enum[]=
-{Field::FIELD_CAST_STOP};
-static Field::field_cast_enum field_cast_set[]=
-{Field::FIELD_CAST_STOP};
-// Array of pointers on conversion table for all fields types casting
-static Field::field_cast_enum *field_cast_array[]=
-{0, //FIELD_CAST_STOP
- field_cast_decimal, field_cast_tiny, field_cast_short,
- field_cast_medium, field_cast_long, field_cast_longlong,
- field_cast_float, field_cast_double,
- field_cast_null,
- field_cast_timestamp, field_cast_year, field_cast_date, field_cast_newdate,
- field_cast_time, field_cast_datetime,
- field_cast_string, field_cast_varstring, field_cast_blob,
- field_cast_geom, field_cast_enum, field_cast_set, field_cast_bit,
- field_cast_new_decimal
-};
-
-
-/*
-  Check if field of given type can store a value of this field.
-
-  SYNOPSIS
-    type   type for test
-
-  RETURN
-    1 can
-    0 can not
-*/
-
-bool Field::field_cast_compatible(Field::field_cast_enum type)
-{
-  DBUG_ASSERT(type != FIELD_CAST_STOP);
-  Field::field_cast_enum *array= field_cast_array[field_cast_type()];
-  while (*array != FIELD_CAST_STOP)
-  {
-    if (*(array++) == type)
-      return 1;
-  }
-  return 0;
-}
-
-
-/*
   Interpret field value as an integer but return the result as a string.
 
   This is used for printing bit_fields as numbers while debugging
@@ -473,8 +1245,13 @@
 
 void Field::make_field(Send_field *field)
 {
-  field->db_name= orig_table->s->table_cache_key;
-  field->org_table_name= orig_table->s->table_name;
+  if (orig_table->s->table_cache_key &&
*(orig_table->s->table_cache_key))
+  {
+    field->org_table_name= orig_table->s->table_name;
+    field->db_name= orig_table->s->table_cache_key;
+  }
+  else
+    field->org_table_name= field->db_name= "";
   field->table_name= orig_table->alias;
   field->col_name= field->org_col_name= field_name;
   field->charsetnr= charset()->number;
@@ -626,7 +1403,6 @@
 
 my_decimal *Field_str::val_decimal(my_decimal *decimal_value)
 {
-  DBUG_ASSERT(result_type() == INT_RESULT);
   longlong nr= val_int();
   int2my_decimal(E_DEC_FATAL_ERROR, nr, 0, decimal_value);
   return decimal_value;
@@ -753,25 +1529,22 @@
 {
   char escaped_string[IO_SIZE];
   char *unquoted_string_buffer= (char *)(unquoted_string->ptr());
-  uint need_quotes;
   DBUG_ENTER("Field::quote_data");
 
-  // this is the same call that mysql_real_escape_string() calls
-  escape_string_for_mysql(&my_charset_bin, (char *)escaped_string,
-    unquoted_string->ptr(), unquoted_string->length());
-
-  need_quotes= needs_quotes();
-
-  if (need_quotes == 0)
+  if (!needs_quotes())
     DBUG_RETURN(0);
 
+  // this is the same call that mysql_real_escape_string() calls
+  if (escape_string_for_mysql(&my_charset_bin, (char *)escaped_string,
+                              sizeof(escaped_string), unquoted_string->ptr(),
+                              unquoted_string->length()) == (ulong)~0)
+    DBUG_RETURN(1);
+
   // reset string, then re-append with quotes and escaped values
   unquoted_string->length(0);
-  if (unquoted_string->append('\''))
-    DBUG_RETURN(1);
-  if (unquoted_string->append((char *)escaped_string))
-    DBUG_RETURN(1);
-  if (unquoted_string->append('\''))
+  if (unquoted_string->append('\'') ||
+      unquoted_string->append((char *)escaped_string) ||
+      unquoted_string->append('\''))
     DBUG_RETURN(1);
   DBUG_RETURN(0);
 }
@@ -2452,14 +3225,15 @@
 
 int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
 {
+  ulong tmp_scan;
   longlong tmp;
   long store_tmp;
   int error;
   char *end;
   
-  tmp= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
-  len-= tmp;
-  from+= tmp;
+  tmp_scan= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
+  len-= tmp_scan;
+  from+= tmp_scan;
 
   end= (char*) from+len;
   tmp= cs->cset->my_strtoll10(cs, from, &end, &error);
@@ -3738,6 +4512,13 @@
     set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, 
                          WARN_DATA_TRUNCATED,
                          nr, MYSQL_TIMESTAMP_DATETIME, 1);
+  if (!error && timestamp == 0 &&
+      (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE))
+  {
+    set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, 
+                         WARN_DATA_TRUNCATED,
+                         nr, MYSQL_TIMESTAMP_DATETIME, 1);
+  }
 
 #ifdef WORDS_BIGENDIAN
   if (table->s->db_low_byte_first)
@@ -4363,6 +5144,12 @@
   }
   else
     tmp=(long) rint(nr);
+
+  /*
+    We don't need to check for zero dates here as this date type is only
+    used in .frm tables from very old MySQL versions
+  */
+
 #ifdef WORDS_BIGENDIAN
   if (table->s->db_low_byte_first)
   {
@@ -4391,6 +5178,7 @@
   }
   else
     tmp=(long) nr;
+
 #ifdef WORDS_BIGENDIAN
   if (table->s->db_low_byte_first)
   {
@@ -4503,6 +5291,7 @@
   res.set_ascii("date", 4);
 }
 
+
 /****************************************************************************
 ** The new date type
 ** This is identical to the old date type, but stored on 3 bytes instead of 4
@@ -4535,17 +5324,17 @@
   return error;
 }
 
+
 int Field_newdate::store(double nr)
 {
   if (nr < 0.0 || nr > 99991231235959.0)
   {
-    (void) Field_newdate::store((longlong) -1);
+    int3store(ptr,(int32) 0);
     set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, 
                          WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE);
     return 1;
   }
-  else
-    return Field_newdate::store((longlong) rint(nr));
+  return Field_newdate::store((longlong) rint(nr));
 }
 
 
@@ -4565,6 +5354,8 @@
   }
   else
   {
+    uint month, day;
+
     tmp=(int32) nr;
     if (tmp)
     {
@@ -4572,24 +5363,33 @@
 	tmp+= (uint32) 20000000L;
       else if (tmp < 999999L)
 	tmp+= (uint32) 19000000L;
+
+      month= (uint) ((tmp/100) % 100);
+      day=   (uint) (tmp%100);
+      if (month > 12 || day > 31)
+      {
+        tmp=0L;					// Don't allow date to change
+        set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, 
+                             ER_WARN_DATA_OUT_OF_RANGE, nr,
+                             MYSQL_TIMESTAMP_DATE, 1);
+        error= 1;
+      }
+      else
+        tmp= day + month*32 + (tmp/10000)*16*32;
     }
-    uint month= (uint) ((tmp/100) % 100);
-    uint day=   (uint) (tmp%100);
-    if (month > 12 || day > 31)
+    else if (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE)
     {
-      tmp=0L;					// Don't allow date to change
       set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, 
-                           ER_WARN_DATA_OUT_OF_RANGE, nr,
-                           MYSQL_TIMESTAMP_DATE, 1);
+                           ER_WARN_DATA_OUT_OF_RANGE, 
+                           0, MYSQL_TIMESTAMP_DATE);
       error= 1;
     }
-    else
-      tmp= day + month*32 + (tmp/10000)*16*32;
   }
-  int3store(ptr,(int32) tmp);
+  int3store(ptr, tmp);
   return error;
 }
 
+
 int Field_newdate::store_time(TIME *ltime,timestamp_type type)
 {
   long tmp;
@@ -4606,6 +5406,7 @@
   return error;
 }
 
+
 bool Field_newdate::send_binary(Protocol *protocol)
 {
   TIME tm;
@@ -4613,11 +5414,13 @@
   return protocol->store_date(&tm);
 }
 
+
 double Field_newdate::val_real(void)
 {
   return (double) Field_newdate::val_int();
 }
 
+
 longlong Field_newdate::val_int(void)
 {
   ulong j= uint3korr(ptr);
@@ -4625,6 +5428,7 @@
   return (longlong) j;
 }
 
+
 String *Field_newdate::val_str(String *val_buffer,
 			       String *val_ptr __attribute__((unused)))
 {
@@ -4652,6 +5456,7 @@
   return val_buffer;
 }
 
+
 bool Field_newdate::get_date(TIME *ltime,uint fuzzydate)
 {
   uint32 tmp=(uint32) uint3korr(ptr);
@@ -4664,11 +5469,13 @@
           1 : 0);
 }
 
+
 bool Field_newdate::get_time(TIME *ltime)
 {
   return Field_newdate::get_date(ltime,0);
 }
 
+
 int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
 {
   uint32 a,b;
@@ -4677,6 +5484,7 @@
   return (a < b) ? -1 : (a > b) ? 1 : 0;
 }
 
+
 void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
 {
   to[0] = ptr[2];
@@ -4684,6 +5492,7 @@
   to[2] = ptr[0];
 }
 
+
 void Field_newdate::sql_type(String &res) const
 {
   res.set_ascii("date", 4);
@@ -4702,15 +5511,19 @@
   TIME time_tmp;
   int error;
   ulonglong tmp= 0;
+  enum enum_mysql_timestamp_type func_res;
   
-  if (str_to_datetime(from, len, &time_tmp,
-                      (TIME_FUZZY_DATE |
-                       (table->in_use->variables.sql_mode &
-                        (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
-                         MODE_INVALID_DATES))),
-                      &error) > MYSQL_TIMESTAMP_ERROR)
+  func_res= str_to_datetime(from, len, &time_tmp,
+                            (TIME_FUZZY_DATE |
+                             (table->in_use->variables.sql_mode &
+                              (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+                               MODE_INVALID_DATES))),
+                            &error);
+  if ((int) func_res > (int) MYSQL_TIMESTAMP_ERROR)
     tmp= TIME_to_ulonglong_datetime(&time_tmp);
-  
+  else
+    error= 1;                                 // Fix if invalid zero date
+
   if (error)
     set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, 
                          ER_WARN_DATA_OUT_OF_RANGE,
@@ -4736,10 +5549,10 @@
     set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, 
                          ER_WARN_DATA_OUT_OF_RANGE,
                          nr, MYSQL_TIMESTAMP_DATETIME);
-    nr=0.0;
+    nr= 0.0;
     error= 1;
   }
-  error |= Field_datetime::store((longlong) rint(nr));
+  error|= Field_datetime::store((longlong) rint(nr));
   return error;
 }
 
@@ -4756,6 +5569,13 @@
     set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, 
                          WARN_DATA_TRUNCATED, initial_nr, 
                          MYSQL_TIMESTAMP_DATETIME, 1);
+  else if (nr == 0 && table->in_use->variables.sql_mode &
MODE_NO_ZERO_DATE)
+  {
+    set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, 
+                         ER_WARN_DATA_OUT_OF_RANGE, 
+                         initial_nr, MYSQL_TIMESTAMP_DATE);
+    error= 1;
+  }
 
 #ifdef WORDS_BIGENDIAN
   if (table->s->db_low_byte_first)
@@ -5329,10 +6149,10 @@
 
 int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
 {
-  int error= 0;
   uint32 not_used, copy_length;
   char buff[STRING_BUFFER_USUAL_SIZE];
   String tmpstr(buff,sizeof(buff), &my_charset_bin);
+  int error_code= 0;
   enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN;
 
   /* Convert character set if necessary */
@@ -5343,7 +6163,7 @@
     from= tmpstr.ptr();
     length=  tmpstr.length();
     if (conv_errors)
-      error= 1;
+      error_code= WARN_DATA_TRUNCATED;
   }
   /* 
     Make sure we don't break a multibyte sequence
@@ -5360,23 +6180,26 @@
     int2store(ptr, copy_length);
 
   // Check if we lost something other than just trailing spaces
-  if ((copy_length < length) && table->in_use->count_cuted_fields)
+  if ((copy_length < length) && table->in_use->count_cuted_fields
&&
+      !error_code)
   {
     const char *end= from + length;
     from+= copy_length;
     from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES);
-    /*
-      If we lost only spaces then produce a NOTE, not a WARNING.
-      But if we have already had errors (e.g with charset conversion),
-      then don't reset level to NOTE.
-    */
-    if (from == end && !error)
+    /* If we lost only spaces then produce a NOTE, not a WARNING */
+    if (from == end)
       level= MYSQL_ERROR::WARN_LEVEL_NOTE;
-    error= 1;
+    error_code= WARN_DATA_TRUNCATED;
   }
-  if (error)
-    set_warning(level, WARN_DATA_TRUNCATED, 1);
-  return error;
+  if (error_code)
+  {
+    if (level == MYSQL_ERROR::WARN_LEVEL_WARN &&
+        table->in_use->abort_on_warning)
+      error_code= ER_DATA_TOO_LONG;
+    set_warning(level, error_code, 1);
+    return 1;
+  }
+  return 0;
 }
 
 
@@ -5722,12 +6545,12 @@
 {
   uint f_length=  length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
   uint char_length= length / field_charset->mbmaxlen;
-  char_length= my_charpos(field_charset, ptr, ptr + length_bytes,
-                          char_length);
+  char *pos= ptr+length_bytes;
+  char_length= my_charpos(field_charset, pos, pos + f_length, char_length);
   set_if_smaller(f_length, char_length);
   /* Key is always stored with 2 bytes */
   int2store(buff,f_length);
-  memcpy(buff+HA_KEY_BLOB_LENGTH, ptr+length_bytes, f_length);
+  memcpy(buff+HA_KEY_BLOB_LENGTH, pos, f_length);
   if (f_length < length)
   {
     /*
@@ -5972,7 +6795,12 @@
     bmove(ptr+packlength,(char*) &from,sizeof(char*));
   }
   if (error)
-    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+  {
+    if (table->in_use->abort_on_warning)
+      set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+    else
+      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+  }
   return 0;
 }
 
@@ -6995,8 +7823,10 @@
 {
   ulonglong bits= 0;
   if (bit_len)
+  {
     bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
-  bits<<= (field_length * 8);
+    bits<<= (field_length * 8);
+  }
 
   switch (field_length) {
   case 0: return bits;
@@ -7151,6 +7981,24 @@
 }
 
 
+void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
+                                      uint32 length_arg, uint32 decimals,
+                                      bool maybe_null, bool is_unsigned)
+{
+  field_name= "";
+  sql_type= sql_type_arg;
+  length= length_arg;;
+  unireg_check= Field::NONE;
+  interval= 0;
+  charset= &my_charset_bin;
+  geom_type= Field::GEOM_GEOMETRY;
+  pack_flag= (FIELDFLAG_NUMBER |
+              ((decimals & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
+              (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
+              (is_unsigned ? 0 : FIELDFLAG_DECIMAL));
+}
+
+
 enum_field_types get_blob_type_from_length(ulong length)
 {
   enum_field_types type;
@@ -7394,40 +8242,6 @@
 }
 
 
-/*
-  Check if field_type is appropriate field type
-  to create field for tmp table using
-  item->tmp_table_field() method
-
-  SYNOPSIS
-    field_types_to_be_kept()
-    field_type     - field type
-
-  NOTE
-    it is used in function get_holder_example_field()
-    from item.cc
-
-  RETURN
-    1 - can use item->tmp_table_field() method
-    0 - can not use item->tmp_table_field() method
-
-*/
-
-bool field_types_to_be_kept(enum_field_types field_type)
-{
-  switch (field_type)
-  {
-    case FIELD_TYPE_DATE:
-    case FIELD_TYPE_NEWDATE:
-    case FIELD_TYPE_TIME:
-    case FIELD_TYPE_DATETIME:
-      return 1;
-    default:
-      return 0;
-  }
-}
-
-
 /* Create a field suitable for create of table */
 
 create_field::create_field(Field *old_field,Field *orig_field)
@@ -7513,7 +8327,37 @@
 }
 
 
-/* Warning handling */
+/*
+  maximum possible display length for blob
+
+  SYNOPSIS
+    Field_blob::max_length()
+
+  RETURN
+    length
+*/
+uint32 Field_blob::max_length()
+{
+  switch (packlength)
+  {
+  case 1:
+    return 255;
+  case 2:
+    return 65535;
+  case 3:
+    return 16777215;
+  case 4:
+    return (uint32) 4294967295U;
+  default:
+    DBUG_ASSERT(0); // we should never go here
+    return 0;
+  }
+}
+
+
+/*****************************************************************************
+ Warning handling
+*****************************************************************************/
 
 /*
   Produce warning or note about data saved into field
@@ -7529,18 +8373,20 @@
     if count_cuted_fields == FIELD_CHECK_IGNORE for current thread.
 
   RETURN VALUE
-    true  - if count_cuted_fields == FIELD_CHECK_IGNORE
-    false - otherwise
+    1 if count_cuted_fields == FIELD_CHECK_IGNORE
+    0 otherwise
 */
+
 bool 
-Field::set_warning(const uint level, const uint code, int cuted_increment)
+Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
+                   int cuted_increment)
 {
   THD *thd= table->in_use;
   if (thd->count_cuted_fields)
   {
     thd->cuted_fields+= cuted_increment;
-    push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level,
-                        code, ER(code), field_name, thd->row_count);
+    push_warning_printf(thd, level, code, ER(code), field_name,
+                        thd->row_count);
     return 0;
   }
   return 1;
@@ -7564,8 +8410,9 @@
     fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current 
     thread.
 */
+
 void 
-Field::set_datetime_warning(const uint level, const uint code, 
+Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, 
                             const char *str, uint str_length, 
                             timestamp_type ts_type, int cuted_increment)
 {
@@ -7592,8 +8439,9 @@
     fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current 
     thread.
 */
+
 void 
-Field::set_datetime_warning(const uint level, const uint code, 
+Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, 
                             longlong nr, timestamp_type ts_type,
                             int cuted_increment)
 {
@@ -7623,8 +8471,9 @@
     fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current 
     thread.
 */
+
 void 
-Field::set_datetime_warning(const uint level, const uint code, 
+Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, 
                             double nr, timestamp_type ts_type)
 {
   if (table->in_use->really_abort_on_warning() ||
@@ -7635,32 +8484,5 @@
     uint str_len= my_sprintf(str_nr, (str_nr, "%g", nr));
     make_truncated_value_warning(table->in_use, str_nr, str_len, ts_type,
                                  field_name);
-  }
-}
-
-/*
-  maximum possible display length for blob
-
-  SYNOPSIS
-    Field_blob::max_length()
-
-  RETURN
-    length
-*/
-uint32 Field_blob::max_length()
-{
-  switch (packlength)
-  {
-  case 1:
-    return 255;
-  case 2:
-    return 65535;
-  case 3:
-    return 16777215;
-  case 4:
-    return (uint32) 4294967295U;
-  default:
-    DBUG_ASSERT(0); // we should never go here
-    return 0;
   }
 }

--- 1.140/sql/field.h	Tue Mar  1 22:38:50 2005
+++ 1.141/sql/field.h	Tue Apr  5 15:01:08 2005
@@ -31,6 +31,17 @@
 struct st_cache_field;
 void field_conv(Field *to,Field *from);
 
+inline uint get_enum_pack_length(int elements)
+{
+  return elements < 256 ? 1 : 2;
+}
+
+inline uint get_set_pack_length(int elements)
+{
+  uint len= (elements + 7) / 8;
+  return len > 4 ? 8 : len;
+}
+
 class Field
 {
   Field(const Item &);				/* Prevent use of these */
@@ -49,7 +60,7 @@
   struct st_table *orig_table;		// Pointer to original table
   const char	**table_name, *field_name;
   LEX_STRING	comment;
-  ulong		query_id;		// For quick test of used fields
+  query_id_t	query_id;		// For quick test of used fields
   /* Field is part of the following keys */
   key_map	key_start,part_of_key,part_of_sortkey;
   /* 
@@ -71,18 +82,6 @@
     GEOM_GEOMETRYCOLLECTION = 7
   };
   enum imagetype { itRAW, itMBR};
-  enum field_cast_enum
-  {
-    FIELD_CAST_STOP, FIELD_CAST_DECIMAL, FIELD_CAST_TINY, FIELD_CAST_SHORT,
-    FIELD_CAST_MEDIUM, FIELD_CAST_LONG, FIELD_CAST_LONGLONG,
-    FIELD_CAST_FLOAT, FIELD_CAST_DOUBLE,
-    FIELD_CAST_NULL,
-    FIELD_CAST_TIMESTAMP, FIELD_CAST_YEAR, FIELD_CAST_DATE, FIELD_CAST_NEWDATE,
-    FIELD_CAST_TIME, FIELD_CAST_DATETIME,
-    FIELD_CAST_STRING, FIELD_CAST_VARSTRING, FIELD_CAST_BLOB,
-    FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET, FIELD_CAST_BIT,
-    FIELD_CAST_NEWDECIMAL
-  };
 
   utype		unireg_check;
   uint32	field_length;		// Length of field
@@ -119,6 +118,8 @@
   String *val_int_as_str(String *val_buffer, my_bool unsigned_flag);
   virtual Item_result result_type () const=0;
   virtual Item_result cmp_type () const { return result_type(); }
+  static enum_field_types field_type_merge(enum_field_types, enum_field_types);
+  static Item_result result_merge_type(enum_field_types);
   bool eq(Field *field)
   {
     return (ptr == field->ptr && null_ptr == field->null_ptr &&
@@ -279,25 +280,23 @@
   virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
   virtual bool has_charset(void) const { return FALSE; }
   virtual void set_charset(CHARSET_INFO *charset) { }
-  bool set_warning(const unsigned int level, const unsigned int code, 
+  bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
                    int cuted_increment);
   bool check_int(const char *str, int length, const char *int_end,
                  CHARSET_INFO *cs);
-  void set_datetime_warning(const uint level, const uint code, 
+  void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code, 
                             const char *str, uint str_len,
                             timestamp_type ts_type, int cuted_increment);
-  void set_datetime_warning(const uint level, const uint code, 
+  void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code, 
                             longlong nr, timestamp_type ts_type,
                             int cuted_increment);
-  void set_datetime_warning(const uint level, const uint code, 
+  void set_datetime_warning(MYSQL_ERROR::enum_warning_level, const uint code, 
                             double nr, timestamp_type ts_type);
   inline bool check_overflow(int op_result)
   {
     return (op_result == E_DEC_OVERFLOW);
   }
   int warn_if_overflow(int op_result);
-  virtual field_cast_enum field_cast_type()= 0;
-  bool field_cast_compatible(field_cast_enum type);
   /* maximum possible display length */
   virtual uint32 max_length()= 0;
   /* length of field value symbolic representation (in bytes) */
@@ -432,7 +431,6 @@
   bool zero_pack() const { return 0; }
   void sql_type(String &str) const;
   uint32 max_length() { return field_length; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_DECIMAL; }
 };
 
 
@@ -470,7 +468,6 @@
   { return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); }
   uint32 representation_length()
   { return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); };
-  field_cast_enum field_cast_type() { return FIELD_CAST_NEWDECIMAL; }
   uint size_of() const { return sizeof(*this); } 
   uint32 pack_length() const { return (uint32) bin_size; }
 };
@@ -504,7 +501,6 @@
   uint32 pack_length() const { return 1; }
   void sql_type(String &str) const;
   uint32 max_length() { return 4; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_TINY; }
 };
 
 
@@ -541,7 +537,6 @@
   uint32 pack_length() const { return 2; }
   void sql_type(String &str) const;
   uint32 max_length() { return 6; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_SHORT; }
 };
 
 
@@ -573,7 +568,6 @@
   uint32 pack_length() const { return 3; }
   void sql_type(String &str) const;
   uint32 max_length() { return 8; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_MEDIUM; }
 };
 
 
@@ -610,7 +604,6 @@
   uint32 pack_length() const { return 4; }
   void sql_type(String &str) const;
   uint32 max_length() { return 11; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_LONG; }
 };
 
 
@@ -650,7 +643,6 @@
   void sql_type(String &str) const;
   bool can_be_compared_as_longlong() const { return TRUE; }
   uint32 max_length() { return 20; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_LONGLONG; }
 };
 #endif
 
@@ -686,7 +678,6 @@
   uint32 pack_length() const { return sizeof(float); }
   void sql_type(String &str) const;
   uint32 max_length() { return 24; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_FLOAT; }
 };
 
 
@@ -721,7 +712,6 @@
   uint32 pack_length() const { return sizeof(double); }
   void sql_type(String &str) const;
   uint32 max_length() { return 53; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_DOUBLE; }
 };
 
 
@@ -754,7 +744,6 @@
   void sql_type(String &str) const;
   uint size_of() const { return sizeof(*this); }
   uint32 max_length() { return 4; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_NULL; }
 };
 
 
@@ -806,7 +795,6 @@
   }
   bool get_date(TIME *ltime,uint fuzzydate);
   bool get_time(TIME *ltime);
-  field_cast_enum field_cast_type() { return FIELD_CAST_TIMESTAMP; }
   timestamp_auto_set_type get_auto_set_type() const;
 };
 
@@ -830,7 +818,6 @@
   bool send_binary(Protocol *protocol);
   void sql_type(String &str) const;
   bool can_be_compared_as_longlong() const { return TRUE; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_YEAR; }
 };
 
 
@@ -863,7 +850,6 @@
   void sql_type(String &str) const;
   bool can_be_compared_as_longlong() const { return TRUE; }
   bool zero_pack() const { return 1; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_DATE; }
 };
 
 class Field_newdate :public Field_str {
@@ -895,7 +881,6 @@
   bool zero_pack() const { return 1; }
   bool get_date(TIME *ltime,uint fuzzydate);
   bool get_time(TIME *ltime);
-  field_cast_enum field_cast_type() { return FIELD_CAST_NEWDATE; }
 };
 
 
@@ -931,7 +916,6 @@
   void sql_type(String &str) const;
   bool can_be_compared_as_longlong() const { return TRUE; }
   bool zero_pack() const { return 1; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_TIME; }
 };
 
 
@@ -969,7 +953,6 @@
   bool zero_pack() const { return 1; }
   bool get_date(TIME *ltime,uint fuzzydate);
   bool get_time(TIME *ltime);
-  field_cast_enum field_cast_type() { return FIELD_CAST_DATETIME; }
 };
 
 
@@ -1018,7 +1001,6 @@
   enum_field_types real_type() const { return FIELD_TYPE_STRING; }
   bool has_charset(void) const
   { return charset() == &my_charset_bin ? FALSE : TRUE; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_STRING; }
   Field *new_field(MEM_ROOT *root, struct st_table *new_table);
 };
 
@@ -1085,7 +1067,6 @@
   enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; }
   bool has_charset(void) const
   { return charset() == &my_charset_bin ? FALSE : TRUE; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_VARSTRING; }
   Field *new_field(MEM_ROOT *root, struct st_table *new_table);
   Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
                        char *new_ptr, uchar *new_null_ptr,
@@ -1183,7 +1164,6 @@
   uint size_of() const { return sizeof(*this); }
   bool has_charset(void) const
   { return charset() == &my_charset_bin ? FALSE : TRUE; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_BLOB; }
   uint32 max_length();
 };
 
@@ -1213,7 +1193,6 @@
   int  store(longlong nr) { return 1; }
   int  store_decimal(const my_decimal *) { return 1; }
   void get_key_image(char *buff,uint length,imagetype type);
-  field_cast_enum field_cast_type() { return FIELD_CAST_GEOM; }
 };
 #endif /*HAVE_SPATIAL*/
 
@@ -1258,7 +1237,6 @@
   bool has_charset(void) const { return TRUE; }
   /* enum and set are sorted as integers */
   CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_ENUM; }
 };
 
 
@@ -1284,7 +1262,6 @@
   void sql_type(String &str) const;
   enum_field_types real_type() const { return FIELD_TYPE_SET; }
   bool has_charset(void) const { return TRUE; }
-  field_cast_enum field_cast_type() { return FIELD_CAST_SET; }
 };
 
 
@@ -1327,7 +1304,6 @@
   { return (uint32) field_length + (bit_len > 0); }
   uint32 pack_length_in_rec() const { return field_length; }
   void sql_type(String &str) const;
-  field_cast_enum field_cast_type() { return FIELD_CAST_BIT; }
   char *pack(char *to, const char *from, uint max_length=~(uint) 0);
   const char *unpack(char* to, const char *from);
   Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
@@ -1340,7 +1316,8 @@
   Create field class for CREATE TABLE
 */
 
-class create_field :public Sql_alloc {
+class create_field :public Sql_alloc
+{
 public:
   const char *field_name;
   const char *change;			// If done with alter table
@@ -1362,6 +1339,11 @@
   create_field() :after(0) {}
   create_field(Field *field, Field *orig_field);
   void create_length_to_internal_length(void);
+
+  /* Init for a tmp table field. To be extended if need be. */
+  void init_for_tmp_table(enum_field_types sql_type_arg,
+                          uint32 max_length, uint32 decimals,
+                          bool maybe_null, bool is_unsigned);
 };
 
 
@@ -1418,7 +1400,6 @@
 uint32 calc_pack_length(enum_field_types type,uint32 length);
 int set_field_to_null(Field *field);
 int set_field_to_null_with_conversions(Field *field, bool no_conversions);
-bool field_types_to_be_kept(enum_field_types field_type);
 
 /*
   The following are for the interface with the .frm file

--- 1.141/sql/handler.cc	Tue Mar  1 22:38:51 2005
+++ 1.142/sql/handler.cc	Tue Apr  5 15:01:09 2005
@@ -32,6 +32,9 @@
 #ifdef HAVE_BERKELEY_DB
 #include "ha_berkeley.h"
 #endif
+#ifdef HAVE_BLACKHOLE_DB
+#include "ha_blackhole.h"
+#endif
 #ifdef HAVE_EXAMPLE_DB
 #include "examples/ha_example.h"
 #endif
@@ -58,8 +61,6 @@
 
 	/* static functions defined in this file */
 
-static int NEAR_F delete_file(const char *name,const char *ext,int extflag);
-
 static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
 
 /* list of all available storage engines (of their handlertons) */
@@ -108,6 +109,9 @@
    "CSV storage engine", DB_TYPE_CSV_DB},
   {"FEDERATED",&have_federated_db,
    "Federated MySQL storage engine", DB_TYPE_FEDERATED_DB},
+  {"BLACKHOLE",&have_blackhole_db,
+   "/dev/null storage engine (anything you write to it disappears)",
+   DB_TYPE_BLACKHOLE_DB},
   {NullS, NULL, NullS, DB_TYPE_UNKNOWN}
 };
 
@@ -232,6 +236,10 @@
   case DB_TYPE_ARCHIVE_DB:
     return new ha_archive(table);
 #endif
+#ifdef HAVE_BLACKHOLE_DB
+  case DB_TYPE_BLACKHOLE_DB:
+    return new ha_blackhole(table);
+#endif
 #ifdef HAVE_FEDERATED_DB
   case DB_TYPE_FEDERATED_DB:
     return new ha_federated(table);
@@ -363,7 +371,7 @@
   my_free((gptr) errmsgs, MYF(0));
   return 0;
 }
-  
+
 
 static inline void ha_was_inited_ok(handlerton **ht)
 {
@@ -431,6 +439,16 @@
       ha_was_inited_ok(ht++);
   }
 #endif
+#ifdef HAVE_FEDERATED_DB
+  if (have_federated_db == SHOW_OPTION_YES)
+  {
+    if (federated_db_init())
+    {
+      have_federated_db= SHOW_OPTION_DISABLED;
+      error= 1;
+    }
+  }
+#endif
 #ifdef HAVE_ARCHIVE_DB
   if (have_archive_db == SHOW_OPTION_YES)
   {
@@ -444,7 +462,12 @@
   }
 #endif
   DBUG_ASSERT(total_ha < MAX_HA);
-  opt_using_transactions= total_ha>opt_bin_log;
+  /*
+    Check if there is a transaction-capable storage engine besides the
+    binary log (which is considered a transaction-capable storage engine in
+    counting total_ha)
+  */
+  opt_using_transactions= total_ha>(ulong)opt_bin_log;
   savepoint_alloc_size+= sizeof(SAVEPOINT);
   return error;
 }
@@ -477,6 +500,10 @@
   if (have_ndbcluster == SHOW_OPTION_YES)
     error|=ndbcluster_end();
 #endif
+#ifdef HAVE_FEDERATED_DB
+  if (have_federated_db == SHOW_OPTION_YES)
+    error|= federated_db_end();
+#endif
 #ifdef HAVE_ARCHIVE_DB
   if (have_archive_db == SHOW_OPTION_YES)
     error|= archive_db_end();
@@ -509,6 +536,16 @@
 /* ========================================================================
  ======================= TRANSACTIONS ===================================*/
 
+/*
+  Register a storage engine for a transaction
+
+  DESCRIPTION
+    Every storage engine MUST call this function when it starts
+    a transaction or a statement (that is it must be called both for the
+    "beginning of transaction" and "beginning of statement").
+    Only storage engines registered for the transaction/statement
+    will know when to commit/rollback it.
+*/
 void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
 {
   THD_TRANS *trans;
@@ -540,7 +577,6 @@
 
 /*
   RETURN
-     -1  - cannot prepare
       0  - ok
       1  - error, transaction was rolled back
 */
@@ -553,8 +589,6 @@
 #ifdef USING_TRANSACTIONS
   if (trans->nht)
   {
-    if (trans->no_2pc)
-      DBUG_RETURN(-1);
     for (; *ht; ht++)
     {
       int err;
@@ -766,18 +800,106 @@
   return res;
 }
 
+#ifndef DBUG_OFF
+/* this does not need to be multi-byte safe or anything */
+static char* xid_to_str(char *buf, XID *xid)
+{
+  int i;
+  char *s=buf;
+  *s++='\'';
+  for (i=0; i < xid->gtrid_length+xid->bqual_length; i++)
+  {
+    uchar c=(uchar)xid->data[i];
+    /* is_next_dig is set if next character is a number */
+    bool is_next_dig= FALSE;
+    if (i < XIDDATASIZE)
+    {
+      char ch= xid->data[i+1];
+      is_next_dig= (ch >= '0' && ch <='9');
+    }
+    if (i == xid->gtrid_length)
+    {
+      *s++='\'';
+      if (xid->bqual_length)
+      {
+        *s++='.';
+        *s++='\'';
+      }
+    }
+    if (c < 32 || c > 126)
+    {
+      *s++='\\';
+      /*
+        If next character is a number, write current character with
+        3 octal numbers to ensure that the next number is not seen
+        as part of the octal number
+      */
+      if (c > 077 || is_next_dig)
+        *s++=_dig_vec_lower[c >> 6];
+      if (c > 007 || is_next_dig)
+        *s++=_dig_vec_lower[(c >> 3) & 7];
+      *s++=_dig_vec_lower[c & 7];
+    }
+    else
+    {
+      if (c == '\'' || c == '\\')
+        *s++='\\';
+      *s++=c;
+    }
+  }
+  *s++='\'';
+  *s=0;
+  return buf;
+}
+#endif
+
 /*
   recover() step of xa
+
+  NOTE
+   there are three modes of operation:
+
+   - automatic recover after a crash
+     in this case commit_list != 0, tc_heuristic_recover==0
+     all xids from commit_list are committed, others are rolled back
+
+   - manual (heuristic) recover
+     in this case commit_list==0, tc_heuristic_recover != 0
+     DBA has explicitly specified that all prepared transactions should
+     be committed (or rolled back).
+
+   - no recovery (MySQL did not detect a crash)
+     in this case commit_list==0, tc_heuristic_recover == 0
+     there should be no prepared transactions in this case.
 */
 int ha_recover(HASH *commit_list)
 {
-  int len, got;
+  int len, got, found_foreign_xids=0, found_my_xids=0;
   handlerton **ht= handlertons, **end_ht=ht+total_ha;
   XID *list=0;
+  bool dry_run=(commit_list==0 && tc_heuristic_recover==0);
   DBUG_ENTER("ha_recover");
 
-  DBUG_ASSERT(total_ha_2pc);
-  DBUG_ASSERT(commit_list || tc_heuristic_recover);
+  /* commit_list and tc_heuristic_recover cannot be set both */
+  DBUG_ASSERT(commit_list==0 || tc_heuristic_recover==0);
+  /* if either is set, total_ha_2pc must be set too */
+  DBUG_ASSERT(dry_run || total_ha_2pc>(ulong)opt_bin_log);
+
+  if (total_ha_2pc <= (ulong)opt_bin_log)
+    DBUG_RETURN(0);
+
+  if (commit_list)
+    sql_print_information("Starting crash recovery...");
+
+#ifndef WILL_BE_DELETED_LATER
+  /*
+    for now, only InnoDB supports 2pc. It means we can always safely
+    rollback all pending transactions, without risking inconsistent data
+  */
+  DBUG_ASSERT(total_ha_2pc == (ulong) opt_bin_log+1); // only InnoDB and binlog
+  tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
+  dry_run=FALSE;
+#endif
 
   for (len= MAX_XID_LIST_SIZE ; list==0 && len > MIN_XID_LIST_SIZE; len/=2)
   {
@@ -785,7 +907,7 @@
   }
   if (!list)
   {
-    my_error(ER_OUTOFMEMORY, MYF(0), len);
+    sql_print_error(ER(ER_OUTOFMEMORY), len*sizeof(XID));
     DBUG_RETURN(1);
   }
 
@@ -795,23 +917,65 @@
       continue;
     while ((got=(*(*ht)->recover)(list, len)) > 0 )
     {
+      sql_print_information("Found %d prepared transaction(s) in %s",
+                            got, (*ht)->name);
       for (int i=0; i < got; i ++)
       {
         my_xid x=list[i].get_my_xid();
         if (!x) // not "mine" - that is generated by external TM
+        {
+#ifndef DBUG_OFF
+          char buf[XIDDATASIZE*4+6]; // see xid_to_str
+          sql_print_information("ignore xid %s", xid_to_str(buf, list+i));
+#endif
+          found_foreign_xids++;
           continue;
+        }
+        if (dry_run)
+        {
+          found_my_xids++;
+          continue;
+        }
+        // recovery mode
         if (commit_list ?
             hash_search(commit_list, (byte *)&x, sizeof(x)) != 0 :
             tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
+        {
+#ifndef DBUG_OFF
+          char buf[XIDDATASIZE*4+6]; // see xid_to_str
+          sql_print_information("commit xid %s", xid_to_str(buf, list+i));
+#endif
           (*(*ht)->commit_by_xid)(list+i);
+        }
         else
+        {
+#ifndef DBUG_OFF
+          char buf[XIDDATASIZE*4+6]; // see xid_to_str
+          sql_print_information("rollback xid %s", xid_to_str(buf, list+i));
+#endif
           (*(*ht)->rollback_by_xid)(list+i);
+        }
       }
       if (got < len)
         break;
     }
   }
   my_free((gptr)list, MYF(0));
+  if (found_foreign_xids)
+    sql_print_warning("Found %d prepared XA transactions", found_foreign_xids);
+  if (dry_run && found_my_xids)
+  {
+    sql_print_error("Found %d prepared transactions! It means that mysqld was "
+                    "not shut down properly last time and critical recovery "
+                    "information (last binlog or %s file) was manually deleted "
+                    "after a crash. You have to start mysqld with "
+                    "--tc-heuristic-recover switch to commit or rollback "
+                    "pending transactions.",
+                    found_my_xids, opt_tc_log_file);
+    DBUG_RETURN(1);
+  }
+  if (commit_list)
+    sql_print_information("Crash recovery finished.");
   DBUG_RETURN(0);
 }
 
@@ -864,9 +1028,9 @@
         if (xid->get_my_xid())
           continue; // skip "our" xids
         protocol->prepare_for_resend();
-        protocol->store_long((longlong)xid->formatID);
-        protocol->store_long((longlong)xid->gtrid_length);
-        protocol->store_long((longlong)xid->bqual_length);
+        protocol->store_longlong((longlong)xid->formatID, FALSE);
+        protocol->store_longlong((longlong)xid->gtrid_length, FALSE);
+        protocol->store_longlong((longlong)xid->bqual_length, FALSE);
         protocol->store(xid->data, xid->gtrid_length+xid->bqual_length,
                         &my_charset_bin);
         if (protocol->write())
@@ -1409,7 +1573,7 @@
 /*
   Print error that we got from handler function
 
-  NOTE:
+  NOTE
    In case of delete table it's only safe to use the following parts of
    the 'table' structure:
      table->s->path
@@ -1570,7 +1734,7 @@
    SYNOPSIS
    error        error code previously returned by handler
    buf          Pointer to String where to add error message
-   
+
    Returns true if this is a temporary error
  */
 
@@ -1606,18 +1770,20 @@
 
   RETURN
     0   If we successfully deleted at least one file from base_ext and
-	didn't get any other errors than ENOENT    
-    #   Error from delete_file()
+	didn't get any other errors than ENOENT
+    #   Error
 */
 
 int handler::delete_table(const char *name)
 {
   int error= 0;
   int enoent_or_zero= ENOENT;                   // Error if no file was deleted
+  char buff[FN_REFLEN];
 
   for (const char **ext=bas_ext(); *ext ; ext++)
   {
-    if (delete_file(name,*ext,2))
+    fn_format(buff, name, "", *ext, 2 | 4);
+    if (my_delete_with_symlink(buff, MYF(0)))
     {
       if ((error= my_errno) != ENOENT)
 	break;
@@ -1642,7 +1808,12 @@
 }
 
 /*
-  Tell the handler to turn on or off transaction in the handler
+  Tell the storage engine that it is allowed to "disable transaction" in the
+  handler. It is a hint that ACID is not required - it is used in NDB for
+  ALTER TABLE, for example, when data are copied to temporary table.
+  A storage engine may treat this hint any way it likes. NDB for example
+  starts to commit every now and then automatically.
+  This hint can be safely ignored.
 */
 
 int ha_enable_transaction(THD *thd, bool on)
@@ -1652,7 +1823,15 @@
   DBUG_ENTER("ha_enable_transaction");
   thd->transaction.on= on;
   if (on)
-    ha_commit(thd);
+  {
+    /*
+      Now all storage engines should have transaction handling enabled.
+      But some may have it enabled all the time - "disabling" transactions
+      is an optimization hint that storage engine is free to ignore.
+      So, let's commit an open transaction (if any) now.
+    */
+    error= end_trans(thd, COMMIT);
+  }
   DBUG_RETURN(error);
 }
 
@@ -1775,13 +1954,6 @@
   DBUG_RETURN(error);  
 }
 
-static int NEAR_F delete_file(const char *name,const char *ext,int extflag)
-{
-  char buff[FN_REFLEN];
-  VOID(fn_format(buff,name,"",ext,extflag | 4));
-  return(my_delete_with_symlink(buff,MYF(MY_WME)));
-}
-
 void st_ha_check_opt::init()
 {
   flags= sql_flags= 0;
@@ -2231,6 +2403,7 @@
 
     known_extensions_id= mysys_usage_id;
     found_exts.push_back((char*) ".db");
+    found_exts.push_back((char*) triggers_file_ext);
     for (types= sys_table_types; types->type; types++)
     {      
       if (*types->value == SHOW_OPTION_YES)

--- 1.142/sql/handler.h	Mon Mar 21 23:36:32 2005
+++ 1.143/sql/handler.h	Tue Apr  5 17:34:13 2005
@@ -162,8 +162,9 @@
   DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB,
   DB_TYPE_GEMINI, DB_TYPE_NDBCLUSTER,
   DB_TYPE_EXAMPLE_DB, DB_TYPE_ARCHIVE_DB, DB_TYPE_CSV_DB,
-  DB_TYPE_FEDERATED_DB, DB_TYPE_PARTITION_DB,
-
+  DB_TYPE_FEDERATED_DB,
+  DB_TYPE_BLACKHOLE_DB,
+  DB_TYPE_PARTITION_DB,
   DB_TYPE_DEFAULT // Must be last
 };
 
@@ -276,6 +277,10 @@
 typedef struct
 {
   /*
+    storage engine name as it should be printed to a user
+  */
+  const char *name;
+  /*
     each storage engine has it's own memory area (actually a pointer)
     in the thd, for storing per-connection information.
     It is accessed as
@@ -507,7 +512,7 @@
 extern ulong savepoint_alloc_size;
 
 /* Forward declaration for condition pushdown to storage engine */
-typedef struct Item COND;
+typedef class Item COND;
 
 typedef struct st_ha_check_opt
 {
@@ -976,10 +981,20 @@
 int ha_commit_trans(THD *thd, bool all);
 int ha_autocommit_or_rollback(THD *thd, int error);
 int ha_enable_transaction(THD *thd, bool on);
-void trans_register_ha(THD *thd, bool all, handlerton *ht);
 
 /* savepoints */
 int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv);
 int ha_savepoint(THD *thd, SAVEPOINT *sv);
 int ha_release_savepoint(THD *thd, SAVEPOINT *sv);
+
+/* these are called by storage engines */
+void trans_register_ha(THD *thd, bool all, handlerton *ht);
+
+/*
+  Storage engine has to assume the transaction will end up with 2pc if
+   - there is more than one 2pc-capable storage engine available
+   - in the current transaction 2pc was not disabled yet
+*/
+#define trans_need_2pc(thd, all)                   ((total_ha_2pc > 1) && \
+        !((all ? &thd->transaction.all :
&thd->transaction.stmt)->no_2pc))
 

--- 1.256/sql/mysql_priv.h	Wed Mar 23 17:57:02 2005
+++ 1.257/sql/mysql_priv.h	Tue Apr  5 17:34:13 2005
@@ -44,6 +44,13 @@
 typedef Bitmap<64> key_map;           /* Used for finding keys */
 typedef ulong key_part_map;           /* Used for finding key parts */
 
+/* query_id */
+typedef ulonglong query_id_t;
+extern query_id_t query_id;
+
+/* increment query_id and return it.  */
+inline query_id_t next_query_id() { return query_id++; }
+
 /* useful constants */
 extern const key_map key_map_empty;
 extern const key_map key_map_full;
@@ -257,6 +264,12 @@
 /* Flag set if setup_tables already done */
 #define OPTION_SETUP_TABLES_DONE        (1L << 30)
 
+/* 
+  Maximum length of time zone name that we support 
+  (Time zone name is char(64) in db). mysqlbinlog needs it.
+*/
+#define MAX_TIME_ZONE_NAME_LENGTH 72
+
 /* The rest of the file is included in the server only */
 #ifndef MYSQL_CLIENT
 
@@ -299,6 +312,10 @@
   use strictly more than 64 bits by adding one more define above, you should
   contact the replication team because the replication code should then be
   updated (to store more bytes on disk).
+
+  NOTE: When adding new SQL_MODE types, make sure to also add them to
+  ../scripts/mysql_create_system_tables.sh and
+  ../scripts/mysql_fix_privilege_tables.sql
 */
 
 #define RAID_BLOCK_SIZE 1024
@@ -425,7 +442,6 @@
 typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
                                       uint key_length,
                                       ulonglong *engine_data);
-
 #include "sql_string.h"
 #include "sql_list.h"
 #include "sql_map.h"
@@ -433,6 +449,7 @@
 #include "handler.h"
 #include "parse_file.h"
 #include "table.h"
+#include "sql_error.h"
 #include "field.h"				/* Field definitions */
 #include "protocol.h"
 #include "sql_udf.h"
@@ -453,6 +470,7 @@
 bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
 bool check_merge_table_access(THD *thd, char *db,
 			      TABLE_LIST *table_list);
+bool check_some_routine_access(THD *thd, const char *db, const char *name);
 bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
 bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
 bool mysql_multi_update_prepare(THD *thd);
@@ -635,12 +653,12 @@
 int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
 Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
 			Item ***copy_func, Field **from_field,
-			bool group, bool modify_item, uint convert_blob_length);
-int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
-		       List<create_field> &fields,
-		       List<Key> &keys, uint &db_options, 
-		       handler *file, KEY *&key_info_buffer,
-		       uint &key_count, int select_field_count);
+			bool group, bool modify_item,
+                        uint convert_blob_length);
+int prepare_create_field(create_field *sql_field, 
+			 uint *blob_columns, 
+			 int *timestamps, int *timestamps_with_niladic,
+			 uint table_flags);
 bool mysql_create_table(THD *thd,const char *db, const char *table_name,
                         HA_CREATE_INFO *create_info,
                         List<create_field> &fields, List<Key> &keys,
@@ -660,7 +678,7 @@
                        uint order_num, ORDER *order,
                        enum enum_duplicates handle_duplicates,
                        bool ignore,
-                       ALTER_INFO *alter_info, bool do_send_ok=1);
+                       ALTER_INFO *alter_info, bool do_send_ok);
 bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
 bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
                              HA_CREATE_INFO *create_info,
@@ -704,7 +722,7 @@
 		  bool *refresh);
 TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table);
 TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
-bool reopen_table(TABLE *table,bool locked=0);
+bool reopen_table(TABLE *table,bool locked);
 bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
 void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
 			  bool send_refresh);
@@ -770,7 +788,7 @@
 		       uint length);
 int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
 void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
-int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd = -1);
+int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
 bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
 bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
 
@@ -791,7 +809,7 @@
 extern LEX_STRING information_schema_name;
 LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
                             const char* str, uint length,
-                            bool allocate_lex_string= 0);
+                            bool allocate_lex_string);
 ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name);
 ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx);
 int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
@@ -807,7 +825,7 @@
 
 /* sql_prepare.cc */
 bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, 
-                        LEX_STRING *name=NULL);
+                        LEX_STRING *name);
 void mysql_stmt_execute(THD *thd, char *packet, uint packet_length);
 void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name);
 void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length);
@@ -815,17 +833,10 @@
 void mysql_stmt_reset(THD *thd, char *packet);
 void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
 void reset_stmt_for_execute(THD *thd, LEX *lex);
-
-/* sql_error.cc */
-MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
-                          const char *msg);
-void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
-			 uint code, const char *format, ...);
-void mysql_reset_errors(THD *thd);
-bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
+void init_stmt_after_parse(THD*, LEX*);
 
 /* sql_handler.cc */
-bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen= 0);
+bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen);
 bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
 bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
                    List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
@@ -846,16 +857,23 @@
 		       char *change, List<String> *interval_list,
 		       CHARSET_INFO *cs,
 		       uint uint_geom_type);
+create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
+				char *length, char *decimals,
+				uint type_modifier, 
+				Item *default_value, Item *on_update_value,
+				LEX_STRING *comment, char *change, 
+				List<String> *interval_list, CHARSET_INFO *cs,
+				uint uint_geom_type);
 void store_position_for_column(const char *name);
-bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc=0);
+bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc);
 void add_join_on(TABLE_LIST *b,Item *expr);
 void add_join_natural(TABLE_LIST *a,TABLE_LIST *b);
 bool add_proc_to_list(THD *thd, Item *item);
 TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
 
 SQL_SELECT *make_select(TABLE *head, table_map const_tables,
-			table_map read_tables, COND *conds, int *error,
-                        bool allow_null_cond= false);
+			table_map read_tables, COND *conds,
+                        bool allow_null_cond,  int *error);
 extern Item **not_found_item;
 Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
                           find_item_error_report_type report_error,
@@ -879,7 +897,7 @@
 int setup_ftfuncs(SELECT_LEX* select);
 int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
 void wait_for_refresh(THD *thd);
-int open_tables(THD *thd, TABLE_LIST *tables, uint *counter);
+int open_tables(THD *thd, TABLE_LIST **tables, uint *counter);
 int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
 bool open_and_lock_tables(THD *thd,TABLE_LIST *tables);
 bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables);
@@ -898,13 +916,13 @@
 TABLE_LIST *unique_table(TABLE_LIST *table, TABLE_LIST *table_list);
 TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
 bool close_temporary_table(THD *thd, const char *db, const char *table_name);
-void close_temporary(TABLE *table, bool delete_table=1);
+void close_temporary(TABLE *table, bool delete_table);
 bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
 			    const char *table_name);
 void remove_db_from_cache(const char *db);
 void flush_tables();
 bool remove_table_from_cache(THD *thd, const char *db, const char *table,
-			     bool return_if_owned_by_thd=0);
+			     bool return_if_owned_by_thd);
 bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables);
 void copy_field_from_tmp_record(Field *field,int offset);
 bool fill_record(THD *thd, List<Item> &fields, List<Item> &values,
@@ -935,8 +953,10 @@
 
 /* sql_load.cc */
 bool mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list,
-	        List<Item> &fields, enum enum_duplicates handle_duplicates,
-                bool ignore, bool local_file, thr_lock_type lock_type);
+	        List<Item> &fields_vars, List<Item> &set_fields,
+                List<Item> &set_values_list,
+                enum enum_duplicates handle_duplicates, bool ignore,
+                bool local_file);
 int write_record(THD *thd, TABLE *table, COPY_INFO *info);
 
 /* sql_manager.cc */
@@ -1021,6 +1041,7 @@
 extern const char **errmesg;			/* Error messages */
 extern const char *myisam_recover_options_str;
 extern const char *in_left_expr_name, *in_additional_cond;
+extern const char * const triggers_file_ext;
 extern Eq_creator eq_creator;
 extern Ne_creator ne_creator;
 extern Gt_creator gt_creator;
@@ -1030,7 +1051,7 @@
 extern char language[FN_REFLEN], reg_ext[FN_EXTLEN];
 extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
 extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
-extern char log_error_file[FN_REFLEN];
+extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
 extern double last_query_cost;
 extern double log_10[32];
 extern ulonglong log_10_int[20];
@@ -1047,7 +1068,7 @@
 extern ulong thd_startup_options, slow_launch_threads, slow_launch_time;
 extern ulong table_cache_size;
 extern ulong max_connections,max_connect_errors, connect_timeout;
-extern ulong slave_net_timeout;
+extern ulong slave_net_timeout, slave_trans_retries;
 extern uint max_user_connections;
 extern ulong what_to_log,flush_time;
 extern ulong query_buff_size, thread_stack,thread_stack_min;
@@ -1073,7 +1094,7 @@
 extern my_bool opt_safe_show_db, opt_local_infile;
 extern my_bool opt_slave_compressed_protocol, use_temp_pool;
 extern my_bool opt_readonly, lower_case_file_system;
-extern my_bool opt_enable_named_pipe, opt_sync_frm;
+extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
 extern my_bool opt_secure_auth;
 extern my_bool sp_automatic_privileges;
 extern my_bool opt_old_style_user_limits;
@@ -1092,7 +1113,7 @@
        LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status,
        LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
        LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
-       LOCK_slave_list, LOCK_active_mi, LOCK_manager,
+       LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock,
        LOCK_global_system_variables, LOCK_user_conn;
 extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
 extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
@@ -1132,6 +1153,7 @@
 extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
 extern SHOW_COMP_OPTION have_crypt;
 extern SHOW_COMP_OPTION have_compress;
+extern SHOW_COMP_OPTION have_blackhole_db;
 extern SHOW_COMP_OPTION have_partition_db;
 
 #ifndef __WIN__
@@ -1164,7 +1186,7 @@
 bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
 bool lock_table_names(THD *thd, TABLE_LIST *table_list);
 void unlock_table_names(THD *thd, TABLE_LIST *table_list,
-			TABLE_LIST *last_table= 0);
+			TABLE_LIST *last_table);
 
 
 /* old unireg functions */
@@ -1174,9 +1196,8 @@
 bool mysql_create_frm(THD *thd, my_string file_name,
 		      HA_CREATE_INFO *create_info,
 		      List<create_field> &create_field,
-		      uint key_count,KEY *key_info, handler *file);
-int rea_create_table(THD *thd, my_string file_name,
-                     HA_CREATE_INFO *create_info,
+		      uint key_count,KEY *key_info,handler *db_type);
+int rea_create_table(THD *thd, my_string file_name,HA_CREATE_INFO *create_info,
 		     List<create_field> &create_field,
 		     uint key_count,KEY *key_info, handler *file);
 int format_number(uint inputflag,uint max_length,my_string pos,uint length,
@@ -1291,14 +1312,6 @@
 #endif
 
 #include "sql_view.h"
-
-/* query_id */
-
-typedef ulonglong query_id_t;
-extern query_id_t query_id;
-
-/* increment query_id and return it.  */
-inline query_id_t next_query_id() { return query_id++; }
 
 /* Some inline functions for more speed */
 

--- 1.421/sql/mysqld.cc	Tue Mar  1 22:38:52 2005
+++ 1.422/sql/mysqld.cc	Tue Apr  5 15:01:12 2005
@@ -309,7 +309,7 @@
 ulong opt_ndb_nodeid;
 #endif
 my_bool opt_readonly, use_temp_pool, relay_log_purge;
-my_bool opt_sync_bdb_logs, opt_sync_frm;
+my_bool opt_sync_bdb_logs, opt_sync_frm, opt_allow_suspicious_udfs;
 my_bool opt_secure_auth= 0;
 my_bool opt_short_log_format= 0;
 my_bool opt_log_queries_not_using_indexes= 0;
@@ -338,7 +338,7 @@
 ulong table_cache_size, thread_stack, thread_stack_min, what_to_log;
 ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
 ulong open_files_limit, max_binlog_size, max_relay_log_size;
-ulong slave_net_timeout;
+ulong slave_net_timeout, slave_trans_retries;
 ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
 ulong query_cache_size=0;
 ulong refresh_version, flush_version;	/* Increments on each reload */
@@ -370,7 +370,7 @@
 char mysql_real_data_home[FN_REFLEN],
      language[FN_REFLEN], reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN],
      *mysqld_user,*mysqld_chroot, *opt_init_file,
-     *opt_init_connect, *opt_init_slave,
+     *opt_init_connect, *opt_init_slave, *opt_tc_log_file,
      def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
 
 const char *opt_date_time_formats[3];
@@ -425,13 +425,14 @@
 SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache;
 SHOW_COMP_OPTION have_geometry, have_rtree_keys;
 SHOW_COMP_OPTION have_crypt, have_compress;
+SHOW_COMP_OPTION have_blackhole_db;
 
 /* Thread specific variables */
 
 pthread_key(MEM_ROOT**,THR_MALLOC);
 pthread_key(THD*, THR_THD);
 pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
-		LOCK_mapped_file, LOCK_status,
+		LOCK_mapped_file, LOCK_status, LOCK_global_read_lock,
 		LOCK_error_log, LOCK_uuid_generator,
 		LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
 		LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
@@ -462,7 +463,7 @@
 static int cleanup_done;
 static ulong opt_specialflag, opt_myisam_block_size;
 static char *opt_logname, *opt_update_logname, *opt_binlog_index_name;
-static char *opt_slow_logname, *opt_tc_log_file, *opt_tc_heuristic_recover;
+static char *opt_slow_logname, *opt_tc_heuristic_recover;
 static char *mysql_home_ptr, *pidfile_name_ptr;
 static char **defaults_argv;
 static char *opt_bin_logname;
@@ -1040,8 +1041,8 @@
     (void) my_delete(pidfile_name,MYF(0));	// This may not always exist
 #endif
   finish_client_errs();
-  const char **errmsgs= my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST);
-  x_free((gptr) errmsgs);	/* Free messages */
+  my_free((gptr) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST),
+          MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
   DBUG_PRINT("quit", ("Error messages freed"));
   /* Tell main we are ready */
   (void) pthread_mutex_lock(&LOCK_thread_count);
@@ -1107,6 +1108,7 @@
   (void) rwlock_destroy(&LOCK_sys_init_connect);
   (void) rwlock_destroy(&LOCK_sys_init_slave);
   (void) pthread_mutex_destroy(&LOCK_global_system_variables);
+  (void) pthread_mutex_destroy(&LOCK_global_read_lock);
   (void) pthread_cond_destroy(&COND_thread_count);
   (void) pthread_cond_destroy(&COND_refresh);
   (void) pthread_cond_destroy(&COND_thread_cache);
@@ -1467,7 +1469,8 @@
 		      errcode ? ER(errcode) : ""));
   if (lock)
     (void) pthread_mutex_lock(&LOCK_thread_count);
-  if ((vio=thd->net.vio) != 0)
+  thd->killed= THD::KILL_CONNECTION;
+  if ((vio= thd->net.vio) != 0)
   {
     if (errcode)
       net_send_error(thd, errcode, ER(errcode)); /* purecov: inspected */
@@ -2598,6 +2601,7 @@
   (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
   (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
   (void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
+  (void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST);
   (void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
   (void) my_rwlock_init(&LOCK_sys_init_connect, NULL);
   (void) my_rwlock_init(&LOCK_sys_init_slave, NULL);
@@ -2804,6 +2808,11 @@
     unireg_abort(1);
   }
 
+  if (ha_recover(0))
+  {
+    unireg_abort(1);
+  }
+
   if (opt_bin_log && mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0,
                                         WRITE_CACHE, 0, max_binlog_size, 0))
       unireg_abort(1);
@@ -3131,8 +3140,17 @@
 #endif
   if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
     opt_skip_slave_start= 1;
-  /* init_slave() must be called after the thread keys are created */
-  init_slave();
+  /*
+    init_slave() must be called after the thread keys are created.
+    Some parts of the code (e.g. SHOW STATUS LIKE 'slave_running' and other
+    places) assume that active_mi != 0, so let's fail if it's 0 (out of
+    memory); a message has already been printed.
+  */
+  if (init_slave() && !active_mi)
+  {
+    end_thr_alarm(1);				// Don't allow alarms
+    unireg_abort(1);
+  }
 
   if (opt_bootstrap)
   {
@@ -3152,13 +3170,11 @@
   create_shutdown_thread();
   create_maintenance_thread();
 
-  printf(ER(ER_READY),my_progname,server_version,
-	 ((unix_sock == INVALID_SOCKET) ? (char*) "" : mysqld_unix_port),
-	 mysqld_port);
-  if (MYSQL_COMPILATION_COMMENT[0] != '\0')
-    fputs("  " MYSQL_COMPILATION_COMMENT, stdout);
-  putchar('\n');
-  fflush(stdout);
+  sql_print_information(ER(ER_STARTUP),my_progname,server_version,
+                        ((unix_sock == INVALID_SOCKET) ? (char*) ""
+                                                       : mysqld_unix_port),
+                         mysqld_port,
+                         MYSQL_COMPILATION_COMMENT);
 
 #if defined(__NT__) || defined(HAVE_SMEM)
   handle_connections_methods();
@@ -3309,9 +3325,10 @@
 int main(int argc, char **argv)
 {
 
-  /* When several instances are running on the same machine, we
-     need to have an  unique  named  hEventShudown  through the
-     application PID e.g.: MySQLShutdown1890; MySQLShutdown2342
+  /*
+    When several instances are running on the same machine, we
+    need to have an  unique  named  hEventShudown  through the
+    application PID e.g.: MySQLShutdown1890; MySQLShutdown2342
   */
   int10_to_str((int) GetCurrentProcessId(),strmov(shutdown_event_name,
                                                   "MySQLShutdown"), 10);
@@ -3752,7 +3769,7 @@
     if (!(vio_tmp=vio_new(new_sock,
 			  sock == unix_sock ? VIO_TYPE_SOCKET :
 			  VIO_TYPE_TCPIP,
-			  sock == unix_sock)) ||
+			  sock == unix_sock ? VIO_LOCALHOST: 0)) ||
 	my_net_init(&thd->net,vio_tmp))
     {
       if (vio_tmp)
@@ -3890,10 +3907,19 @@
   char *suffix_pos;
   char connect_number_char[22], *p;
   const char *errmsg= 0;
+  SECURITY_ATTRIBUTES *sa_event= 0, *sa_mapping= 0;
   my_thread_init();
   DBUG_ENTER("handle_connections_shared_memorys");
   DBUG_PRINT("general",("Waiting for allocated shared memory."));
 
+  if (my_security_attr_create(&sa_event, &errmsg,
+                              GENERIC_ALL, SYNCHRONIZE | EVENT_MODIFY_STATE))
+    goto error;
+
+  if (my_security_attr_create(&sa_mapping, &errmsg,
+                             GENERIC_ALL, FILE_MAP_READ | FILE_MAP_WRITE))
+    goto error;
+
   /*
     The name of event and file-mapping events create agree next rule:
       shared_memory_base_name+unique_part
@@ -3903,22 +3929,22 @@
   */
   suffix_pos= strxmov(tmp,shared_memory_base_name,"_",NullS);
   strmov(suffix_pos, "CONNECT_REQUEST");
-  if ((smem_event_connect_request= CreateEvent(0,FALSE,FALSE,tmp)) == 0)
+  if ((smem_event_connect_request= CreateEvent(sa_event,
+                                               FALSE, FALSE, tmp)) == 0)
   {
     errmsg= "Could not create request event";
     goto error;
   }
   strmov(suffix_pos, "CONNECT_ANSWER");
-  if ((event_connect_answer= CreateEvent(0,FALSE,FALSE,tmp)) == 0)
+  if ((event_connect_answer= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
   {
     errmsg="Could not create answer event";
     goto error;
   }
   strmov(suffix_pos, "CONNECT_DATA");
-  if ((handle_connect_file_map= CreateFileMapping(INVALID_HANDLE_VALUE,0,
-						   PAGE_READWRITE,
-						   0,sizeof(connect_number),
-						   tmp)) == 0)
+  if ((handle_connect_file_map=
+       CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
+                         PAGE_READWRITE, 0, sizeof(connect_number), tmp)) == 0)
   {
     errmsg= "Could not create file mapping";
     goto error;
@@ -3963,10 +3989,9 @@
     suffix_pos= strxmov(tmp,shared_memory_base_name,"_",connect_number_char,
 			 "_",NullS);
     strmov(suffix_pos, "DATA");
-    if ((handle_client_file_map= CreateFileMapping(INVALID_HANDLE_VALUE,0,
-						    PAGE_READWRITE,0,
-						    smem_buffer_length,
-						    tmp)) == 0)
+    if ((handle_client_file_map=
+         CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
+                           PAGE_READWRITE, 0, smem_buffer_length, tmp)) == 0)
     {
       errmsg= "Could not create file mapping";
       goto errorconn;
@@ -3979,31 +4004,33 @@
       goto errorconn;
     }
     strmov(suffix_pos, "CLIENT_WROTE");
-    if ((event_client_wrote= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
+    if ((event_client_wrote= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create client write event";
       goto errorconn;
     }
     strmov(suffix_pos, "CLIENT_READ");
-    if ((event_client_read= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
+    if ((event_client_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create client read event";
       goto errorconn;
     }
     strmov(suffix_pos, "SERVER_READ");
-    if ((event_server_read= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
+    if ((event_server_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create server read event";
       goto errorconn;
     }
     strmov(suffix_pos, "SERVER_WROTE");
-    if ((event_server_wrote= CreateEvent(0, FALSE, FALSE, tmp)) == 0)
+    if ((event_server_wrote= CreateEvent(sa_event,
+                                         FALSE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create server write event";
       goto errorconn;
     }
     strmov(suffix_pos, "CONNECTION_CLOSED");
-    if ((event_conn_closed= CreateEvent(0, TRUE , FALSE, tmp)) == 0)
+    if ((event_conn_closed= CreateEvent(sa_event,
+                                        TRUE, FALSE, tmp)) == 0)
     {
       errmsg= "Could not create closed connection event";
       goto errorconn;
@@ -4078,6 +4105,8 @@
     strxmov(buff, "Can't create shared memory service: ", errmsg, ".", NullS);
     sql_perror(buff);
   }
+  my_security_attr_free(sa_event);
+  my_security_attr_free(sa_mapping);
   if (handle_connect_map)	UnmapViewOfFile(handle_connect_map);
   if (handle_connect_file_map)	CloseHandle(handle_connect_file_map);
   if (event_connect_answer)	CloseHandle(event_connect_answer);
@@ -4197,7 +4226,7 @@
   OPT_QUERY_CACHE_TYPE, OPT_QUERY_CACHE_WLOCK_INVALIDATE, OPT_RECORD_BUFFER,
   OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE,
   OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
-  OPT_READONLY, OPT_DEBUGGING,
+  OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_DEBUGGING,
   OPT_SORT_BUFFER, OPT_TABLE_CACHE,
   OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
   OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK,
@@ -4217,6 +4246,7 @@
   OPT_INNODB_STATUS_FILE,
   OPT_INNODB_MAX_DIRTY_PAGES_PCT,
   OPT_INNODB_TABLE_LOCKS,
+  OPT_INNODB_SUPPORT_XA,
   OPT_INNODB_OPEN_FILES,
   OPT_INNODB_AUTOEXTEND_INCREMENT,
   OPT_INNODB_SYNC_SPIN_LOOPS,
@@ -4227,7 +4257,7 @@
   OPT_BDB_MAX_LOCK,
   OPT_ERROR_LOG_FILE,
   OPT_DEFAULT_WEEK_FORMAT,
-  OPT_RANGE_ALLOC_BLOCK_SIZE,
+  OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_ALLOW_SUSPICIOUS_UDFS,
   OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE,
   OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE,
   OPT_SYNC_FRM, OPT_SYNC_BINLOG,
@@ -4275,6 +4305,13 @@
 #endif /* HAVE_REPLICATION */
   {"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode will also set
transaction isolation level 'serializable'.", 0, 0, 0,
    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+  {"allow-suspicious-udfs", OPT_ALLOW_SUSPICIOUS_UDFS,
+   "Allows use of UDFs consisting of only one symbol xxx() "
+   "without corresponding xxx_init() or xxx_deinit(). That also means "
+   "that one can load any function from any library, for example exit() "
+   "from libc.so",
+   (gptr*) &opt_allow_suspicious_udfs, (gptr*) &opt_allow_suspicious_udfs,
+   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
   {"auto-increment-increment", OPT_AUTO_INCREMENT,
    "Auto-increment columns are incremented by this",
    (gptr*) &global_system_variables.auto_increment_increment,
@@ -4513,6 +4550,11 @@
    (gptr*) &global_system_variables.innodb_table_locks,
    (gptr*) &global_system_variables.innodb_table_locks,
    0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+  {"innodb_support_xa", OPT_INNODB_SUPPORT_XA,
+   "Enable InnoDB support for the XA two-phase commit",
+   (gptr*) &global_system_variables.innodb_support_xa,
+   (gptr*) &global_system_variables.innodb_support_xa,
+   0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
 #endif /* End HAVE_INNOBASE_DB */
   {"isam", OPT_ISAM, "Enable ISAM (if this version of MySQL supports it). \
 Disable with --skip-isam.",
@@ -4571,7 +4613,7 @@
    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
   {"log-tc-size", OPT_LOG_TC_SIZE, "Size of transaction coordinator log.",
    (gptr*) &opt_tc_log_size, (gptr*) &opt_tc_log_size, 0, GET_ULONG,
-   REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ~0, 0, TC_LOG_PAGE_SIZE, 0},
+   REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ~0L, 0, TC_LOG_PAGE_SIZE, 0},
   {"log-update", OPT_UPDATE_LOG,
    "The update log is deprecated since version 5.0, is replaced by the binary \
 log and this option justs turns on --log-bin instead.",
@@ -5210,7 +5252,7 @@
    "Max number of errors/warnings to store for a statement.",
    (gptr*) &global_system_variables.max_error_count,
    (gptr*) &max_system_variables.max_error_count,
-   0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 1, 65535, 0, 1, 0},
+   0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 0, 65535, 0, 1, 0},
   {"max_heap_table_size", OPT_MAX_HEP_TABLE_SIZE,
    "Don't allow creation of heap tables bigger than this.",
    (gptr*) &global_system_variables.max_heap_table_size,
@@ -5227,7 +5269,7 @@
     (gptr*) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG,
     REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
   {"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE,
-   "If non-zero: relay log will be rotated automatically when the size exceeds this
value; if zero (the default): when the size exceeds max_binlog_size. 0 expected, the
minimum value for this variable is 4096.",
+   "If non-zero: relay log will be rotated automatically when the size exceeds this
value; if zero (the default): when the size exceeds max_binlog_size. 0 excepted, the
minimum value for this variable is 4096.",
    (gptr*) &max_relay_log_size, (gptr*) &max_relay_log_size, 0, GET_ULONG,
    REQUIRED_ARG, 0L, 0L, 1024*1024L*1024L, 0, IO_SIZE, 0},
   { "max_seeks_for_key", OPT_MAX_SEEKS_FOR_KEY,
@@ -5413,6 +5455,12 @@
    "Number of seconds to wait for more data from a master/slave connection before
aborting the read.",
    (gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0,
    GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
+  {"slave_transaction_retries", OPT_SLAVE_TRANS_RETRIES,
+   "Number of times the slave SQL thread will retry a transaction in case "
+   "it failed with a deadlock or elapsed lock wait timeout, "
+   "before giving up and stopping.",
+   (gptr*) &slave_trans_retries, (gptr*) &slave_trans_retries, 0,
+   GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
 #endif /* HAVE_REPLICATION */
   {"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
    "If creating the thread takes longer than this value (in seconds), the
Slow_launch_threads counter will be incremented.",
@@ -5668,7 +5716,8 @@
   {"Select_range_check",       (char*) offsetof(STATUS_VAR, select_range_check_count),
SHOW_LONG_STATUS},
   {"Select_scan",	       (char*) offsetof(STATUS_VAR, select_scan_count),
SHOW_LONG_STATUS},
   {"Slave_open_temp_tables",   (char*) &slave_open_temp_tables, SHOW_LONG},
-  {"Slave_running",            (char*) 0, SHOW_SLAVE_RUNNING},
+  {"Slave_running",            (char*) 0,                       SHOW_SLAVE_RUNNING},
+  {"Slave_retried_transactions",(char*) 0,                     
SHOW_SLAVE_RETRIED_TRANS},
   {"Slow_launch_threads",      (char*) &slow_launch_threads,    SHOW_LONG},
   {"Slow_queries",             (char*) offsetof(STATUS_VAR, long_query_count),
SHOW_LONG_STATUS},
   {"Sort_merge_passes",	       (char*) offsetof(STATUS_VAR, filesort_merge_passes),
SHOW_LONG_STATUS},
@@ -5798,7 +5847,7 @@
   opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0;
   opt_disable_networking= opt_skip_show_db=0;
   opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0;
-  opt_tc_log_file= "tc.log";      // no hostname in tc_log file name !
+  opt_tc_log_file= (char *)"tc.log";      // no hostname in tc_log file name !
   opt_secure_auth= 0;
   opt_bootstrap= opt_myisam_log= 0;
   mqh_used= 0;
@@ -5937,6 +5986,11 @@
   have_archive_db= SHOW_OPTION_YES;
 #else
   have_archive_db= SHOW_OPTION_NO;
+#endif
+#ifdef HAVE_BLACKHOLE_DB
+  have_blackhole_db= SHOW_OPTION_YES;
+#else
+  have_blackhole_db= SHOW_OPTION_NO;
 #endif
 #ifdef HAVE_FEDERATED_DB
   have_federated_db= SHOW_OPTION_YES;

--- 1.135/BitKeeper/deleted/.del-errmsg.txt~f96b7055cac394e	Tue Dec 14 15:13:17 2004
+++ 1.136/BitKeeper/deleted/.del-errmsg.txt~f96b7055cac394e	Tue Apr  5 15:01:06 2005
@@ -67,7 +67,7 @@
 "Column '%-.64s' cannot be null",
 "Unknown database '%-.64s'",
 "Table '%-.64s' already exists",
-"Unknown table '%-.64s'",
+"Unknown table '%-.180s'",
 "Column '%-.64s' in %-.64s is ambiguous",
 "Server shutdown in progress",
 "Unknown column '%-.64s' in '%-.64s'",
@@ -90,7 +90,7 @@
 "Specified key was too long; max key length is %d bytes",
 "Key column '%-.64s' doesn't exist in table",
 "BLOB column '%-.64s' can't be used in key specification with the used table type",
-"Column length too big for column '%-.64s' (max = %d); use BLOB instead",
+"Column length too big for column '%-.64s' (max = %d); use BLOB or TEXT instead",
 "Incorrect table definition; there can be only one auto column and it must be defined as
a key",
 "%s: ready for connections.\nVersion: '%s'  socket: '%s'  port: %d",
 "%s: Normal shutdown\n",
@@ -143,7 +143,7 @@
 "No paths allowed for shared library",
 "Function '%-.64s' already exists",
 "Can't open shared library '%-.64s' (errno: %d %-.64s)",
-"Can't find function '%-.64s' in library'",
+"Can't find function '%-.64s' in library",
 "Function '%-.64s' is not defined",
 "Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin
flush-hosts'",
 "Host '%-.64s' is not allowed to connect to this MySQL server",

--- 1.124/BitKeeper/deleted/.del-errmsg.txt~ef53c33ac0ff8a84	Tue Dec 14 15:13:16 2004
+++ 1.125/BitKeeper/deleted/.del-errmsg.txt~ef53c33ac0ff8a84	Tue Apr  5 17:34:12 2005
@@ -72,7 +72,7 @@
 "óÔÏÌÂÅÃ '%-.64s' ÎÅ
ÍÏÖÅÔ
ÐÒÉÎÉÍÁÔØ
×ÅÌÉÞÉÎÕ NULL",
 "îÅÉÚ×ÅÓÔÎÁÑ
ÂÁÚÁ ÄÁÎÎÙÈ '%-.64s'",
 "ôÁÂÌÉÃÁ '%-.64s' ÕÖÅ
ÓÕÝÅÓÔ×ÕÅÔ",
-"îÅÉÚ×ÅÓÔÎÁÑ
ÔÁÂÌÉÃÁ '%-.64s'",
+"îÅÉÚ×ÅÓÔÎÁÑ
ÔÁÂÌÉÃÁ '%-.175s'",
 "óÔÏÌÂÅÃ '%-.64s' × %-.64s
ÚÁÄÁÎ
ÎÅÏÄÎÏÚÎÁÞÎÏ",
 "óÅÒ×ÅÒ
ÎÁÈÏÄÉÔÓÑ ×
ÐÒÏÃÅÓÓÅ
ÏÓÔÁÎÏ×ËÉ",
 "îÅÉÚ×ÅÓÔÎÙÊ
ÓÔÏÌÂÅÃ '%-.64s' × '%-.64s'",

--- 1.208/sql/sql_base.cc	Tue Mar  1 22:38:53 2005
+++ 1.209/sql/sql_base.cc	Tue Apr  5 15:01:14 2005
@@ -20,6 +20,7 @@
 #include "mysql_priv.h"
 #include "sql_select.h"
 #include "sp_head.h"
+#include "sp.h"
 #include "sql_trigger.h"
 #include <m_ctype.h>
 #include <my_dir.h>
@@ -359,7 +360,30 @@
 
 
 /*
-  Close all tables used by thread
+  Mark all tables in the list which were used by current substatement
+  as free for reuse.
+
+  SYNOPSIS
+    mark_used_tables_as_free_for_reuse()
+      thd   - thread context
+      table - head of the list of tables
+
+  DESCRIPTION
+    Marks all tables in the list which were used by current substatement
+    (they are marked by its query_id) as free for reuse.
+*/
+
+static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
+{
+  for (; table ; table= table->next)
+    if (table->query_id == thd->query_id)
+      table->query_id= 0;
+}
+
+
+/*
+  Close all tables used by the current substatement, or all tables
+  used by this thread if we are on the upper level.
 
   SYNOPSIS
     close_thread_tables()
@@ -372,14 +396,31 @@
   IMPLEMENTATION
     Unlocks tables and frees derived tables.
     Put all normal tables used by thread in free list.
+
+    When in prelocked mode it will only close/mark as free for reuse
+    tables opened by this substatement, it will also check if we are
+    closing tables after execution of complete query (i.e. we are on
+    upper level) and will leave prelocked mode if needed.
 */
 
 void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived, 
                          TABLE *stopper)
 {
   bool found_old_table;
+  prelocked_mode_type prelocked_mode= thd->prelocked_mode;
   DBUG_ENTER("close_thread_tables");
 
+  /*
+    We are assuming here that thd->derived_tables contains ONLY derived
+    tables for this substatement. i.e. instead of approach which uses
+    query_id matching for determining which of the derived tables belong
+    to this substatement we rely on the ability of substatements to
+    save/restore thd->derived_tables during their execution.
+
+    TODO: Probably even better approach is to simply associate list of
+          derived tables with (sub-)statement instead of thread and destroy
+          them at the end of its execution.
+  */
   if (thd->derived_tables && !skip_derived)
   {
     TABLE *table, *next;
@@ -394,10 +435,50 @@
     }
     thd->derived_tables= 0;
   }
-  if (thd->locked_tables)
+
+  if (prelocked_mode)
   {
-    ha_commit_stmt(thd);			// If select statement
-    DBUG_VOID_RETURN;				// LOCK TABLES in use
+    /*
+      Mark all temporary tables used by this substatement as free for reuse.
+    */
+    mark_used_tables_as_free_for_reuse(thd, thd->temporary_tables);
+  }
+
+  if (thd->locked_tables || prelocked_mode)
+  {
+    /*
+      TODO: It is not 100% clear whenever we should do ha_commit_stmt() for
+            sub-statements. This issue needs additional investigation.
+    */
+    ha_commit_stmt(thd);
+
+    /* We are under simple LOCK TABLES so should not do anything else. */
+    if (!prelocked_mode)
+      DBUG_VOID_RETURN;
+
+    if (!thd->lex->requires_prelocking())
+    {
+      /*
+        If we are executing one of substatements we have to mark
+        all tables which it used as free for reuse.
+      */
+      mark_used_tables_as_free_for_reuse(thd, thd->open_tables);
+      DBUG_VOID_RETURN;
+    }
+
+    DBUG_ASSERT(prelocked_mode);
+    /*
+      We are in prelocked mode, so we have to leave it now with doing
+      implicit UNLOCK TABLES if need.
+    */
+    thd->prelocked_mode= NON_PRELOCKED;
+
+    if (prelocked_mode == PRELOCKED_UNDER_LOCK_TABLES)
+      DBUG_VOID_RETURN;
+
+    thd->lock= thd->locked_tables;
+    thd->locked_tables= 0;
+    /* Fallthrough */
   }
 
   if (thd->lock)
@@ -441,6 +522,17 @@
   if (!lock_in_use)
     VOID(pthread_mutex_unlock(&LOCK_open));
   /*  VOID(pthread_sigmask(SIG_SETMASK,&thd->signals,NULL)); */
+
+  if (prelocked_mode == PRELOCKED)
+  {
+    /*
+      If we are here then we are leaving normal prelocked mode, so it is
+      good idea to turn off OPTION_TABLE_LOCK flag.
+    */
+    DBUG_ASSERT(thd->lex->requires_prelocking());
+    thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+  }
+
   DBUG_VOID_RETURN;
 }
 
@@ -541,7 +633,7 @@
                     table->s->table_name,"`,", NullS);
     }
     next=table->next;
-    close_temporary(table);
+    close_temporary(table, 1);
   }
   if (query && found_user_tables && mysql_bin_log.is_open())
   {
@@ -588,45 +680,41 @@
                                const char *db_name,
                                const char *table_name)
 {
-  if (lower_case_table_names)
-  {
-    for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
-    {
-      if ((table->table == 0 || table->table->s->tmp_table == NO_TMP_TABLE)
&&
-          ((!strcmp(table->db, db_name) &&
-            !strcmp(table->table_name, table_name)) ||
-           (table->view &&
-            !my_strcasecmp(table_alias_charset,
-                           table->db, db_name) &&
-            !my_strcasecmp(table_alias_charset,
-                           table->table->alias, table_name))))
-        break;
-    }
-  }
-  else
+  for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
   {
-    for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
-    {
-      if ((table->table == 0 || table->table->s->tmp_table == NO_TMP_TABLE)
&&
-          ((!strcmp(table->db, db_name) &&
-            !strcmp(table->table_name, table_name)) ||
-           (table->view &&
-            !strcmp(table->table->s->db, db_name) &&
-            !strcmp(table->table->alias, table_name))))
-        break;
-    }
+    if ((table->table == 0 || table->table->s->tmp_table == NO_TMP_TABLE)
&&
+        strcmp(table->db, db_name) == 0 &&
+        strcmp(table->table_name, table_name) == 0)
+      break;
   }
   return table;
 }
 
 
 /*
-  Test that table is unique
+  Test that table is unique (It's only exists once in the table list)
 
   SYNOPSIS
     unique_table()
-    table       table which should be chaked
-    table_list  list of tables
+    table                 table which should be checked
+    table_list            list of tables
+
+  NOTE: to exclude derived tables from check we use following mechanism:
+    a) during derived table processing set THD::derived_tables_processing
+    b) JOIN::prepare set SELECT::exclude_from_table_unique_test if
+       THD::derived_tables_processing set. (we can't use JOIN::execute
+       because for PS we perform only JOIN::prepare, but we can't set this
+       flag in JOIN::prepare if we are not sure that we are in derived table
+       processing loop, because multi-update call fix_fields() for some its
+       items (which mean JOIN::prepare for subqueries) before unique_table
+       call to detect which tables should be locked for write).
+    c) unique_table skip all tables which belong to SELECT with
+       SELECT::exclude_from_table_unique_test set.
+    Also SELECT::exclude_from_table_unique_test used to exclude from check
+    tables of main SELECT of multi-delete and multi-update
+
+    TODO: when we will have table/view change detection we can do this check
+          only once for PS/SP
 
   RETURN
     found duplicate
@@ -635,42 +723,51 @@
 
 TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
 {
+  TABLE_LIST *res;
+  const char *d_name, *t_name;
   DBUG_ENTER("unique_table");
   DBUG_PRINT("enter", ("table alias: %s", table->alias));
-  TABLE_LIST *res;
-  const char *d_name= table->db, *t_name= table->table_name;
-  char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
-  /* temporary table is always unique */
-  if (table->table && table->table->s->tmp_table != NO_TMP_TABLE)
-    return 0;
-  if (table->view)
-  {
-    /* it is view and table opened */
-    if (lower_case_table_names)
-    {
-      strmov(t_name_buff, table->table->alias);
-      my_casedn_str(files_charset_info, t_name_buff);
-      t_name= t_name_buff;
-      strmov(d_name_buff, table->table->s->db);
-      my_casedn_str(files_charset_info, d_name_buff);
-      d_name= d_name_buff;
-    }
-    else
-    {
-      d_name= table->table->s->db;
-      t_name= table->table->alias;
-    }
+
+  /*
+    If this function called for query which update table (INSERT/UPDATE/...)
+    then we have in table->table pointer to TABLE object which we are
+    updating even if it is VIEW so we need TABLE_LIST of this TABLE object
+    to get right names (even if lower_case_table_names used).
+
+    If this function called for CREATE command that we have not opened table
+    (table->table equal to 0) and right names is in current TABLE_LIST
+    object.
+  */
+  if (table->table)
+  {
+    /* temporary table is always unique */
+    if (table->table && table->table->s->tmp_table != NO_TMP_TABLE)
+      DBUG_RETURN(0);
+    table= table->find_underlying_table(table->table);
+    /*
+      as far as we have table->table we have to find real TABLE_LIST of
+      it in underlying tables
+    */
+    DBUG_ASSERT(table);
   }
+  d_name= table->db;
+  t_name= table->table_name;
 
   DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
   for(;;)
   {
     if (!(res= find_table_in_global_list(table_list, d_name, t_name)) ||
-        !res->table || res->table != table->table)
+        (!res->table || res->table != table->table) &&
+        (res->select_lex &&
!res->select_lex->exclude_from_table_unique_test))
       break;
-    /* if we found entry of this table try again. */
+    /*
+      If we found entry of this table or or table of SELECT which already
+      processed in derived table or top select of multi-update/multi-delete
+      (exclude_from_table_unique_test).
+    */
     table_list= res->next_global;
-    DBUG_PRINT("info", ("found same copy of table"));
+    DBUG_PRINT("info",
+               ("found same copy of table or table which we should skip"));
   }
   DBUG_RETURN(res);
 }
@@ -706,7 +803,7 @@
     return 1;
   table= *prev;
   *prev= table->next;
-  close_temporary(table);
+  close_temporary(table, 1);
   if (thd->slave_thread)
     --slave_open_temp_tables;
   return 0;
@@ -910,7 +1007,8 @@
 	  !memcmp(table->s->table_cache_key, key,
 		  key_length + TMP_TABLE_KEY_EXTRA))
       {
-	if (table->query_id == thd->query_id)
+	if (table->query_id == thd->query_id ||
+            thd->prelocked_mode && table->query_id)
 	{
 	  my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
 	  DBUG_RETURN(0);
@@ -924,16 +1022,17 @@
     }
   }
 
-  if (thd->locked_tables)
+  if (thd->locked_tables || thd->prelocked_mode)
   {						// Using table locks
     for (table=thd->open_tables; table ; table=table->next)
     {
       if (table->s->key_length == key_length &&
-	  !memcmp(table->s->table_cache_key,key,key_length) &&
-	  !my_strcasecmp(system_charset_info, table->alias, alias))
+          !memcmp(table->s->table_cache_key, key, key_length) &&
+          !my_strcasecmp(system_charset_info, table->alias, alias) &&
+          table->query_id != thd->query_id && /* skip tables already used
by this query */
+          !(thd->prelocked_mode && table->query_id))
       {
-	if (table->query_id != thd->query_id)
-	  table->query_id=thd->query_id;
+        table->query_id= thd->query_id;
         DBUG_PRINT("info",("Using locked table"));
 	goto reset;
       }
@@ -1512,7 +1611,8 @@
       if (ha_create_table_from_engine(thd, db, name, TRUE) != 0)
        goto err;
 
-      thd->clear_error(); // Clear error message
+      mysql_reset_errors(thd, 1);    // Clear warnings
+      thd->clear_error();            // Clear error message
       continue;
     }
 
@@ -1625,21 +1725,34 @@
   SYNOPSIS
     open_tables()
     thd - thread handler
-    start - list of tables
+    start - list of tables in/out
     counter - number of opened tables will be return using this parameter
 
+  NOTE
+    Unless we are already in prelocked mode, this function will also precache
+    all SP/SFs explicitly or implicitly (via views and triggers) used by the
+    query and add tables needed for their execution to table list. If resulting
+    tables list will be non empty it will mark query as requiring precaching.
+    Prelocked mode will be enabled for such query during lock_tables() call.
+
+    If query for which we are opening tables is already marked as requiring
+    prelocking it won't do such precaching and will simply reuse table list
+    which is already built.
+
   RETURN
     0  - OK
     -1 - error
 */
 
-int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
+int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
 {
   TABLE_LIST *tables;
   bool refresh;
   int result=0;
-  DBUG_ENTER("open_tables");
   MEM_ROOT new_frm_mem;
+  /* Also used for indicating that prelocking is need */
+  TABLE_LIST **query_tables_last_own;
+  DBUG_ENTER("open_tables");
   /*
     temporary mem_root for new .frm parsing.
     TODO: variables for size
@@ -1649,8 +1762,51 @@
   thd->current_tablenr= 0;
  restart:
   *counter= 0;
+  query_tables_last_own= 0;
   thd->proc_info="Opening tables";
-  for (tables= start; tables ;tables= tables->next_global)
+
+  /*
+    If we are not already executing prelocked statement and don't have
+    statement for which table list for prelocking is already built, let
+    us cache routines and try to build such table list.
+
+    NOTE: If we want queries with functions to work under explicit
+    LOCK TABLES we have to additionaly lock mysql.proc table in it.
+    At least until Monty will fix SP loading :)
+
+    NOTE: We can't delay prelocking until we will met some sub-statement
+    which really uses tables, since this will imply that we have to restore
+    its table list to be able execute it in some other context.
+    And current views implementation assumes that view tables are added to
+    global table list only once during PS preparing/first SP execution.
+    Also locking at earlier stage is probably faster altough may decrease
+    concurrency a bit.
+
+    NOTE: We will mark statement as requiring prelocking only if we will
+    have non empty table list. But this does not guarantee that in prelocked
+    mode we will have some locked tables, because queries which use only
+    derived/information schema tables and views possible. Thus "counter"
+    may be still zero for prelocked statement...
+  */
+  if (!thd->prelocked_mode && !thd->lex->requires_prelocking()
&&
+      (thd->lex->spfuns.records || thd->lex->spprocs.records))
+  {
+    TABLE_LIST **save_query_tables_last;
+
+    sp_cache_routines(thd, thd->lex);
+    save_query_tables_last= thd->lex->query_tables_last;
+
+    DBUG_ASSERT(thd->lex->query_tables == *start);
+
+    if (sp_add_sp_tables_to_table_list(thd, thd->lex, thd->lex) ||
+        *start)
+    {
+      query_tables_last_own= save_query_tables_last;
+      *start= thd->lex->query_tables;
+    }
+  }
+
+  for (tables= *start; tables ;tables= tables->next_global)
   {
     /*
       Ignore placeholders for derived tables. After derived tables
@@ -1671,8 +1827,27 @@
       free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
       if (tables->view)
       {
+        /* VIEW placeholder */
 	(*counter)--;
-	continue; //VIEW placeholder
+        /*
+          Again if needed we have to get cache all routines used by this view
+          and add tables used by them to table list.
+        */
+        if (!thd->prelocked_mode && !thd->lex->requires_prelocking()
&&
+            (tables->view->spfuns.records || tables->view->spprocs.records))
+        {
+          // FIXME We should catch recursion for both views and funcs here
+          sp_cache_routines(thd, tables->view);
+
+          /* We have at least one table in TL here */
+          if (!query_tables_last_own)
+            query_tables_last_own= thd->lex->query_tables_last;
+          sp_add_sp_tables_to_table_list(thd, thd->lex, tables->view);
+        }
+        /* Cleanup hashes because destructo for this LEX is never called */
+        hash_free(&tables->view->spfuns);
+        hash_free(&tables->view->spprocs);
+	continue;
       }
 
       if (refresh)				// Refresh in progress
@@ -1684,7 +1859,12 @@
 	thd->version=refresh_version;
 	TABLE **prev_table= &thd->open_tables;
 	bool found=0;
-	for (TABLE_LIST *tmp= start; tmp; tmp= tmp->next_global)
+        /*
+          QQ: What we should do if we have started building of table list
+          for prelocking ??? Probably throw it away ? But before we should
+          mark all temporary tables as free? How about locked ?
+        */
+	for (TABLE_LIST *tmp= *start; tmp; tmp= tmp->next_global)
 	{
 	  /* Close normal (not temporary) changed tables */
 	  if (tmp->table && ! tmp->table->s->tmp_table)
@@ -1713,7 +1893,27 @@
       break;
     }
     else
+    {
+      /*
+        If we are not already in prelocked mode and extended table list is not
+        yet built and we have trigger for table being opened then we should
+        cache all routines used by its triggers and add their tables to
+        prelocking list.
+        If we lock table for reading we won't update it so there is no need to
+        process its triggers since they never will be activated.
+
+        FIXME Now we are simply turning on prelocking. Proper integration
+        and testing is to be done later.
+      */
+      if (!thd->prelocked_mode && !thd->lex->requires_prelocking()
&&
+          tables->table->triggers &&
+          tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+      {
+        if (!query_tables_last_own)
+            query_tables_last_own= thd->lex->query_tables_last;
+      }
       free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
+    }
 
     if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
       tables->table->reginfo.lock_type=tables->lock_type;
@@ -1721,6 +1921,10 @@
   }
   thd->proc_info=0;
   free_root(&new_frm_mem, MYF(0));              // Free pre-alloced block
+
+  if (query_tables_last_own)
+    thd->lex->mark_as_requiring_prelocking(query_tables_last_own);
+
   DBUG_RETURN(result);
 }
 
@@ -1769,6 +1973,11 @@
     table_list		Table to open is first table in this list
     lock_type		Lock to use for open
 
+  NOTE
+    This function don't do anything like SP/SF/views/triggers analysis done
+    in open_tables(). It is intended for opening of only one concrete table.
+    And used only in special contexts.
+
   RETURN VALUES
     table		Opened table
     0			Error
@@ -1843,7 +2052,7 @@
 {
   DBUG_ENTER("simple_open_n_lock_tables");
   uint counter;
-  if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
+  if (open_tables(thd, &tables, &counter) || lock_tables(thd, tables, counter))
     DBUG_RETURN(-1);				/* purecov: inspected */
   DBUG_RETURN(0);
 }
@@ -1870,7 +2079,7 @@
 {
   uint counter;
   DBUG_ENTER("open_and_lock_tables");
-  if (open_tables(thd, tables, &counter) ||
+  if (open_tables(thd, &tables, &counter) ||
       lock_tables(thd, tables, counter) ||
       mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
       (thd->fill_derived_tables() &&
@@ -1903,7 +2112,7 @@
   uint counter;
   DBUG_ENTER("open_normal_and_derived_tables");
   DBUG_ASSERT(!thd->fill_derived_tables());
-  if (open_tables(thd, tables, &counter) ||
+  if (open_tables(thd, &tables, &counter) ||
       mysql_handle_derived(thd->lex, &mysql_derived_prepare))
     DBUG_RETURN(TRUE); /* purecov: inspected */
   relink_tables_for_multidelete(thd);           // Not really needed, but
@@ -1937,6 +2146,27 @@
 
 
 /*
+  Mark all real tables in the list as free for reuse.
+
+  SYNOPSIS
+    mark_real_tables_as_free_for_reuse()
+      thd   - thread context
+      table - head of the list of tables
+
+  DESCRIPTION
+    Marks all real tables in the list (i.e. not views, derived
+    or schema tables) as free for reuse.
+*/
+
+static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
+{
+  for (; table; table= table->next_global)
+    if (!table->placeholder() && !table->schema_table)
+      table->table->query_id= 0;
+}
+
+
+/*
   Lock all tables in list
 
   SYNOPSIS
@@ -1950,6 +2180,10 @@
     handling thr_lock gives us.  You most always get all needed locks at
     once.
 
+    If query for which we are calling this function marked as requring
+    prelocking, this function will do implicit LOCK TABLES and change
+    thd::prelocked_mode accordingly.
+
   RETURN VALUES
    0	ok
    -1	Error
@@ -1958,36 +2192,125 @@
 int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
 {
   TABLE_LIST *table;
+
+  DBUG_ENTER("lock_tables");
+  /*
+    We can't meet statement requiring prelocking if we already
+    in prelocked mode.
+  */
+  DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking());
+  /*
+    If statement requires prelocking then it has non-empty table list.
+    So it is safe to shortcut.
+  */
+  DBUG_ASSERT(!thd->lex->requires_prelocking() || tables);
+
   if (!tables)
-    return 0;
+    DBUG_RETURN(0);
 
-  if (!thd->locked_tables)
+  /*
+    We need this extra check for thd->prelocked_mode because we want to avoid
+    attempts to lock tables in substatements. Checking for thd->locked_tables
+    is not enough in some situations. For example for SP containing
+    "drop table t3; create temporary t3 ..; insert into t3 ...;"
+    thd->locked_tables may be 0 after drop tables, and without this extra
+    check insert will try to lock temporary table t3, that will lead
+    to memory leak...
+  */
+  if (!thd->locked_tables && !thd->prelocked_mode)
   {
     DBUG_ASSERT(thd->lock == 0);	// You must lock everything at once
     TABLE **start,**ptr;
+
     if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count)))
-      return -1;
+      DBUG_RETURN(-1);
     for (table= tables; table; table= table->next_global)
     {
       if (!table->placeholder() && !table->schema_table)
 	*(ptr++)= table->table;
     }
+
+    /* We have to emulate LOCK TABLES if we are statement needs prelocking. */
+    if (thd->lex->requires_prelocking())
+    {
+      thd->in_lock_tables=1;
+      thd->options|= OPTION_TABLE_LOCK;
+    }
+
     if (!(thd->lock=mysql_lock_tables(thd,start, (uint) (ptr - start))))
-      return -1;				/* purecov: inspected */
+    {
+      if (thd->lex->requires_prelocking())
+      {
+        thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+        thd->in_lock_tables=0;
+      }
+      DBUG_RETURN(-1);
+    }
+    if (thd->lex->requires_prelocking() &&
+        thd->lex->sql_command != SQLCOM_LOCK_TABLES)
+    {
+      TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
+      /*
+        We just have done implicit LOCK TABLES, and now we have
+        to emulate first open_and_lock_tables() after it.
+
+        Note that "LOCK TABLES" can also be marked as requiring prelocking
+        (e.g. if one locks view which uses functions). We should not emulate
+        such open_and_lock_tables() in this case. We also should not set
+        THD::prelocked_mode or first close_thread_tables() call will do
+        "UNLOCK TABLES".
+      */
+      thd->locked_tables= thd->lock;
+      thd->lock= 0;
+      thd->in_lock_tables=0;
+
+      for (table= tables; table != first_not_own; table= table->next_global)
+      {
+        if (!table->placeholder() && !table->schema_table)
+        {
+          table->table->query_id= thd->query_id;
+          if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
+          {
+            ha_rollback_stmt(thd);
+            mysql_unlock_tables(thd, thd->locked_tables);
+            thd->locked_tables= 0;
+            thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+            DBUG_RETURN(-1);
+          }
+        }
+      }
+      /*
+        Let us mark all tables which don't belong to the statement itself,
+        and was marked as occupied during open_tables() as free for reuse.
+      */
+      mark_real_tables_as_free_for_reuse(first_not_own);
+      thd->prelocked_mode= PRELOCKED;
+    }
   }
   else
   {
-    for (table= tables; table; table= table->next_global)
+    TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
+    for (table= tables; table != first_not_own; table= table->next_global)
     {
-      if (!table->placeholder() && 
+      if (!table->placeholder() && !table->schema_table &&
 	  check_lock_and_start_stmt(thd, table->table, table->lock_type))
       {
 	ha_rollback_stmt(thd);
-	return -1;
+	DBUG_RETURN(-1);
       }
     }
+    /*
+      If we are under explicit LOCK TABLES and our statement requires
+      prelocking, we should mark all "additional" tables as free for use
+      and enter prelocked mode.
+    */
+    if (thd->lex->requires_prelocking())
+    {
+      mark_real_tables_as_free_for_reuse(first_not_own);
+      thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES;
+    }
   }
-  return 0;
+  DBUG_RETURN(0);
 }
 
 

--- 1.133/sql/sql_lex.cc	Tue Mar  1 22:38:54 2005
+++ 1.134/sql/sql_lex.cc	Tue Apr  5 15:01:15 2005
@@ -170,13 +170,12 @@
   lex->sphead= NULL;
   lex->spcont= NULL;
   lex->proc_list.first= 0;
+  lex->query_tables_own_last= 0;
 
   if (lex->spfuns.records)
     my_hash_reset(&lex->spfuns);
   if (lex->spprocs.records)
     my_hash_reset(&lex->spprocs);
-  if (lex->sptabs.records)
-    my_hash_reset(&lex->sptabs);
   DBUG_VOID_RETURN;
 }
 
@@ -1114,7 +1113,7 @@
   first_execution= 1;
   first_cond_optimization= 1;
   parsing_place= NO_MATTER;
-  no_wrap_view_item= 0;
+  exclude_from_table_unique_test= no_wrap_view_item= FALSE;
   link_next= 0;
 }
 
@@ -1495,77 +1494,6 @@
 }
 
 
-/*
-  Find db.table which will be updated in this unit
-
-  SYNOPSIS
-    st_select_lex_unit::check_updateable()
-    db		- data base name
-    table	- real table name
-
-  RETURN
-    1 - found
-    0 - OK (table did not found)
-*/
-
-bool st_select_lex_unit::check_updateable(char *db, char *table)
-{
-  for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
-    if (sl->check_updateable(db, table))
-      return 1;
-  return 0;
-}
-
-
-/*
-  Find db.table which will be updated in this select and
-  underlying ones (except derived tables)
-
-  SYNOPSIS
-    st_select_lex::check_updateable()
-    db		- data base name
-    table	- real table name
-
-  RETURN
-    1 - found
-    0 - OK (table did not found)
-*/
-
-bool st_select_lex::check_updateable(char *db, char *table)
-{
-  if (find_table_in_local_list(get_table_list(), db, table))
-    return 1;
-
-  return check_updateable_in_subqueries(db, table);
-}
-
-/*
-   Find db.table which will be updated in underlying subqueries
-
-   SYNOPSIS
-    st_select_lex::check_updateable_in_subqueries()
-    db		- data base name
-    table	- real table name
-
-  RETURN
-    1 - found
-    0 - OK (table did not found)
-*/
-
-bool st_select_lex::check_updateable_in_subqueries(char *db, char *table)
-{
-  for (SELECT_LEX_UNIT *un= first_inner_unit();
-       un;
-       un= un->next_unit())
-  {
-    if (un->first_select()->linkage != DERIVED_TABLE_TYPE &&
-	un->check_updateable(db, table))
-      return 1;
-  }
-  return 0;
-}
-
-
 void st_select_lex_unit::print(String *str)
 {
   for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
@@ -1838,8 +1766,6 @@
   select_limit_cnt= values->select_limit+values->offset_limit;
   if (select_limit_cnt < values->select_limit)
     select_limit_cnt= HA_POS_ERROR;		// no limit
-  if (select_limit_cnt == HA_POS_ERROR)
-    sl->options&= ~OPTION_FOUND_ROWS;
 }
 
 
@@ -1871,6 +1797,8 @@
     */
     if ((query_tables= query_tables->next_global))
       query_tables->prev_global= &query_tables;
+    else
+      query_tables_last= &query_tables;
     first->next_global= 0;
 
     /*
@@ -1976,6 +1904,8 @@
   {
     if ((first->next_global= query_tables))
       query_tables->prev_global= &first->next_global;
+    else
+      query_tables_last= &first->next_global;
     query_tables= first;
 
     if (link_to_local)

--- 1.163/sql/sql_lex.h	Tue Mar  1 22:38:54 2005
+++ 1.164/sql/sql_lex.h	Tue Apr  5 15:01:15 2005
@@ -437,13 +437,13 @@
   void exclude_tree();
 
   /* UNION methods */
-  bool prepare(THD *thd, select_result *result, ulong additional_options);
+  bool prepare(THD *thd, select_result *result, ulong additional_options,
+               const char *tmp_table_alias);
   bool exec();
   bool cleanup();
   inline void unclean() { cleaned= 0; }
   void reinit_exec_mechanism();
 
-  bool check_updateable(char *db, char *table);
   void print(String *str);
 
   ulong init_prepare_fake_select_lex(THD *thd);
@@ -526,6 +526,8 @@
   bool first_cond_optimization;
   /* do not wrap view fields with Item_ref */
   bool no_wrap_view_item;
+  /* exclude this select from check of unique_table() */
+  bool exclude_from_table_unique_test;
 
   /* 
      SELECT for SELECT command st_select_lex. Used to privent scaning
@@ -616,8 +618,6 @@
     init_select();
   }
   bool setup_ref_array(THD *thd, uint order_group_num);
-  bool check_updateable(char *db, char *table);
-  bool check_updateable_in_subqueries(char *db, char *table);
   void print(THD *thd, String *str);
   static void print_order(String *str, ORDER *order);
   void print_limit(THD *thd, String *str);
@@ -702,8 +702,9 @@
   TABLE_LIST *query_tables;	/* global list of all tables in this query */
   /*
     last element next_global of previous list (used only for list building
-    during parsing and VIEW processing. This pointer is not valid in
-    mysql_execute_command
+    during parsing and VIEW processing. This pointer could be invalid during
+    processing of information schema tables(see get_schema_tables_result
+    function)
   */
   TABLE_LIST **query_tables_last;
   TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */
@@ -787,7 +788,6 @@
   sp_pcontext *spcont;
   HASH spfuns;		/* Called functions */
   HASH spprocs;		/* Called procedures */
-  HASH sptabs;		/* Merged table lists */
   st_sp_chistics sp_chistics;
   bool only_view;       /* used for SHOW CREATE TABLE/VIEW */
   /*
@@ -806,23 +806,31 @@
   */
   SQL_LIST trg_table_fields;
 
-  st_lex() :result(0), sql_command(SQLCOM_END)
+  /*
+    If non-0 then indicates that query requires prelocking and points to
+    next_global member of last own element in query table list (i.e. last
+    table which was not added to it as part of preparation to prelocking).
+    0 - indicates that this query does not need prelocking.
+  */
+  TABLE_LIST **query_tables_own_last;
+
+  /*
+    Pointers to part of LOAD DATA statement that should be rewritten
+    during replication ("LOCAL 'filename' REPLACE INTO" part).
+  */
+  uchar *fname_start, *fname_end;
+
+  st_lex() :result(0), sql_command(SQLCOM_END), query_tables_own_last(0)
   {
     extern byte *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first);
-    extern byte *sp_table_key(const byte *ptr, uint *plen, my_bool first);
     hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
     hash_init(&spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
-    hash_init(&sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
   }
-  
-  ~st_lex()
+
+  virtual ~st_lex()
   {
-    if (spfuns.array.buffer)
-      hash_free(&spfuns);
-    if (spprocs.array.buffer)
-      hash_free(&spprocs);
-    if (sptabs.array.buffer)
-      hash_free(&sptabs);
+    hash_free(&spfuns);
+    hash_free(&spprocs);
   }
 
   inline void uncacheable(uint8 cause)
@@ -859,6 +867,21 @@
   bool can_not_use_merged();
   bool only_view_structure();
   bool need_correct_ident();
+
+  inline bool requires_prelocking()
+  {
+    return test(query_tables_own_last);
+  }
+  inline void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last)
+  {
+    query_tables_own_last= tables_own_last;
+  }
+  /* Return pointer to first not-own table in query-tables or 0 */
+  TABLE_LIST* first_not_own_table()
+  {
+    return ( query_tables_own_last ? *query_tables_own_last : 0);
+  }
+
 } LEX;
 
 struct st_lex_local: public st_lex
@@ -873,6 +896,8 @@
   }
   static void operator delete(void *ptr,size_t size)
   { TRASH(ptr, size); }
+  static void operator delete(void *ptr, MEM_ROOT *mem_root)
+  { /* Never called */ }
 };
 
 void lex_init(void);

--- 1.308/sql/sql_select.cc	Mon Apr  4 17:52:49 2005
+++ 1.309/sql/sql_select.cc	Tue Apr  5 15:01:17 2005
@@ -9353,18 +9353,19 @@
       table->file->extra(HA_EXTRA_KEYREAD);
       tab->index= tab->ref.key;
     }
-    if ((error=join_read_const(tab)))
+    error=join_read_const(tab);
+    if (table->key_read)
+    {
+      table->key_read=0;
+      table->file->extra(HA_EXTRA_NO_KEYREAD);
+    }
+    if (error)
     {
       tab->info="unique row not found";
       /* Mark for EXPLAIN that the row was not found */
       pos->records_read=0.0;
       if (!table->maybe_null || error > 0)
 	DBUG_RETURN(error);
-    }
-    if (table->key_read)
-    {
-      table->key_read=0;
-      table->file->extra(HA_EXTRA_NO_KEYREAD);
     }
   }
   if (*tab->on_expr_ref && !table->null_row)

--- 1.216/sql/sql_table.cc	Tue Mar  1 22:38:55 2005
+++ 1.217/sql/sql_table.cc	Tue Apr  5 15:01:18 2005
@@ -65,7 +65,7 @@
 bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
                     my_bool drop_temporary)
 {
-  bool error= FALSE;
+  bool error= FALSE, need_start_waiters= FALSE;
   DBUG_ENTER("mysql_rm_table");
 
   /* mark for close and remove all cached entries */
@@ -74,23 +74,19 @@
   thd->mysys_var->current_cond= &COND_refresh;
   VOID(pthread_mutex_lock(&LOCK_open));
 
-  if (!drop_temporary && global_read_lock)
+  if (!drop_temporary)
   {
-    if (thd->global_read_lock)
+    if ((error= wait_if_global_read_lock(thd, 0, 1)))
     {
       my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), tables->table_name);
-      error= TRUE;
       goto err;
     }
-    while (global_read_lock && ! thd->killed)
-    {
-      (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
-    }
-
+    else
+      need_start_waiters= TRUE;
   }
   error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0);
 
- err:
+err:
   pthread_mutex_unlock(&LOCK_open);
 
   pthread_mutex_lock(&thd->mysys_var->mutex);
@@ -98,6 +94,9 @@
   thd->mysys_var->current_cond= 0;
   pthread_mutex_unlock(&thd->mysys_var->mutex);
 
+  if (need_start_waiters)
+    start_waiting_global_read_lock(thd);
+
   if (error)
     DBUG_RETURN(TRUE);
   send_ok(thd);
@@ -114,7 +113,7 @@
     tables		List of tables to delete
     if_exists		If 1, don't give error if one table doesn't exists
     dont_log_query	Don't write query to log files. This will also not
-			generate warnings if the handler files doesn't exists  
+                        generate warnings if the handler files doesn't exists
 
  NOTES
    Works like documented in mysql_rm_table(), but don't check
@@ -208,7 +207,8 @@
     if (!drop_temporary)
     {
       abort_locked_tables(thd,db,table->table_name);
-      while (remove_table_from_cache(thd,db,table->table_name) &&
!thd->killed)
+      while (remove_table_from_cache(thd, db, table->table_name, 0) &&
+             !thd->killed)
       {
 	dropping_tables++;
 	(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
@@ -257,7 +257,19 @@
 	/* Delete the table definition file */
 	strmov(end,reg_ext);
 	if (!(new_error=my_delete(path,MYF(MY_WME))))
+        {
 	  some_tables_deleted=1;
+          /*
+            Destroy triggers for this table if there are any.
+
+            We won't need this as soon as we will have new .FRM format,
+            in which we will store trigger definitions in the same .FRM
+            files as table descriptions.
+          */
+          strmov(end, triggers_file_ext);
+          if (!access(path, F_OK))
+            new_error= my_delete(path, MYF(MY_WME));
+        }
         error|= new_error;
       }
     }
@@ -273,7 +285,8 @@
   if (wrong_tables.length())
   {
     if (!foreign_key_error)
-      my_error(ER_BAD_TABLE_ERROR, MYF(0), wrong_tables.c_ptr());
+      my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
+                      wrong_tables.c_ptr());
     else
       my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
     error= 1;
@@ -291,7 +304,7 @@
     }
   }
 
-  unlock_table_names(thd, tables);
+  unlock_table_names(thd, tables, (TABLE_LIST*) 0);
   thd->no_warnings_for_error= 0;
   DBUG_RETURN(error);
 }
@@ -432,6 +445,174 @@
 
 
 /*
+  Prepare a create_table instance for packing
+
+  SYNOPSIS
+    prepare_create_field()
+    sql_field     field to prepare for packing
+    blob_columns  count for BLOBs
+    timestamps    count for timestamps
+    table_flags   table flags
+
+  DESCRIPTION
+    This function prepares a create_field instance.
+    Fields such as pack_flag are valid after this call.
+
+  RETURN VALUES
+   0	ok
+   1	Error
+*/
+
+int prepare_create_field(create_field *sql_field, 
+			 uint *blob_columns, 
+			 int *timestamps, int *timestamps_with_niladic,
+			 uint table_flags)
+{
+  DBUG_ENTER("prepare_field");
+
+  /*
+    This code came from mysql_prepare_table.
+    Indent preserved to make patching easier
+  */
+  DBUG_ASSERT(sql_field->charset);
+
+  switch (sql_field->sql_type) {
+  case FIELD_TYPE_BLOB:
+  case FIELD_TYPE_MEDIUM_BLOB:
+  case FIELD_TYPE_TINY_BLOB:
+  case FIELD_TYPE_LONG_BLOB:
+    sql_field->pack_flag=FIELDFLAG_BLOB |
+      pack_length_to_packflag(sql_field->pack_length -
+                              portable_sizeof_char_ptr);
+    if (sql_field->charset->state & MY_CS_BINSORT)
+      sql_field->pack_flag|=FIELDFLAG_BINARY;
+    sql_field->length=8;			// Unireg field length
+    sql_field->unireg_check=Field::BLOB_FIELD;
+    (*blob_columns)++;
+    break;
+  case FIELD_TYPE_GEOMETRY:
+#ifdef HAVE_SPATIAL
+    if (!(table_flags & HA_CAN_GEOMETRY))
+    {
+      my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED),
+                      MYF(0), "GEOMETRY");
+      DBUG_RETURN(1);
+    }
+    sql_field->pack_flag=FIELDFLAG_GEOM |
+      pack_length_to_packflag(sql_field->pack_length -
+                              portable_sizeof_char_ptr);
+    if (sql_field->charset->state & MY_CS_BINSORT)
+      sql_field->pack_flag|=FIELDFLAG_BINARY;
+    sql_field->length=8;			// Unireg field length
+    sql_field->unireg_check=Field::BLOB_FIELD;
+    (*blob_columns)++;
+    break;
+#else
+    my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0),
+                    sym_group_geom.name, sym_group_geom.needed_define);
+    DBUG_RETURN(1);
+#endif /*HAVE_SPATIAL*/
+  case MYSQL_TYPE_VARCHAR:
+#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
+    if (table_flags & HA_NO_VARCHAR)
+    {
+      /* convert VARCHAR to CHAR because handler is not yet up to date */
+      sql_field->sql_type=    MYSQL_TYPE_VAR_STRING;
+      sql_field->pack_length= calc_pack_length(sql_field->sql_type,
+                                               (uint) sql_field->length);
+      if ((sql_field->length / sql_field->charset->mbmaxlen) >
+          MAX_FIELD_CHARLENGTH)
+      {
+        my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
+                        MYF(0), sql_field->field_name, MAX_FIELD_CHARLENGTH);
+        DBUG_RETURN(1);
+      }
+    }
+#endif
+    /* fall through */
+  case FIELD_TYPE_STRING:
+    sql_field->pack_flag=0;
+    if (sql_field->charset->state & MY_CS_BINSORT)
+      sql_field->pack_flag|=FIELDFLAG_BINARY;
+    break;
+  case FIELD_TYPE_ENUM:
+    sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
+      FIELDFLAG_INTERVAL;
+    if (sql_field->charset->state & MY_CS_BINSORT)
+      sql_field->pack_flag|=FIELDFLAG_BINARY;
+    sql_field->unireg_check=Field::INTERVAL_FIELD;
+    check_duplicates_in_interval("ENUM",sql_field->field_name,
+                                 sql_field->interval,
+                                 sql_field->charset);
+    break;
+  case FIELD_TYPE_SET:
+    sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
+      FIELDFLAG_BITFIELD;
+    if (sql_field->charset->state & MY_CS_BINSORT)
+      sql_field->pack_flag|=FIELDFLAG_BINARY;
+    sql_field->unireg_check=Field::BIT_FIELD;
+    check_duplicates_in_interval("SET",sql_field->field_name,
+                                 sql_field->interval,
+                                 sql_field->charset);
+    break;
+  case FIELD_TYPE_DATE:			// Rest of string types
+  case FIELD_TYPE_NEWDATE:
+  case FIELD_TYPE_TIME:
+  case FIELD_TYPE_DATETIME:
+  case FIELD_TYPE_NULL:
+    sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
+    break;
+  case FIELD_TYPE_BIT:
+    if (!(table_flags & HA_CAN_BIT_FIELD))
+    {
+      my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "BIT FIELD");
+      DBUG_RETURN(1);
+    }
+    sql_field->pack_flag= FIELDFLAG_NUMBER;
+    break;
+  case FIELD_TYPE_NEWDECIMAL:
+    sql_field->pack_flag=(FIELDFLAG_NUMBER |
+                          (sql_field->flags & UNSIGNED_FLAG ? 0 :
+                           FIELDFLAG_DECIMAL) |
+                          (sql_field->flags & ZEROFILL_FLAG ?
+                           FIELDFLAG_ZEROFILL : 0) |
+                          (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+    break;
+  case FIELD_TYPE_TIMESTAMP:
+    /* We should replace old TIMESTAMP fields with their newer analogs */
+    if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
+    {
+      if (!*timestamps)
+      {
+        sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
+        (*timestamps_with_niladic)++;
+      }
+      else
+        sql_field->unireg_check= Field::NONE;
+    }
+    else if (sql_field->unireg_check != Field::NONE)
+      (*timestamps_with_niladic)++;
+
+    (*timestamps)++;
+    /* fall-through */
+  default:
+    sql_field->pack_flag=(FIELDFLAG_NUMBER |
+                          (sql_field->flags & UNSIGNED_FLAG ? 0 :
+                           FIELDFLAG_DECIMAL) |
+                          (sql_field->flags & ZEROFILL_FLAG ?
+                           FIELDFLAG_ZEROFILL : 0) |
+                          f_settype((uint) sql_field->sql_type) |
+                          (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+    break;
+  }
+  if (!(sql_field->flags & NOT_NULL_FLAG))
+    sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
+  if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
+    sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
+  DBUG_RETURN(0);
+}
+
+/*
   Preparation for table creation
 
   SYNOPSIS
@@ -445,18 +626,19 @@
     Prepares the table and key structures for table creation.
 
   NOTES
-    sets create_info->varchar if the table has a varchar or blob.
+    sets create_info->varchar if the table has a varchar
 
   RETURN VALUES
     0	ok
     -1	error
 */
 
-int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
-			List<create_field> &fields,
-			List<Key> &keys, bool tmp_table, uint &db_options,
-			handler *file, KEY *&key_info_buffer,
-			uint *key_count, int select_field_count)
+static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
+                               List<create_field> *fields,
+                               List<Key> *keys, bool tmp_table,
+                               uint *db_options,
+                               handler *file, KEY **key_info_buffer,
+                               uint *key_count, int select_field_count)
 {
   const char	*key_name;
   create_field	*sql_field,*dup_field;
@@ -468,11 +650,11 @@
   int		timestamps= 0, timestamps_with_niladic= 0;
   int		field_no,dup_no;
   int		select_field_pos,auto_increment=0;
-  List_iterator<create_field> it(fields),it2(fields);
+  List_iterator<create_field> it(*fields),it2(*fields);
   uint total_uneven_bit_length= 0;
   DBUG_ENTER("mysql_prepare_table");
 
-  select_field_pos=fields.elements - select_field_count;
+  select_field_pos= fields->elements - select_field_count;
   null_fields=blob_columns=0;
   create_info->varchar= 0;
 
@@ -677,11 +859,11 @@
     if ((sql_field->flags & BLOB_FLAG) ||
 	sql_field->sql_type == MYSQL_TYPE_VARCHAR &&
 	create_info->row_type != ROW_TYPE_FIXED)
-      db_options|= HA_OPTION_PACK_RECORD;
+      (*db_options)|= HA_OPTION_PACK_RECORD;
     it2.rewind();
   }
   /* If fixed row records, we need one bit to check for deleted rows */
-  if (!(db_options & HA_OPTION_PACK_RECORD))
+  if (!((*db_options) & HA_OPTION_PACK_RECORD))
     null_fields++;
   pos= (null_fields + total_uneven_bit_length + 7) / 8;
 
@@ -690,142 +872,12 @@
   {
     DBUG_ASSERT(sql_field->charset != 0);
 
-    switch (sql_field->sql_type) {
-    case FIELD_TYPE_BLOB:
-    case FIELD_TYPE_MEDIUM_BLOB:
-    case FIELD_TYPE_TINY_BLOB:
-    case FIELD_TYPE_LONG_BLOB:
-      sql_field->pack_flag=FIELDFLAG_BLOB |
-	pack_length_to_packflag(sql_field->pack_length -
-				portable_sizeof_char_ptr);
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|=FIELDFLAG_BINARY;
-      sql_field->length=8;			// Unireg field length
-      sql_field->unireg_check=Field::BLOB_FIELD;
-      blob_columns++;
-      create_info->varchar= 1;
-      break;
-    case FIELD_TYPE_GEOMETRY:
-#ifdef HAVE_SPATIAL
-      if (!(file->table_flags() & HA_CAN_GEOMETRY))
-      {
-	my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY");
-	DBUG_RETURN(-1);
-      }
-      sql_field->pack_flag=FIELDFLAG_GEOM |
-	pack_length_to_packflag(sql_field->pack_length -
-				portable_sizeof_char_ptr);
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|=FIELDFLAG_BINARY;
-      sql_field->length=8;			// Unireg field length
-      sql_field->unireg_check=Field::BLOB_FIELD;
-      blob_columns++;
-      create_info->varchar= 1;
-      break;
-#else
-      my_error(ER_FEATURE_DISABLED, MYF(0),
-               sym_group_geom.name, sym_group_geom.needed_define);
+    if (prepare_create_field(sql_field, &blob_columns, 
+			     &timestamps, &timestamps_with_niladic,
+			     file->table_flags()))
       DBUG_RETURN(-1);
-#endif /*HAVE_SPATIAL*/
-    case MYSQL_TYPE_VARCHAR:
-#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
-      if (file->table_flags() & HA_NO_VARCHAR)
-      {
-        /* convert VARCHAR to CHAR because handler is not yet up to date */
-        sql_field->sql_type=    MYSQL_TYPE_VAR_STRING;
-        sql_field->pack_length= calc_pack_length(sql_field->sql_type,
-                                                 (uint) sql_field->length);
-        if ((sql_field->length / sql_field->charset->mbmaxlen) >
-            MAX_FIELD_CHARLENGTH)
-        {
-          my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
-                          MYF(0), sql_field->field_name, MAX_FIELD_CHARLENGTH);
-          DBUG_RETURN(-1);
-        }
-      }
-      else
-#endif
-        create_info->varchar= 1;
-      /* fall through */
-    case MYSQL_TYPE_STRING:
-      sql_field->pack_flag=0;
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|= FIELDFLAG_BINARY;
-      break;
-    case FIELD_TYPE_ENUM:
-      sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
-	FIELDFLAG_INTERVAL;
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|=FIELDFLAG_BINARY;
-      sql_field->unireg_check=Field::INTERVAL_FIELD;
-      check_duplicates_in_interval("ENUM",sql_field->field_name,
-                                   sql_field->interval,
-                                   sql_field->charset);
-      break;
-    case FIELD_TYPE_SET:
-      sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
-	FIELDFLAG_BITFIELD;
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|=FIELDFLAG_BINARY;
-      sql_field->unireg_check=Field::BIT_FIELD;
-      check_duplicates_in_interval("SET",sql_field->field_name,
-                                   sql_field->interval,
-                                   sql_field->charset);
-      break;
-    case FIELD_TYPE_DATE:			// Rest of string types
-    case FIELD_TYPE_NEWDATE:
-    case FIELD_TYPE_TIME:
-    case FIELD_TYPE_DATETIME:
-    case FIELD_TYPE_NULL:
-      sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
-      break;
-    case FIELD_TYPE_BIT:
-      if (!(file->table_flags() & HA_CAN_BIT_FIELD))
-      {
-        my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "BIT FIELD");
-        DBUG_RETURN(-1);
-      }
-      sql_field->pack_flag= FIELDFLAG_NUMBER;
-      break;
-    case FIELD_TYPE_NEWDECIMAL:
-      sql_field->pack_flag=(FIELDFLAG_NUMBER |
-                            (sql_field->flags & UNSIGNED_FLAG ? 0 :
-                             FIELDFLAG_DECIMAL) |
-                            (sql_field->flags & ZEROFILL_FLAG ?
-                             FIELDFLAG_ZEROFILL : 0) |
-                            (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
-      break;
-    case FIELD_TYPE_TIMESTAMP:
-      /* We should replace old TIMESTAMP fields with their newer analogs */
-      if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
-      {
-	if (!timestamps)
-	{
-	  sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
-	  timestamps_with_niladic++;
-	}
-	else
-	  sql_field->unireg_check= Field::NONE;
-      }
-      else if (sql_field->unireg_check != Field::NONE)
-	timestamps_with_niladic++;
-
-      timestamps++;
-      /* fall-through */
-    default:
-      sql_field->pack_flag=(FIELDFLAG_NUMBER |
-			    (sql_field->flags & UNSIGNED_FLAG ? 0 :
-			     FIELDFLAG_DECIMAL) |
-			    (sql_field->flags & ZEROFILL_FLAG ?
-			     FIELDFLAG_ZEROFILL : 0) |
-			    f_settype((uint) sql_field->sql_type) |
-			    (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
-      break;
-    }
-    if (!(sql_field->flags & NOT_NULL_FLAG))
-      sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
-    if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
-      sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
+    if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
+      create_info->varchar= 1;
     sql_field->offset= pos;
     if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
       auto_increment++;
@@ -859,7 +911,7 @@
 
   /* Create keys */
 
-  List_iterator<Key> key_iterator(keys), key_iterator2(keys);
+  List_iterator<Key> key_iterator(*keys), key_iterator2(*keys);
   uint key_parts=0, fk_key_count=0;
   bool primary_key=0,unique_key=0;
   Key *key, *key2;
@@ -946,9 +998,9 @@
     DBUG_RETURN(-1);
   }
 
-  key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)* *key_count);
+  (*key_info_buffer) = key_info= (KEY*) sql_calloc(sizeof(KEY)* *key_count);
   key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
-  if (!key_info_buffer || ! key_part_info)
+  if (!*key_info_buffer || ! key_part_info)
     DBUG_RETURN(-1);				// Out of memory
 
   key_iterator.rewind();
@@ -1222,7 +1274,7 @@
       }
       key_part_info->length=(uint16) length;
       /* Use packed keys for long strings on the first column */
-      if (!(db_options & HA_OPTION_NO_PACK_KEYS) &&
+      if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
 	  (length >= KEY_DEFAULT_PACK_LENGTH &&
 	   (sql_field->sql_type == MYSQL_TYPE_STRING ||
 	    sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
@@ -1253,8 +1305,8 @@
 	}
 	else if (!(key_name = key->name))
 	  key_name=make_unique_key_name(sql_field->field_name,
-					key_info_buffer,key_info);
-	if (check_if_keyname_exists(key_name,key_info_buffer,key_info))
+					*key_info_buffer, key_info);
+	if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
 	{
 	  my_error(ER_DUP_KEYNAME, MYF(0), key_name);
 	  DBUG_RETURN(-1);
@@ -1289,7 +1341,7 @@
     DBUG_RETURN(-1);
   }
   /* Sort keys in optimized order */
-  qsort((gptr) key_info_buffer, *key_count, sizeof(KEY),
+  qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY),
 	(qsort_cmp) sort_keys);
 
   DBUG_RETURN(0);
@@ -1355,7 +1407,7 @@
 			ha_get_storage_engine(new_db_type),
 			table_name);
   }
-  db_options=create_info->table_options;
+  db_options= create_info->table_options;
   if (create_info->row_type == ROW_TYPE_DYNAMIC)
     db_options|=HA_OPTION_PACK_RECORD;
   alias= table_case_name(create_info, table_name);
@@ -1418,9 +1470,9 @@
     create_info->default_table_charset= db_info.default_table_charset;
   }
 
-  if (mysql_prepare_table(thd, create_info, fields,
-			  keys, internal_tmp_table, db_options, file,
-			  key_info_buffer, &key_count,
+  if (mysql_prepare_table(thd, create_info, &fields,
+			  &keys, internal_tmp_table, &db_options, file,
+			  &key_info_buffer, &key_count,
 			  select_field_count))
     goto err;
 
@@ -1624,6 +1676,8 @@
 					   ((Item_field *)item)->field :
 					   (Field*) 0))))
       DBUG_RETURN(0);
+    if (item->maybe_null)
+      cr_field->flags &= ~NOT_NULL_FLAG;
     extra_fields->push_back(cr_field);
   }
   /*
@@ -1753,7 +1807,7 @@
   mysql_lock_abort(thd, table);			// end threads waiting on lock
 
   /* Wait until all there are no other threads that has this table open */
-  while (remove_table_from_cache(thd, table->s->db, table->s->table_name))
+  while (remove_table_from_cache(thd, table->s->db, table->s->table_name, 0))
   {
     dropping_tables++;
     (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
@@ -2039,7 +2093,7 @@
     thd->no_warnings_for_error= 0;
     table->next_global= next_global_table;
     /* if view are unsupported */
-    if (table->view && !view_operator_func)
+    if (table->view && view_operator_func == NULL)
     {
       result_code= HA_ADMIN_NOT_IMPLEMENTED;
       goto send_result;
@@ -2122,7 +2176,7 @@
 					      "Waiting to get writelock");
       mysql_lock_abort(thd,table->table);
       while (remove_table_from_cache(thd, table->table->s->db,
-				     table->table->s->table_name) &&
+				     table->table->s->table_name, 0) &&
 	     ! thd->killed)
       {
 	dropping_tables++;
@@ -2132,7 +2186,9 @@
       thd->exit_cond(old_message);
       if (thd->killed)
 	goto err;
-      open_for_modify=0;
+      /* Flush entries in the query cache involving this table. */
+      query_cache_invalidate3(thd, table->table, 0);
+      open_for_modify= 0;
     }
 
     result_code = (table->table->file->*operator_func)(thd, check_opt);
@@ -2235,7 +2291,7 @@
     {
       pthread_mutex_lock(&LOCK_open);
       remove_table_from_cache(thd, table->table->s->db,
-			      table->table->s->table_name);
+			      table->table->s->table_name, 0);
       pthread_mutex_unlock(&LOCK_open);
       /* May be something modified consequently we have to invalidate cache */
       query_cache_invalidate3(thd, table->table, 0);
@@ -2696,9 +2752,9 @@
   create_info.db_type=DB_TYPE_DEFAULT;
   create_info.default_table_charset= thd->variables.collation_database;
   db_options= 0;
-  if (mysql_prepare_table(thd, &create_info, fields,
-			  keys, /*tmp_table*/ 0, db_options, table->file,
-			  key_info_buffer, key_count,
+  if (mysql_prepare_table(thd, &create_info, &fields,
+			  &keys, /*tmp_table*/ 0, &db_options, table->file,
+			  &key_info_buffer, key_count,
 			  /*select_field_count*/ 0))
     DBUG_RETURN(-1);
 
@@ -2829,9 +2885,9 @@
   {
     db_options= 0;
     if (table->file->drop_index(table, key_numbers, key_count)||
-	mysql_prepare_table(thd, &create_info, fields,
-			    keys, /*tmp_table*/ 0, db_options, table->file,
-			    key_info_buffer, key_count,
+	mysql_prepare_table(thd, &create_info, &fields,
+			    &keys, /*tmp_table*/ 0, &db_options, table->file,
+			    &key_info_buffer, key_count,
 			    /*select_field_count*/ 0)||
 	(snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home,
 		  table_list->db, (lower_case_table_names == 2)?
@@ -3544,7 +3600,7 @@
     if (table)
     {
       VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file
-      remove_table_from_cache(thd,db,table_name); // Mark all in-use copies old
+      remove_table_from_cache(thd,db,table_name, 0); // Mark in-use copies old
       mysql_lock_abort(thd,table);		 // end threads waiting on lock
     }
     VOID(quick_rm_table(old_db_type,db,old_name));
@@ -3656,6 +3712,13 @@
 
   if (to->file->external_lock(thd, F_WRLCK))
     DBUG_RETURN(-1);
+
+  /* We can abort alter table for any table type */
+  thd->no_trans_update= 0;
+  thd->abort_on_warning= !ignore && test(thd->variables.sql_mode &
+                                         (MODE_STRICT_TRANS_TABLES |
+                                          MODE_STRICT_ALL_TABLES));
+
   from->file->info(HA_STATUS_VARIABLE);
   to->file->start_bulk_insert(from->file->records);
 
@@ -3709,9 +3772,11 @@
       goto err;
   };
 
-  /* Handler must be told explicitly to retrieve all columns, because
-     this function does not set field->query_id in the columns to the
-     current query id */
+  /*
+    Handler must be told explicitly to retrieve all columns, because
+    this function does not set field->query_id in the columns to the
+    current query id
+  */
   from->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
   init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1);
   if (ignore ||
@@ -3735,6 +3800,7 @@
       else
         to->next_number_field->reset();
     }
+    
     for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
     {
       copy_ptr->do_copy(copy_ptr);
@@ -3779,6 +3845,7 @@
 
  err:
   thd->variables.sql_mode= save_sql_mode;
+  thd->abort_on_warning= 0;
   free_io_cache(from);
   *copied= found_count;
   *deleted=delete_count;

--- 1.153/sql/sql_update.cc	Mon Mar 28 14:12:29 2005
+++ 1.154/sql/sql_update.cc	Tue Apr  5 15:01:19 2005
@@ -267,7 +267,8 @@
   else
     used_key_is_modified=0;
 
-  if (used_key_is_modified || order)
+  if (used_key_is_modified || order ||
+      partition_key_modified(table, fields))
   {
     /*
       We can't update table directly;  We must first search after all

--- 1.349/sql/sql_yacc.yy	Wed Mar 23 17:57:03 2005
+++ 1.350/sql/sql_yacc.yy	Tue Apr  5 17:34:13 2005
@@ -56,6 +56,13 @@
 		      ER_WARN_DEPRECATED_SYNTAX, \
 		      ER(ER_WARN_DEPRECATED_SYNTAX), (A), (B));
 
+#define TEST_ASSERT(A) \
+  if (!(A)) \
+  {					\
+    yyerror(ER(ER_SYNTAX_ERROR));	\
+    YYABORT;				\
+  }
+
 /* Helper for parsing "IS [NOT] truth_value" */
 inline Item *is_truth_value(Item *A, bool v1, bool v2)
 {
@@ -701,12 +708,13 @@
 	text_string opt_gconcat_separator
 
 %type <num>
-	type int_type real_type order_dir opt_field_spec lock_option
+	type int_type real_type order_dir lock_option
 	udf_type if_exists opt_local opt_table_options table_options
         table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type
         opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct
         opt_ignore_leaves fulltext_options spatial_type union_option
         start_transaction_opts opt_chain opt_release
+        union_opt select_derived_init
         field_option
 
 %type <ulong_num>
@@ -730,6 +738,7 @@
 	signed_literal now_or_signed_literal opt_escape
 	sp_opt_default
 	simple_ident_nospvar simple_ident_q
+        field_or_var
 
 %type <item_num>
 	NUM_literal
@@ -753,6 +762,7 @@
 %type <table_list>
 	join_table_list  join_table
         table_factor table_ref
+        select_derived derived_table_list
 
 %type <date_time_type> date_time_type;
 %type <interval> interval
@@ -787,6 +797,7 @@
 %type <variable> internal_variable_name
 
 %type <select_lex> in_subselect in_subselect_init
+	get_select_lex
 
 %type <boolfunc2creator> comp_op
 
@@ -825,8 +836,8 @@
         prepare prepare_src execute deallocate 
 	statement sp_suid opt_view_list view_list or_replace algorithm
 	sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
+        load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
         partition_entry
-
 END_OF_INPUT
 
 %type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@@ -1391,19 +1402,41 @@
 	  RETURNS_SYM
 	  {
 	    LEX *lex= Lex;
-	    sp_head *sp= lex->sphead;
-
-	    sp->m_returns_begin= lex->tok_start;
-	    sp->m_returns_cs= lex->charset= NULL;
+	    lex->charset= NULL;
+	    lex->length= lex->dec= NULL;
+	    lex->interval_list.empty();
+	    lex->type= 0;
 	  }
 	  type
 	  {
 	    LEX *lex= Lex;
 	    sp_head *sp= lex->sphead;
+            LEX_STRING cmt = { 0, 0 };
+	    create_field *new_field;
+	    uint unused1= 0;
+	    int unused2= 0;
+
+	    if (!(new_field= new_create_field(YYTHD, (char*) "",
+					      (enum enum_field_types)$8,
+			  		      lex->length, lex->dec, lex->type,
+			  		      (Item *)0, (Item *) 0, &cmt, 0,
+					      &lex->interval_list, 
+			  		      (lex->charset ? lex->charset :
+					       default_charset_info),
+					      lex->uint_geom_type)))
+	      YYABORT;
+
+	    if (prepare_create_field(new_field, &unused1, &unused2, &unused2,
+				     0))
+	      YYABORT;
+
+	    sp->m_returns= new_field->sql_type;
+	    sp->m_returns_cs= new_field->charset;
+	    sp->m_returns_len= new_field->length;
+	    sp->m_returns_pack= new_field->pack_flag;
+	    sp->m_returns_typelib= 
+              sp->create_typelib(&new_field->interval_list);
 
-	    sp->m_returns_end= lex->tok_start;
-	    sp->m_returns= (enum enum_field_types)$8;
-	    sp->m_returns_cs= lex->charset;
 	    bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
 	  }
 	  sp_c_chistics
@@ -1567,12 +1600,12 @@
 
 sp_proc_stmts:
 	  /* Empty */ {}
-	| sp_proc_stmts  { Lex->query_tables= 0; } sp_proc_stmt ';'
+	| sp_proc_stmts  sp_proc_stmt ';'
 	;
 
 sp_proc_stmts1:
 	  sp_proc_stmt ';' {}
-	| sp_proc_stmts1  { Lex->query_tables= 0; } sp_proc_stmt ';'
+	| sp_proc_stmts1  sp_proc_stmt ';'
 	;
 
 sp_decls:
@@ -1606,13 +1639,15 @@
 	;
 
 sp_decl:
-	  DECLARE_SYM sp_decl_idents type sp_opt_default
+	  DECLARE_SYM sp_decl_idents type 
+          { Lex->sphead->reset_lex(YYTHD); }
+          sp_opt_default
 	  {
 	    LEX *lex= Lex;
 	    sp_pcontext *ctx= lex->spcont;
 	    uint max= ctx->context_pvars();
 	    enum enum_field_types type= (enum enum_field_types)$3;
-	    Item *it= $4;
+	    Item *it= $5;
 
 	    for (uint i = max-$2 ; i < max ; i++)
 	    {
@@ -1624,15 +1659,19 @@
 	        sp_instr_set *in= new sp_instr_set(lex->sphead->instructions(),
 	                                           ctx,
 						   ctx->pvar_context2index(i),
-						   it, type);
+                                                   it, type, lex,
+                                                   (i == max - 1));
 
-		in->tables= lex->query_tables;
-		lex->query_tables= 0;
+                /*
+                  The last instruction is assigned to be responsible for
+                  freeing LEX.
+                */
 	        lex->sphead->add_instr(in);
 	        ctx->set_isset(i, TRUE);
 		ctx->set_default(i, it);
 	      }
 	    }
+            lex->sphead->restore_lex(YYTHD);
 	    $$.vars= $2;
 	    $$.conds= $$.hndlrs= $$.curs= 0;
 	  }
@@ -1884,36 +1923,39 @@
 	      my_message(ER_SP_NO_USE, ER(ER_SP_NO_USE), MYF(0));
 	      YYABORT;
 	    }
-	    /* Don't add an instruction for empty SET statements.
-	    ** (This happens if the SET only contained local variables,
-	    **  which get their set instructions generated separately.)
+	    /*
+              Don't add an instruction for SET statements, since all
+              instructions for them were already added during processing
+              of "set" rule.
 	    */
-	    if (lex->sql_command != SQLCOM_SET_OPTION ||
-		! lex->var_list.is_empty())
-	    {
-		sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
-						   lex->spcont);
-
-		/* Extract the query statement from the tokenizer:
-                   The end is either lex->tok_end or tok->ptr. */
-		if (lex->ptr - lex->tok_end > 1)
-		  i->m_query.length= lex->ptr - sp->m_tmp_query;
-		else
-		  i->m_query.length= lex->tok_end - sp->m_tmp_query;
-		i->m_query.str= strmake_root(YYTHD->mem_root,
-					     (char *)sp->m_tmp_query,
-					     i->m_query.length);
-		i->set_lex(lex);
-		sp->add_instr(i);
-		lex->sp_lex_in_use= TRUE;
-	      }
+            DBUG_ASSERT(lex->sql_command != SQLCOM_SET_OPTION ||
+                        lex->var_list.is_empty());
+            if (lex->sql_command != SQLCOM_SET_OPTION)
+	    {
+              sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
+                                                 lex->spcont, lex);
+
+              /* Extract the query statement from the tokenizer:
+                 The end is either lex->tok_end or tok->ptr. */
+              if (lex->ptr - lex->tok_end > 1)
+                i->m_query.length= lex->ptr - sp->m_tmp_query;
+              else
+                i->m_query.length= lex->tok_end - sp->m_tmp_query;
+              i->m_query.str= strmake_root(YYTHD->mem_root,
+                                           (char *)sp->m_tmp_query,
+                                           i->m_query.length);
+              sp->add_instr(i);
+            }
 	    sp->restore_lex(YYTHD);
           }
-	| RETURN_SYM expr
+          | RETURN_SYM 
+          { Lex->sphead->reset_lex(YYTHD); }
+          expr
 	  {
 	    LEX *lex= Lex;
+	    sp_head *sp= lex->sphead;
 
-	    if (lex->sphead->m_type == TYPE_ENUM_PROCEDURE)
+	    if (sp->m_type == TYPE_ENUM_PROCEDURE)
 	    {
 	      my_message(ER_SP_BADRETURN, ER(ER_SP_BADRETURN), MYF(0));
 	      YYABORT;
@@ -1922,12 +1964,12 @@
 	    {
 	      sp_instr_freturn *i;
 
-	      i= new sp_instr_freturn(lex->sphead->instructions(),
-				      lex->spcont,
-		                      $2, lex->sphead->m_returns);
-	      lex->sphead->add_instr(i);
-	      lex->sphead->m_has_return= TRUE;
+	      i= new sp_instr_freturn(sp->instructions(), lex->spcont,
+		                      $3, sp->m_returns, lex);
+	      sp->add_instr(i);
+	      sp->m_has_return= TRUE;
 	    }
+	    sp->restore_lex(YYTHD);
 	  }
 	| IF sp_if END IF {}
 	| CASE_SYM WHEN_SYM
@@ -1935,7 +1977,9 @@
 	    Lex->sphead->m_simple_case= FALSE;
 	  }
 	  sp_case END CASE_SYM {}
-	| CASE_SYM expr WHEN_SYM
+        | CASE_SYM
+          { Lex->sphead->reset_lex(YYTHD); }
+          expr WHEN_SYM
 	  {
 	    /* We "fake" this by using an anonymous variable which we
 	       set to the expression. Note that all WHENs are evaluate
@@ -1944,15 +1988,14 @@
 	    LEX *lex= Lex;
 	    uint offset= lex->spcont->current_pvars();
 	    sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
-					       lex->spcont,
-	                                       offset, $2, MYSQL_TYPE_STRING);
+                                               lex->spcont, offset, $3,
+                                               MYSQL_TYPE_STRING, lex, TRUE);
 	    LEX_STRING dummy={(char*)"", 0};
 
 	    lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
-	    i->tables= lex->query_tables;
-	    lex->query_tables= 0;
 	    lex->sphead->add_instr(i);
 	    lex->sphead->m_simple_case= TRUE;
+            lex->sphead->restore_lex(YYTHD);
 	  }
 	  sp_case END CASE_SYM
 	  {
@@ -2206,18 +2249,19 @@
 	;
 
 sp_if:
-	  expr THEN_SYM
+          { Lex->sphead->reset_lex(YYTHD); }
+          expr THEN_SYM
 	  {
 	    LEX *lex= Lex;
 	    sp_head *sp= lex->sphead;
 	    sp_pcontext *ctx= lex->spcont;
 	    uint ip= sp->instructions();
-	    sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx, $1);
+	    sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx,
+                                                               $2, lex);
 
-	    i->tables= lex->query_tables;
-	    lex->query_tables= 0;
 	    sp->push_backpatch(i, ctx->push_label((char *)"", 0));
             sp->add_instr(i);
+            sp->restore_lex(YYTHD);
 	  }
 	  sp_proc_stmts1
 	  {
@@ -2245,7 +2289,8 @@
 	;
 
 sp_case:
-	  expr THEN_SYM
+	  { Lex->sphead->reset_lex(YYTHD); }
+          expr THEN_SYM
 	  {
             LEX *lex= Lex;
 	    sp_head *sp= lex->sphead;
@@ -2254,7 +2299,7 @@
 	    sp_instr_jump_if_not *i;
 
 	    if (! sp->m_simple_case)
-	      i= new sp_instr_jump_if_not(ip, ctx, $1);
+	      i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
 	    else
 	    { /* Simple case: <caseval> = <whenval> */
 	      LEX_STRING ivar;
@@ -2263,15 +2308,14 @@
 	      ivar.length= 5;
 	      Item *var= (Item*) new Item_splocal(ivar, 
 						  ctx->current_pvars()-1);
-	      Item *expr= new Item_func_eq(var, $1);
+	      Item *expr= new Item_func_eq(var, $2);
 
-	      i= new sp_instr_jump_if_not(ip, ctx, expr);
+	      i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
               lex->variables_used= 1;
 	    }
 	    sp->push_backpatch(i, ctx->push_label((char *)"", 0));
-	    i->tables= lex->query_tables;
-	    lex->query_tables= 0;
             sp->add_instr(i);
+            sp->restore_lex(YYTHD);
 	  }
 	  sp_proc_stmts1
 	  {
@@ -2387,19 +2431,20 @@
 
 	    lex->sphead->add_instr(i);
 	  }
-	| WHILE_SYM expr DO_SYM
+        | WHILE_SYM 
+          { Lex->sphead->reset_lex(YYTHD); }
+          expr DO_SYM
 	  {
 	    LEX *lex= Lex;
 	    sp_head *sp= lex->sphead;
 	    uint ip= sp->instructions();
 	    sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
-							       $2);
+							       $3, lex);
 
 	    /* Jumping forward */
 	    sp->push_backpatch(i, lex->spcont->last_label());
-	    i->tables= lex->query_tables;
-	    lex->query_tables= 0;
             sp->add_instr(i);
+            sp->restore_lex(YYTHD);
 	  }
 	  sp_proc_stmts1 END WHILE_SYM
 	  {
@@ -2410,17 +2455,18 @@
 
 	    lex->sphead->add_instr(i);
 	  }
-	| REPEAT_SYM sp_proc_stmts1 UNTIL_SYM expr END REPEAT_SYM
+        | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM 
+          { Lex->sphead->reset_lex(YYTHD); }
+          expr END REPEAT_SYM
 	  {
 	    LEX *lex= Lex;
 	    uint ip= lex->sphead->instructions();
 	    sp_label_t *lab= lex->spcont->last_label();  /* Jumping back */
 	    sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
-							       $4, lab->ip);
-
-	    i->tables= lex->query_tables;
-	    lex->query_tables= 0;
+                                                               $5, lab->ip,
+                                                               lex);
             lex->sphead->add_instr(i);
+            lex->sphead->restore_lex(YYTHD);
 	  }
 	;
 
@@ -4031,9 +4077,15 @@
 check:
 	CHECK_SYM table_or_tables
 	{
-	   LEX *lex=Lex;
-	   lex->sql_command = SQLCOM_CHECK;
-	   lex->check_opt.init();
+	  LEX *lex=Lex;
+
+	  if (lex->sphead)
+	  {
+	    my_error(ER_SP_BADSTATEMENT, MYF(0), "CHECK");
+	    YYABORT;
+	  }
+	  lex->sql_command = SQLCOM_CHECK;
+	  lex->check_opt.init();
 	}
 	table_list opt_mi_check_type
 	{}
@@ -4399,13 +4451,53 @@
 
 /* all possible expressions */
 expr:	
-	expr or bool_term	{ $$= new Item_cond_or($1,$3); }
-	| expr XOR bool_term	{ $$= new Item_cond_xor($1,$3); }
-	| bool_term ;
+	  bool_term { Select->expr_list.push_front(new List<Item>); }
+          bool_or_expr
+          {
+            List<Item> *list= Select->expr_list.pop();
+            if (list->elements)
+            {
+              list->push_front($1);
+              $$= new Item_cond_or(*list);
+              /* optimize construction of logical OR to reduce
+                 amount of objects for complex expressions */
+            }
+            else
+              $$= $1;
+            delete list;
+          }
+	;
+
+bool_or_expr:
+	/* empty */
+        | bool_or_expr or bool_term
+          { Select->expr_list.head()->push_back($3); }
+        ;
 
 bool_term:
-	bool_term and bool_factor { $$= new Item_cond_and($1,$3); }
-	| bool_factor ;
+	bool_term XOR bool_term { $$= new Item_cond_xor($1,$3); }
+	| bool_factor { Select->expr_list.push_front(new List<Item>); }
+          bool_and_expr
+          {
+            List<Item> *list= Select->expr_list.pop();
+            if (list->elements)
+            {
+              list->push_front($1);
+              $$= new Item_cond_and(*list);
+              /* optimize construction of logical AND to reduce
+                 amount of objects for complex expressions */
+            }
+            else
+              $$= $1;
+            delete list;
+          }
+	;
+
+bool_and_expr:
+	/* empty */
+        | bool_and_expr and bool_factor
+          { Select->expr_list.head()->push_back($3); }
+        ;
 
 bool_factor:
 	NOT_SYM bool_factor	{ $$= negate_expression(YYTHD, $2); }
@@ -5131,6 +5223,8 @@
 sum_expr:
 	AVG_SYM '(' in_sum_expr ')'
 	  { $$=new Item_sum_avg($3); }
+	| AVG_SYM '(' DISTINCT in_sum_expr ')'
+	  { $$=new Item_sum_avg_distinct($4); }
 	| BIT_AND  '(' in_sum_expr ')'
 	  { $$=new Item_sum_and($3); }
 	| BIT_OR  '(' in_sum_expr ')'
@@ -5288,6 +5382,7 @@
 	    sel->when_list.head()->push_back($5);
 	  };
 
+/* Warning - may return NULL in case of incomplete SELECT */
 table_ref:
         table_factor            { $$=$1; }
         | join_table            { $$=$1; }
@@ -5299,36 +5394,47 @@
         ;
 
 join_table_list:
+	derived_table_list		{ TEST_ASSERT($$=$1); }
+	;
+        
+/* Warning - may return NULL in case of incomplete SELECT */
+derived_table_list:
         table_ref { $$=$1; }
-        | join_table_list ',' table_ref { $$=$3; }
+        | derived_table_list ',' table_ref
+          {
+            TEST_ASSERT($1 && ($$=$3));
+          }
         ;
 
 join_table:
-        table_ref normal_join table_ref { $$=$3; }
+        table_ref normal_join table_ref { TEST_ASSERT($1 && ($$=$3)); }
 	| table_ref STRAIGHT_JOIN table_factor
-	  { $3->straight=1; $$=$3 ; }
+	  {  TEST_ASSERT($1 && ($$=$3)); $3->straight=1; }
 	| table_ref normal_join table_ref ON expr
-	  { add_join_on($3,$5); $$=$3; }
+	  { TEST_ASSERT($1 && ($$=$3)); add_join_on($3,$5); }
 	| table_ref normal_join table_ref
 	  USING
 	  {
 	    SELECT_LEX *sel= Select;
+            TEST_ASSERT($1 && $3);
             sel->save_names_for_using_list($1, $3);
 	  }
 	  '(' using_list ')'
 	  { add_join_on($3,$7); $$=$3; }
 
 	| table_ref LEFT opt_outer JOIN_SYM table_ref ON expr
-	  { add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
+	  { TEST_ASSERT($1 && $5); add_join_on($5,$7);
$5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
 	| table_ref LEFT opt_outer JOIN_SYM table_factor
 	  {
 	    SELECT_LEX *sel= Select;
+            TEST_ASSERT($1 && $5);
             sel->save_names_for_using_list($1, $5);
 	  }
 	  USING '(' using_list ')'
 	  { add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
 	| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
 	  {
+            TEST_ASSERT($1 && $6);
 	    add_join_natural($1,$6);
 	    $6->outer_join|=JOIN_TYPE_LEFT;
 	    $$=$6;
@@ -5336,6 +5442,7 @@
 	| table_ref RIGHT opt_outer JOIN_SYM table_ref ON expr
           { 
 	    LEX *lex= Lex;
+            TEST_ASSERT($1 && $5);
             if (!($$= lex->current_select->convert_right_join()))
               YYABORT;
             add_join_on($$, $7);
@@ -5343,6 +5450,7 @@
 	| table_ref RIGHT opt_outer JOIN_SYM table_factor
 	  {
 	    SELECT_LEX *sel= Select;
+            TEST_ASSERT($1 && $5);
             sel->save_names_for_using_list($1, $5);
 	  }
 	  USING '(' using_list ')'
@@ -5354,13 +5462,14 @@
           }
 	| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
 	  {
+            TEST_ASSERT($1 && $6);
 	    add_join_natural($6,$1);
 	    LEX *lex= Lex;
             if (!($$= lex->current_select->convert_right_join()))
               YYABORT;
 	  }
 	| table_ref NATURAL JOIN_SYM table_factor
-	  { add_join_natural($1,$4); $$=$4; };
+	  { TEST_ASSERT($1 && ($$=$4)); add_join_natural($1,$4); };
         
 
 normal_join:
@@ -5369,6 +5478,7 @@
 	| CROSS JOIN_SYM	{}
 	;
 
+/* Warning - may return NULL in case of incomplete SELECT */
 table_factor:
 	{
 	  SELECT_LEX *sel= Select;
@@ -5387,50 +5497,96 @@
 	    YYABORT;
           sel->add_joined_table($$);
 	}
-        | '('
+	| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
+	  { TEST_ASSERT($3 && $7); add_join_on($7,$9);
$7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
+	| select_derived_init get_select_lex select_derived2
           {
             LEX *lex= Lex;
-            if (lex->current_select->init_nested_join(lex->thd))
-              YYABORT;
+            SELECT_LEX *sel= lex->current_select;
+            if ($1)
+            {
+	      if (sel->set_braces(1))
+	      {
+	        yyerror(ER(ER_SYNTAX_ERROR));
+	        YYABORT;
+	      }
+              /* select in braces, can't contain global parameters */
+	      if (sel->master_unit()->fake_select_lex)
+                sel->master_unit()->global_parameters=
+                   sel->master_unit()->fake_select_lex;
+            }
+            if ($2->init_nested_join(lex->thd))
+              YYABORT;            
+            $$= 0;
+            /* incomplete derived tables return NULL, we must be 
+               nested in select_derived rule to be here. */
+          }
+	| '(' get_select_lex select_derived union_opt ')' opt_table_alias
+	{
+          /* Use $2 instead of Lex->current_select as derived table will
+             alter value of Lex->current_select. */
+
+          if (!($3 || $6) && $2->embedding && 
+              !$2->embedding->nested_join->join_list.elements)
+          {
+            /* we have a derived table ($3 == NULL) but no alias,
+               Since we are nested in further parentheses so we
+               can pass NULL to the outer level parentheses
+               Permits parsing of "((((select ...))) as xyz)" */
+            $$= 0;
           }
-          join_table_list ')'
+          else
+          if (!$3)
           {
-            LEX *lex= Lex;
-            if (!($$= lex->current_select->end_nested_join(lex->thd)))
-              YYABORT;
-          }
-	| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
-	  { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
-	| '(' select_derived union_opt ')' opt_table_alias
-	{
-	  LEX *lex=Lex;
-	  SELECT_LEX_UNIT *unit= lex->current_select->master_unit();
-	  lex->current_select= unit->outer_select();
-	  if (!($$= lex->current_select->
-                add_table_to_list(lex->thd, new Table_ident(unit), $5, 0,
-				  TL_READ,(List<String> *)0,
-	                          (List<String> *)0)))
+            /* Handle case of derived table, alias may be NULL if there
+               are no outer parentheses, add_table_to_list() will throw
+               error in this case */
+	    LEX *lex=Lex;
+            SELECT_LEX *sel= lex->current_select;
+	    SELECT_LEX_UNIT *unit= sel->master_unit();
+	    lex->current_select= sel= unit->outer_select();
+	    if (!($$= sel->
+                  add_table_to_list(lex->thd, new Table_ident(unit), $6, 0,
+				    TL_READ,(List<String> *)0,
+	                            (List<String> *)0)))
 
+	      YYABORT;
+            sel->add_joined_table($$);           
+          }
+	  else
+          if ($4 || $6)
+	  {
+            /* simple nested joins cannot have aliases or unions */
+            yyerror(ER(ER_SYNTAX_ERROR));
 	    YYABORT;
-          lex->current_select->add_joined_table($$);           
-	};
-
+	  }
+          else
+            $$= $3;
+	}
+        ;
 
+/* handle contents of parentheses in join expression */
 select_derived:
-	SELECT_SYM select_derived2
-	| '(' select_derived ')'
+	  get_select_lex
 	  {
-            SELECT_LEX *sel= Select;
-	    if (sel->set_braces(1))
-	    {
+            LEX *lex= Lex;
+            if ($1->init_nested_join(lex->thd))
+              YYABORT;
+          }
+          derived_table_list
+          {
+            LEX *lex= Lex;
+            /* for normal joins, $3 != NULL and end_nested_join() != NULL,
+               for derived tables, both must equal NULL */
+            
+            if (!($$= $1->end_nested_join(lex->thd)) && $3)
+              YYABORT;
+            if (!$3 && $$)
+            {
 	      yyerror(ER(ER_SYNTAX_ERROR));
 	      YYABORT;
-	    }
-            /* select in braces, can't contain global parameters */
-	    if (sel->master_unit()->fake_select_lex)
-              sel->master_unit()->global_parameters=
-                 sel->master_unit()->fake_select_lex;
-	  }
+            }
+          }
  	;
 
 select_derived2:
@@ -5458,6 +5614,29 @@
 	opt_select_from
         ;
 
+get_select_lex:
+	/* Empty */ { $$= Select; }
+        ;
+
+select_derived_init:
+          SELECT_SYM
+          {
+            LEX *lex= Lex;
+            SELECT_LEX *sel= lex->current_select;        
+            TABLE_LIST *embedding;
+            if (!sel->embedding || sel->end_nested_join(lex->thd))
+	    {
+              /* we are not in parentheses */
+              yyerror(ER(ER_SYNTAX_ERROR));
+	      YYABORT;
+	    }
+            embedding= Select->embedding;
+            $$= embedding &&
+                !embedding->nested_join->join_list.elements;
+            /* return true if we are deeply nested */
+          }
+        ;
+
 opt_outer:
 	/* empty */	{}
 	| OUTER		{};
@@ -6078,11 +6257,6 @@
 	   }
 	   ident_eq_list;
 
-opt_field_spec:
-	/* empty */	  { }
-	| '(' fields ')'  { }
-	| '(' ')'	  { };
-
 fields:
 	fields ',' insert_ident { Lex->field_list.push_back($3); }
 	| insert_ident		{ Lex->field_list.push_back($1); };
@@ -6784,34 +6958,53 @@
 
 /* import, export of files */
 
-load:	LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING_sys
+load:   LOAD DATA_SYM 
+        {
+          LEX *lex=Lex;
+          lex->fname_start= lex->ptr;
+        }
+        load_data
+        {}
+        |
+        LOAD TABLE_SYM table_ident FROM MASTER_SYM
+        {
+          Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
+          if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
+            YYABORT;
+        };
+
+load_data:
+	load_data_lock opt_local INFILE TEXT_STRING_sys
 	{
 	  LEX *lex=Lex;
 	  lex->sql_command= SQLCOM_LOAD;
-	  lex->lock_option= $3;
-	  lex->local_file=  $4;
+	  lex->lock_option= $1;
+	  lex->local_file=  $2;
 	  lex->duplicates= DUP_ERROR;
 	  lex->ignore= 0;
-	  if (!(lex->exchange= new sql_exchange($6.str,0)))
-	    YYABORT;
-	  lex->field_list.empty();
-	}
-	opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term
-	opt_ignore_lines opt_field_spec
-	{
-	  if (!Select->add_table_to_list(YYTHD, $11, NULL, TL_OPTION_UPDATING))
+	  if (!(lex->exchange= new sql_exchange($4.str, 0)))
 	    YYABORT;
+        }
+        opt_duplicate INTO
+        {
+	  LEX *lex=Lex;
+	  lex->fname_end= lex->ptr;
 	}
-        |
-	LOAD TABLE_SYM table_ident FROM MASTER_SYM
+        TABLE_SYM table_ident
         {
-	  Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
-	  if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
-	    YYABORT;
-
+          LEX *lex=Lex;
+          if (!Select->add_table_to_list(YYTHD, $10, NULL, TL_OPTION_UPDATING,
+                                         lex->lock_option))
+            YYABORT;
+          lex->field_list.empty();
+          lex->update_list.empty();
+          lex->value_list.empty();
         }
+        opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
+        opt_load_data_set_spec
+        {}
         |
-	LOAD DATA_SYM FROM MASTER_SYM
+	FROM MASTER_SYM
         {
 	  Lex->sql_command = SQLCOM_LOAD_MASTER_DATA;
         };
@@ -6891,6 +7084,29 @@
             Lex->exchange->skip_lines= atol($2.str);
           };
 
+opt_field_or_var_spec:
+	/* empty */	          { }
+	| '(' fields_or_vars ')'  { }
+	| '(' ')'	          { };
+
+fields_or_vars:
+        fields_or_vars ',' field_or_var
+          { Lex->field_list.push_back($3); }
+        | field_or_var
+          { Lex->field_list.push_back($1); }
+        ;
+        
+field_or_var:
+        simple_ident_nospvar {$$= $1;}
+        | '@' ident_or_text
+          { $$= new Item_user_var_as_out_param($2); }
+        ;
+
+opt_load_data_set_spec:
+        /* empty */           { }
+        | SET insert_update_list  { };
+
+
 /* Common definitions */
 
 text_literal:
@@ -7576,8 +7792,75 @@
 	| OPTION {};
 
 option_value_list:
+	option_type_value
+	| option_value_list ',' option_type_value;
+
+option_type_value:
+        {
+          if (Lex->sphead)
+          {
+            /*
+              If we are in SP we want have own LEX for each assignment.
+              This is mostly because it is hard for several sp_instr_set
+              and sp_instr_set_trigger instructions share one LEX. 
+              (Well, it is theoretically possible but adds some extra 
+               overhead on preparation for execution stage and IMO less
+               robust).
+
+              QQ: May be we should simply prohibit group assignments in SP?
+            */
+            LEX *lex;
+            Lex->sphead->reset_lex(YYTHD);
+            lex= Lex;
+            
+            /* Set new LEX as if we at start of set rule. */
+	    lex->sql_command= SQLCOM_SET_OPTION;
+	    mysql_init_select(lex);
+	    lex->option_type=OPT_SESSION;
+	    lex->var_list.empty();
+            lex->one_shot_set= 0;
+	    lex->sphead->m_tmp_query= lex->tok_start;
+          }
+        }
 	option_type option_value
-	| option_value_list ',' option_type option_value;
+        {
+          LEX *lex= Lex;
+          
+          if (lex->sphead)
+          {
+            sp_head *sp= lex->sphead;
+            
+	    if (!lex->var_list.is_empty())
+	    {
+              /*
+                We have assignment to user or system variable or
+                option setting, so we should construct sp_instr_stmt
+                for it.
+              */
+              LEX_STRING qbuff;
+	      sp_instr_stmt *i;
+              
+              if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont,
+                                         lex)))
+                YYABORT;
+                
+              if (lex->ptr - lex->tok_end > 1)
+                qbuff.length= lex->ptr - sp->m_tmp_query;
+              else
+                qbuff.length= lex->tok_end - sp->m_tmp_query;
+              
+              if (!(qbuff.str= alloc_root(YYTHD->mem_root, qbuff.length + 5)))
+                YYABORT;
+                
+              strmake(strmake(qbuff.str, "SET ", 4), (char *)sp->m_tmp_query,
+                      qbuff.length);
+              qbuff.length+= 4;
+              i->m_query= qbuff;
+              sp->add_instr(i);
+            }
+            lex->sphead->restore_lex(YYTHD);
+          }
+        };
 
 option_type:
 	/* empty */	{}
@@ -7604,31 +7887,7 @@
 option_value:
 	  '@' ident_or_text equal expr
 	  {
-            LEX *lex= Lex;
-
-            if (lex->sphead && lex->sphead->m_type !=
TYPE_ENUM_PROCEDURE)
-            {
-              /*
-                We have to use special instruction in functions and triggers
-                because sp_instr_stmt will close all tables and thus ruin
-                execution of statement invoking function or trigger.
-
-                We also do not want to allow expression with subselects in
-                this case.
-              */
-              if (lex->query_tables)
-              {
-                my_message(ER_SP_SUBSELECT_NYI, ER(ER_SP_SUBSELECT_NYI),
-                           MYF(0));
-                YYABORT;
-              }
-              sp_instr_set_user_var *i= 
-                new sp_instr_set_user_var(lex->sphead->instructions(),
-                                          lex->spcont, $2, $4);
-	      lex->sphead->add_instr(i);
-            }
-            else
-              lex->var_list.push_back(new set_var_user(new
Item_func_set_user_var($2,$4)));
+            Lex->var_list.push_back(new set_var_user(new
Item_func_set_user_var($2,$4)));
 	  }
 	| internal_variable_name equal set_expr_or_default
 	  {
@@ -7689,9 +7948,7 @@
 	      else
 	        it= new Item_null();
               i= new sp_instr_set(lex->sphead->instructions(), ctx,
-	                          spv->offset, it, spv->type);
-	      i->tables= lex->query_tables;
-	      lex->query_tables= 0;
+	                          spv->offset, it, spv->type, lex, TRUE);
 	      lex->sphead->add_instr(i);
 	      spv->isset= TRUE;
 	    }
@@ -7875,7 +8132,7 @@
 
 	  if (lex->sphead)
 	  {
-	    my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0));
+	    my_error(ER_SP_BADSTATEMENT, MYF(0), "LOCK");
 	    YYABORT;
 	  }
 	  lex->sql_command= SQLCOM_LOCK_TABLES;
@@ -7914,7 +8171,7 @@
 
 	  if (lex->sphead)
 	  {
-	    my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0));
+	    my_error(ER_SP_BADSTATEMENT, MYF(0), "UNLOCK");
 	    YYABORT;
 	  }
 	  lex->sql_command= SQLCOM_UNLOCK_TABLES;
@@ -8059,6 +8316,7 @@
 	| SHOW VIEW_SYM { Lex->grant |= SHOW_VIEW_ACL; }
 	| CREATE ROUTINE_SYM { Lex->grant |= CREATE_PROC_ACL; }
 	| ALTER ROUTINE_SYM { Lex->grant |= ALTER_PROC_ACL; }
+	| CREATE USER { Lex->grant |= CREATE_USER_ACL; }
 	;
 
 
@@ -8413,13 +8671,12 @@
 	;
 
 union_opt:
-	union_list {}
-	| optional_order_or_limit {}
+	/* Empty */ { $$= 0; }
+	| union_list { $$= 1; }
+	| union_order_or_limit { $$= 1; }
 	;
 
-optional_order_or_limit:
-	/* Empty */ {}
-	|
+union_order_or_limit:
 	  {
 	    THD *thd= YYTHD;
 	    LEX *lex= thd->lex;

--- 1.173/sql/table.cc	Wed Mar 23 17:57:03 2005
+++ 1.174/sql/table.cc	Tue Apr  5 15:01:20 2005
@@ -1417,6 +1417,15 @@
 
   part_info_len= uint4korr(head+51);
   share->frm_version= head[2];
+  /*
+    Check if .frm file created by MySQL 5.0. In this case we want to
+    display CHAR fields as CHAR and not as VARCHAR.
+    We do it this way as we want to keep the old frm version to enable
+    MySQL 4.1 to read these files.
+  */
+  if (share->frm_version == FRM_VER_TRUE_VARCHAR -1 && head[33] == 5)
+    share->frm_version= FRM_VER_TRUE_VARCHAR;
+
   share->db_type= ha_checktype((enum db_type) (uint) *(head+3));
   share->db_create_options= db_create_options=uint2korr(head+30);
   share->db_options_in_use= share->db_create_options;
@@ -2560,6 +2569,10 @@
   uint key_length;
   ulong length;
   char fill[IO_SIZE];
+  int create_flags= O_RDWR | O_TRUNC;
+
+  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+    create_flags|= O_EXCL | O_NOFOLLOW;
 
 #if SIZEOF_OFF_T > 4
   /* Fix this when we have new .frm files;  Current limit is 4G rows (QQ) */
@@ -2574,7 +2587,7 @@
   */
   set_if_smaller(create_info->raid_chunks, 255);
 
-  if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
+  if ((file= my_create(name, CREATE_MODE, create_flags, MYF(MY_WME))) >= 0)
   {
     bzero((char*) fileinfo,64);
     /* header */
@@ -2597,6 +2610,7 @@
     create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers
     int2store(fileinfo+30,create_info->table_options);
     fileinfo[32]=0;				// No filename anymore
+    fileinfo[33]=5;                             // Mark for 5.0 frm file
     int4store(fileinfo+34,create_info->avg_row_length);
     fileinfo[38]= (create_info->default_table_charset ?
 		   create_info->default_table_charset->number : 0);
@@ -2670,8 +2684,12 @@
 
   field->val_str(&str);
   if (!(length= str.length()))
+  {
+    res->length(0);
     return 1;
-  to= strmake_root(mem, str.ptr(), length);
+  }
+  if (!(to= strmake_root(mem, str.ptr(), length)))
+    length= 0;                                  // Safety fix
   res->set(to, length, ((Field_str*)field)->charset());
   return 0;
 }
@@ -2982,7 +3000,7 @@
     check_opt_type  - WHITH CHECK OPTION type (VIEW_CHECK_NONE,
                       VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED)
   NOTES
-    ancestor is list of tables and views used by view
+    ancestor is list of tables and views used by view (underlying tables/views)
 
   DESCRIPTION
     It is:
@@ -3016,6 +3034,9 @@
   bool res= FALSE;
   DBUG_ENTER("st_table_list::setup_ancestor");
 
+  if (check_stack_overrun(thd, (char *)&res))
+    return TRUE;
+
   for (tbl= ancestor; tbl; tbl= tbl->next_local)
   {
     if (tbl->ancestor &&
@@ -3251,6 +3272,34 @@
   DBUG_RETURN(res);
 }
 
+
+/*
+  Find underlying base tables (TABLE_LIST) which represent given
+  table_to_find (TABLE)
+
+  SYNOPSIS
+    st_table_list::find_underlying_table()
+    table_to_find table to find
+
+  RETURN
+    0  table is not found
+    found table reference
+*/
+
+st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find)
+{
+  /* is this real table and table which we are looking for? */
+  if (table == table_to_find && ancestor == 0)
+    return this;
+
+  for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+  {
+    TABLE_LIST *result;
+    if ((result= tbl->find_underlying_table(table_to_find)))
+      return result;
+  }
+  return 0;
+}
 
 /*
   cleunup items belonged to view fields translation table

--- 1.92/sql/table.h	Mon Mar 21 23:36:33 2005
+++ 1.93/sql/table.h	Tue Apr  5 15:01:20 2005
@@ -190,7 +190,7 @@
   ORDER		*group;
   const char	*alias;            	  /* alias or table name */
   uchar		*null_flags;
-  ulong		query_id;
+  query_id_t	query_id;
 
   ha_rows	quick_rows[MAX_KEY];
   key_part_map  const_key_parts[MAX_KEY];
@@ -325,6 +325,7 @@
 
 struct st_lex;
 class select_union;
+class TMP_TABLE_PARAM;
 
 struct Field_translator
 {
@@ -342,6 +343,15 @@
   char		*db, *alias, *table_name, *schema_table_name;
   char          *option;                /* Used by cache index  */
   Item		*on_expr;		/* Used with outer join */
+  /*
+    The scturcture of ON expression presented in the member above
+    can be changed during certain optimizations. This member
+    contains a snapshot of AND-OR structure of the ON expression
+    made after permanent transformations of the parse tree, and is
+    used to restore ON clause before every reexecution of a prepared
+    statement or stored procedure.
+  */
+  Item          *prep_on_expr;
   COND_EQUAL    *cond_equal;            /* Used with outer join */
   struct st_table_list *natural_join;	/* natural join on this table*/
   /* ... join ... USE INDEX ... IGNORE INDEX */
@@ -364,11 +374,12 @@
   ST_SCHEMA_TABLE *schema_table;        /* Information_schema table */
   st_select_lex	*schema_select_lex;
   bool schema_table_reformed;
+  TMP_TABLE_PARAM *schema_table_param;
   /* link to select_lex where this table was used */
   st_select_lex	*select_lex;
   st_lex	*view;			/* link on VIEW lex for merging */
   Field_translator *field_translation;	/* array of VIEW fields */
-  /* ancestor of this table (VIEW merge algorithm) */
+  /* list of ancestor(s) of this table (underlying table(s)/view(s) */
   st_table_list	*ancestor;
   /* most upper view this table belongs to */
   st_table_list	*belong_to_view;
@@ -423,6 +434,11 @@
   /* FRMTYPE_ERROR if any type is acceptable */
   enum frm_type_enum required_type;
   char		timestamp_buffer[20];	/* buffer for timestamp (19+1) */
+  /*
+    This TABLE_LIST object is just placeholder for prelocking, it will be
+    used for implicit LOCK TABLES only and won't be used in real statement.
+  */
+  bool          prelocking_placeholder;
 
   void calc_md5(char *buffer);
   void set_ancestor();
@@ -435,6 +451,7 @@
   void restore_want_privilege();
   bool check_single_table(st_table_list **table, table_map map);
   bool set_insert_values(MEM_ROOT *mem_root);
+  st_table_list *find_underlying_table(TABLE *table);
 } TABLE_LIST;
 
 class Item;

--- 1.56/sql/unireg.cc	Sat Feb 12 19:15:43 2005
+++ 1.57/sql/unireg.cc	Tue Apr  5 17:34:13 2005
@@ -40,7 +40,7 @@
 static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
 			    create_field *last_field);
 static bool pack_fields(File file, List<create_field> &create_fields);
-static bool make_empty_rec(int file, enum db_type table_type,
+static bool make_empty_rec(THD *thd, int file, enum db_type table_type,
 			   uint table_options,
 			   List<create_field> &create_fields,
 			   uint reclength,uint null_fields,
@@ -68,7 +68,7 @@
 		      HA_CREATE_INFO *create_info,
 		      List<create_field> &create_fields,
 		      uint keys, KEY *key_info,
-                      handler *db_file)
+		      handler *db_file)
 {
   uint reclength,info_length,screens,key_info_length,maxlength,null_fields;
   File file;
@@ -76,7 +76,6 @@
   uchar fileinfo[64],forminfo[288],*keybuff;
   TYPELIB formnames;
   uchar *screen_buff;
-  uint key_buff_length;
   DBUG_ENTER("mysql_create_frm");
 #ifdef HAVE_PARTITION_DB
   partition_info *part_info= thd->lex->part_info;
@@ -85,22 +84,23 @@
   formnames.type_names=0;
   if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
     DBUG_RETURN(1);
+  DBUG_ASSERT(db_file != NULL);
   if (pack_header(forminfo, create_info->db_type,create_fields,info_length,
 		  screens, create_info->table_options, db_file))
   {
     my_free((gptr) screen_buff,MYF(0));
     if (thd->net.last_errno != ER_TOO_MANY_FIELDS)
-      DBUG_RETURN(TRUE);
+      DBUG_RETURN(1);
 
     // Try again without UNIREG screens (to get more columns)
     thd->net.last_error[0]=0;
     if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
-      DBUG_RETURN(TRUE);
+      DBUG_RETURN(1);
     if (pack_header(forminfo, create_info->db_type, create_fields,info_length,
 		    screens, create_info->table_options, db_file))
     {
       my_free((gptr) screen_buff,MYF(0));
-      DBUG_RETURN(TRUE);
+      DBUG_RETURN(1);
     }
   }
   reclength=uint2korr(forminfo+266);
@@ -110,10 +110,10 @@
 		       create_info, keys)) < 0)
   {
     my_free((gptr) screen_buff,MYF(0));
-    DBUG_RETURN(TRUE);
+    DBUG_RETURN(1);
   }
 
-  key_buff_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
+  uint key_buff_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
   keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
   key_info_length=pack_keys(keybuff,keys,key_info);
   VOID(get_form_pos(file,fileinfo,&formnames));
@@ -144,7 +144,7 @@
   VOID(my_seek(file,
 	       (ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
 	       MY_SEEK_SET,MYF(0)));
-  if (make_empty_rec(file,create_info->db_type,create_info->table_options,
+  if (make_empty_rec(thd,file,create_info->db_type,create_info->table_options,
 		     create_fields,reclength,null_fields, db_file))
     goto err;
 
@@ -220,13 +220,14 @@
   Create a frm (table definition) file and the tables
 
   SYNOPSIS
-    mysql_create_frm()
+    rea_create_table()
     thd			Thread handler
     file_name		Name of file (including database and .frm)
     create_info		create info parameters
     create_fields	Fields to create
     keys		number of keys to create
     key_info		Keys to create
+    file		Handler to use.
   RETURN
     0  ok
     1  error
@@ -657,7 +658,7 @@
 
 	/* save an empty record on start of formfile */
 
-static bool make_empty_rec(File file,enum db_type table_type,
+static bool make_empty_rec(THD *thd, File file,enum db_type table_type,
 			   uint table_options,
 			   List<create_field> &create_fields,
 			   uint reclength, uint null_fields,
@@ -669,6 +670,7 @@
   uchar *buff,*null_pos;
   TABLE table;
   create_field *field;
+  enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
   DBUG_ENTER("make_empty_rec");
 
   /* We need a table to generate columns for default values */
@@ -680,7 +682,7 @@
     DBUG_RETURN(1);
   }
 
-  table.in_use= current_thd;
+  table.in_use= thd;
   table.s->db_low_byte_first= handler->low_byte_first();
   table.s->blob_ptr_size= portable_sizeof_char_ptr;
 
@@ -692,14 +694,14 @@
     null_count++;
   }
   bfill(buff,(null_length=(null_fields+7)/8),255);
-  null_pos=buff;
+  null_pos= buff + null_count / 8;
 
   List_iterator<create_field> it(create_fields);
+  thd->count_cuted_fields= CHECK_FIELD_WARN;    // To find wrong default values
   while ((field=it++))
   {
     Field *regfield=make_field((char*) buff+field->offset,field->length,
-			       field->flags & NOT_NULL_FLAG ? 0:
-			       null_pos+null_count/8,
+                               null_pos,
 			       null_count & 7,
 			       field->pack_flag,
 			       field->sql_type,
@@ -709,6 +711,7 @@
 			       field->interval,
 			       field->field_name,
 			       &table);
+    DBUG_ASSERT(regfield);
 
     if (!(field->flags & NOT_NULL_FLAG))
       null_count++;
@@ -722,7 +725,14 @@
     if (field->def &&
 	(regfield->real_type() != FIELD_TYPE_YEAR ||
 	 field->def->val_int() != 0))
-      (void) field->def->save_in_field(regfield, 1);
+    {
+      if (field->def->save_in_field(regfield, 1))
+      {
+        my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name);
+        error= 1;
+        goto err;
+      }
+    }
     else if (regfield->real_type() == FIELD_TYPE_ENUM &&
 	     (field->flags & NOT_NULL_FLAG))
     {
@@ -741,6 +751,9 @@
   /* Fill not used startpos */
   bfill((byte*) buff+null_length,firstpos-null_length,255);
   error=(int) my_write(file,(byte*) buff,(uint) reclength,MYF_RW);
+
+err:
   my_free((gptr) buff,MYF(MY_FAE));
+  thd->count_cuted_fields= old_count_cuted_fields;
   DBUG_RETURN(error);
 } /* make_empty_rec */

--- 1.24/sql/share/errmsg.txt	Fri Mar 18 10:12:47 2005
+++ 1.25/sql/share/errmsg.txt	Tue Apr  5 17:34:13 2005
@@ -1214,30 +1214,30 @@
 	swe "Tabellen '%-.64s' finns redan"
 	ukr "Таблиця '%-.64s' вже ¦сну╓"
 ER_BAD_TABLE_ERROR 42S02 
-	cze "Nezn-BАmА tabulka '%-.64s'"
-	dan "Ukendt tabel '%-.64s'"
-	nla "Onbekende tabel '%-.64s'"
-	eng "Unknown table '%-.64s'"
-	jps "table '%-.64s' ┌м┌ ┌Х┌э┌¹┌Я.",
-	est "Tundmatu tabel '%-.64s'"
-	fre "Table '%-.64s' inconnue"
-	ger "Unbekannte Tabelle '%-.64s'"
-	greek "аЦМЫСТОР ПъМАЙАР '%-.64s'"
-	hun "Ervenytelen tabla: '%-.64s'"
-	ita "Tabella '%-.64s' sconosciuta"
-	jpn "table '%-.64s' ¤о╓¢¤Й╓ч╓»¤С."
-	kor "евюл╨М '%-.64s'´б ¾к╪Ж ¾Ью╫"
-	nor "Ukjent tabell '%-.64s'"
-	norwegian-ny "Ukjent tabell '%-.64s'"
-	pol "Nieznana tabela '%-.64s'"
-	por "Tabela '%-.64s' desconhecida"
-	rum "Tabela '%-.64s' este invalida"
-	rus "Неизвестная таблица '%-.64s'"
-	serbian "Nepoznata tabela '%-.64s'"
-	slo "NeznАma tabuµka '%-.64s'"
-	spa "Tabla '%-.64s' desconocida"
-	swe "OkДnd tabell '%-.64s'"
-	ukr "Нев╕дома таблиця '%-.64s'"
+	cze "Nezn-BАmА tabulka '%-.180s'"
+	dan "Ukendt tabel '%-.180s'"
+	nla "Onbekende tabel '%-.180s'"
+	eng "Unknown table '%-.180s'"
+	jps "table '%-.180s' ┌м┌ ┌Х┌э┌¹┌Я.",
+	est "Tundmatu tabel '%-.180s'"
+	fre "Table '%-.180s' inconnue"
+	ger "Unbekannte Tabelle '%-.180s'"
+	greek "аЦМЫСТОР ПъМАЙАР '%-.180s'"
+	hun "Ervenytelen tabla: '%-.180s'"
+	ita "Tabella '%-.180s' sconosciuta"
+	jpn "table '%-.180s' ¤о╓¢¤Й╓ч╓»¤С."
+	kor "евюл╨М '%-.180s'´б ¾к╪Ж ¾Ью╫"
+	nor "Ukjent tabell '%-.180s'"
+	norwegian-ny "Ukjent tabell '%-.180s'"
+	pol "Nieznana tabela '%-.180s'"
+	por "Tabela '%-.180s' desconhecida"
+	rum "Tabela '%-.180s' este invalida"
+	rus "Неизвестная таблица '%-.180s'"
+	serbian "Nepoznata tabela '%-.180s'"
+	slo "NeznАma tabuµka '%-.180s'"
+	spa "Tabla '%-.180s' desconocida"
+	swe "OkДnd tabell '%-.180s'"
+	ukr "Нев╕дома таблиця '%-.180s'"
 ER_NON_UNIQ_ERROR 23000 
 	cze "Sloupec '%-.64s' v %s nen-BМ zcela jasnЩ"
 	dan "Felt: '%-.64s' i tabel %s er ikke entydigt"
@@ -1774,7 +1774,7 @@
 	cze "P-BЬМli¹ velkА dИlka sloupce '%-.64s' (nejvМce %d). Pou¾ijte BLOB"
 	dan "For stor feltlФngde for kolonne '%-.64s' (maks = %d). Brug BLOB i stedet"
 	nla "Te grote kolomlengte voor '%-.64s' (max = %d). Maak hiervoor gebruik van het type
BLOB"
-	eng "Column length too big for column '%-.64s' (max = %d); use BLOB instead"
+	eng "Column length too big for column '%-.64s' (max = %d); use BLOB or TEXT instead"
 	jps "column '%-.64s' ┌м,┼m∙ш┌·┌И column
┌л▒Е┌╚┌³┌ª▒½┌·┌¬┌э┌·. (█е▒Е %d ┌э┌е). BLOB
┌П┌╘┌М┌Х┌и▌g≈p┌µ┌д┌­┌¾┌³┌¢.",
 	est "Tulba '%-.64s' pikkus on liiga pikk (maksimaalne pikkus: %d). Kasuta BLOB
vДljatЭЭpi"
 	fre "Champ '%-.64s' trop long (max = %d). Utilisez un BLOB"
@@ -1789,7 +1789,7 @@
 	pol "Zbyt du¿a d³ugo?Ф kolumny '%-.64s' (maks. = %d). W zamian u¿yj
typu BLOB"
 	por "Comprimento da coluna '%-.64s' grande demais (max = %d); use BLOB em seu lugar"
 	rum "Lungimea coloanei '%-.64s' este prea lunga (maximum = %d). Foloseste BLOB mai bine"
-	rus "Слишком большая длина столбца '%-.64s' (максимум = %d). Используйте тип BLOB вместо
текущего"
+	rus "Слишком большая длина столбца '%-.64s' (максимум = %d). Используйте тип BLOB или
TEXT вместо текущего"
 	serbian "Previ e podataka za kolonu '%-.64s' (maksimum je %d). Upotrebite BLOB polje"
 	slo "PrМli¹ veµkА dЕ╬ka pre pole '%-.64s' (maximum = %d). Pou¾ite
BLOB"
 	spa "Longitud de columna demasiado grande para la columna '%-.64s' (maximo = %d).Usar
BLOB en su lugar"
@@ -1839,7 +1839,7 @@
 	pol "%s: gotowe do po³?czenia"
 	por "%s: Pronto para conexУes"
 	rum "%s: sint gata pentru conectii"
-	rus "%s: Готов принимать соединения.\nВерсия: '%s'  сокет: '%s'  порт: %d"
+	rus "%s: Готов принимать соединения.\nВерсия: '%s'  сокет: '%s'  порт: %d  %s"
 	serbian "%s: Spreman za konekcije\n"
 	slo "%s: pripravenЩ na spojenie"
 	spa "%s: preparado para conexiones"
@@ -4637,7 +4637,7 @@
 	rus "Пользователь '%-.64s' превысил использование ресурса '%s' (текущее значение: %ld)"
 	spa "Usuario '%-.64s' ha excedido el recurso '%s' (actual valor: %ld)"
 	swe "AnvДndare '%-.64s' har Жverskridit '%s' (nuvarande vДrde: %ld)"
-ER_SPECIFIC_ACCESS_DENIED_ERROR  
+ER_SPECIFIC_ACCESS_DENIED_ERROR 42000 
 	nla "Toegang geweigerd. U moet het %-.128s privilege hebben voor deze operatie"
 	eng "Access denied; you need the %-.128s privilege for this operation"
 	ger "Befehl nicht zulДssig. HierfЭr wird die Berechtigung %-.128s benЖtigt"
@@ -5094,7 +5094,7 @@
 ER_SP_BADRETURN 42000 
 	eng "RETURN is only allowed in a FUNCTION"
 ER_SP_BADSTATEMENT 0A000 
-	eng "LOCK and UNLOCK tables are not allowed in stored procedures"
+	eng "%s is not allowed in stored procedures"
 ER_UPDATE_LOG_DEPRECATED_IGNORED 42000 
 	eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has
been ignored"
 ER_UPDATE_LOG_DEPRECATED_TRANSLATED 42000 
@@ -5374,3 +5374,11 @@
         eng "A Nullable field in partition function is not allowed"
 ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF
         eng "A %s need to include all fields in the partition function"
+ER_STARTUP
+	eng "%s: ready for connections.\nVersion: '%s'  socket: '%s'  port: %d  %s"
+ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR
+        eng "Can't load value from file with fixed size rows to variable"
+ER_CANT_CREATE_USER_WITH_GRANT 42000
+	eng "You are not allowed to create a user with GRANT"
+ER_WRONG_VALUE_FOR_TYPE  
+	eng "Incorrect %-.32s value: '%-.128s' for function %-.32s"

--- 1.303/BitKeeper/etc/logging_ok	Tue Apr  5 11:31:46 2005
+++ 1.304/BitKeeper/etc/logging_ok	Tue Apr  5 14:59:10 2005
@@ -142,6 +142,7 @@
 miguel@stripped
 mikael@mc04.(none)
 mikael@stripped
+mikron@stripped
 mikron@stripped
 mikron@stripped
 mleich@stripped

--- 1.169/sql/ha_ndbcluster.cc	Fri Apr  1 20:58:23 2005
+++ 1.170/sql/ha_ndbcluster.cc	Tue Apr  5 15:01:08 2005
@@ -3806,6 +3806,26 @@
   my_free((char*)data, MYF(0));
   my_free((char*)pack_data, MYF(0));
   
+  partition_info *part_info= form->s->part_info;
+  // Currently only support for one field in the partion key
+  Field *partition_field= 0;
+  // Check partition info
+  if (part_info)
+  {
+      if (part_info->part_type == HASH_PARTITION &&
+	  part_info->list_of_part_fields == TRUE &&
+	  part_info->subpart_type == NOT_A_PARTITION &&
+	  part_info->part_field_list.elements == 1 &&
+	  part_info->part_field_array[0]->flags & PRI_KEY_FLAG)
+      {
+	  partition_field= part_info->part_field_array[0];
+      }
+      else
+      {
+	  return HA_ERR_UNSUPPORTED;
+      }
+  }
+
   for (i= 0; i < form->s->fields; i++) 
   {
     Field *field= form->field[i];
@@ -3814,6 +3834,13 @@
                         field->pack_length()));
     if ((my_errno= create_ndb_column(col, field, info)))
       DBUG_RETURN(my_errno);
+    if (partition_field)
+    {
+	if (partition_field == field)
+	    col.setDistributionKey(TRUE);
+	else
+	    col.setDistributionKey(FALSE);
+    }
     tab.addColumn(col);
     if(col.getPrimaryKey())
       pk_length += (field->pack_length() + 3) / 4;
@@ -4106,11 +4133,12 @@
   m_tableVersion(-1),
   m_table_info(NULL),
   m_table_flags(HA_REC_NOT_IN_SEQ |
-                HA_NULL_IN_KEY |
-                HA_AUTO_PART_KEY |
-                HA_NO_PREFIX_CHAR_KEYS |
-                HA_NEED_READ_RANGE_BUFFER |
-                HA_CAN_BIT_FIELD),
+		HA_NULL_IN_KEY |
+                HA_CAN_PARTITION |
+		HA_AUTO_PART_KEY |
+		HA_NO_PREFIX_CHAR_KEYS |
+		HA_NEED_READ_RANGE_BUFFER |
+		HA_CAN_BIT_FIELD),
   m_share(0),
   m_use_write(FALSE),
   m_ignore_dup_key(FALSE),

--- 1.79/sql/ha_ndbcluster.h	Tue Mar 22 22:29:56 2005
+++ 1.80/sql/ha_ndbcluster.h	Tue Apr  5 15:01:09 2005
@@ -432,6 +432,10 @@
   const char * table_type() const;
   const char ** bas_ext() const;
   ulong table_flags(void) const;
+  ulong table_flags2(void) const
+  {
+    return HA_CAN_UPDATE_PARTITION_KEY;
+  }
   ulong index_flags(uint idx, uint part, bool all_parts) const;
   uint max_supported_record_length() const;
   uint max_supported_keys() const;

--- 1.89/BitKeeper/deleted/.del-errmsg.txt~8ed1999cbd481dc4	Tue Dec 14 15:13:13 2004
+++ 1.90/BitKeeper/deleted/.del-errmsg.txt~8ed1999cbd481dc4	Tue Apr  5 17:34:12 2005
@@ -73,7 +73,7 @@
 "óÔÏ×ÂÅÃØ '%-.64s' ÎÅ
ÍÏÖÅ ÂÕÔÉ
ÎÕÌØÏ×ÉÍ",
 "îÅв╕ÄÏÍÁ ÂÁÚÁ
ÄÁÎÎÉÈ '%-.64s'",
 "ôÁÂÌÉÃÑ '%-.64s' ×ÖÅ
¦ÓÎу╓",
-"îÅв╕ÄÏÍÁ
ÔÁÂÌÉÃÑ '%-.64s'",
+"îÅв╕ÄÏÍÁ
ÔÁÂÌÉÃÑ '%-.180s'",
 "óÔÏ×ÂÅÃØ '%-.64s' Õ %-.64s
×ÉÚÎÁÞÅÎÉÊ
ÎÅÏÄÎÏÚÎÁÞÎÏ",
 "úÁ×ÅÒÛу╓ÔØÓÑ
ÒÁÂÏÔÁ
ÓÅÒ×ÅÒÁ",
 "îÅв╕ÄÏÍÉÊ
ÓÔÏ×ÂÅÃØ '%-.64s' Õ '%-.64s'",

--- 1.86/sql/set_var.cc	Tue Mar  1 22:38:53 2005
+++ 1.87/sql/set_var.cc	Tue Apr  5 15:01:13 2005
@@ -340,6 +340,8 @@
 #ifdef HAVE_REPLICATION
 sys_var_long_ptr	sys_slave_net_timeout("slave_net_timeout",
 					      &slave_net_timeout);
+sys_var_long_ptr	sys_slave_trans_retries("slave_transaction_retries",
+                                                &slave_trans_retries);
 #endif
 sys_var_long_ptr	sys_slow_launch_time("slow_launch_time",
 					     &slow_launch_time);
@@ -390,6 +392,8 @@
 							&srv_max_purge_lag);
 sys_var_thd_bool	sys_innodb_table_locks("innodb_table_locks",
                                                &SV::innodb_table_locks);
+sys_var_thd_bool	sys_innodb_support_xa("innodb_support_xa",
+                                               &SV::innodb_support_xa);
 sys_var_long_ptr	sys_innodb_autoextend_increment("innodb_autoextend_increment",
 							&srv_auto_extend_increment);
 sys_var_long_ptr	sys_innodb_sync_spin_loops("innodb_sync_spin_loops",
@@ -409,7 +413,7 @@
 
 #ifdef HAVE_NDBCLUSTER_DB
 /* ndb thread specific variable settings */
-sys_var_thd_ulong 
+sys_var_thd_ulong
 sys_ndb_autoincrement_prefetch_sz("ndb_autoincrement_prefetch_sz",
 				  &SV::ndb_autoincrement_prefetch_sz);
 sys_var_thd_bool
@@ -418,7 +422,8 @@
 sys_ndb_use_exact_count("ndb_use_exact_count", &SV::ndb_use_exact_count);
 sys_var_thd_bool
 sys_ndb_use_transactions("ndb_use_transactions", &SV::ndb_use_transactions);
-sys_var_long_ptr sys_ndb_cache_check_time("ndb_cache_check_time",
&ndb_cache_check_time);
+sys_var_long_ptr
+sys_ndb_cache_check_time("ndb_cache_check_time", &ndb_cache_check_time);
 #endif
 
 /* Time/date/datetime formats */
@@ -652,6 +657,7 @@
 #ifdef HAVE_REPLICATION
   &sys_slave_compressed_protocol,
   &sys_slave_net_timeout,
+  &sys_slave_trans_retries,
   &sys_slave_skip_counter,
 #endif
   &sys_slow_launch_time,
@@ -686,6 +692,7 @@
   &sys_innodb_max_dirty_pages_pct,
   &sys_innodb_max_purge_lag,
   &sys_innodb_table_locks,
+  &sys_innodb_support_xa,
   &sys_innodb_max_purge_lag,
   &sys_innodb_autoextend_increment,
   &sys_innodb_sync_spin_loops,
@@ -696,10 +703,10 @@
   &sys_engine_condition_pushdown,
 #ifdef HAVE_NDBCLUSTER_DB
   &sys_ndb_autoincrement_prefetch_sz,
+  &sys_ndb_cache_check_time,
   &sys_ndb_force_send,
   &sys_ndb_use_exact_count,
   &sys_ndb_use_transactions,
-  &sys_ndb_cache_check_time,
 #endif
   &sys_unique_checks,
   &sys_updatable_views_with_limit,
@@ -760,6 +767,7 @@
   {sys_group_concat_max_len.name, (char*) &sys_group_concat_max_len,  SHOW_SYS},
   {"have_archive",	      (char*) &have_archive_db,	            SHOW_HAVE},
   {"have_bdb",		      (char*) &have_berkeley_db,	    SHOW_HAVE},
+  {"have_blackhole_engine",   (char*) &have_blackhole_db,	    SHOW_HAVE},
   {"have_compress",	      (char*) &have_compress,		    SHOW_HAVE},
   {"have_crypt",	      (char*) &have_crypt,		    SHOW_HAVE},
   {"have_csv",	              (char*) &have_csv_db,	            SHOW_HAVE},
@@ -808,6 +816,7 @@
   {"innodb_open_files", (char*) &innobase_open_files, SHOW_LONG },
   {sys_innodb_sync_spin_loops.name, (char*) &sys_innodb_sync_spin_loops, SHOW_SYS},
   {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS},
+  {sys_innodb_support_xa.name, (char*) &sys_innodb_support_xa, SHOW_SYS},
   {sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency,
SHOW_SYS},
   {sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay,
SHOW_SYS},
 #endif
@@ -919,6 +928,7 @@
   {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size,	    SHOW_SYS},
 #ifdef HAVE_REPLICATION
   {sys_relay_log_purge.name,  (char*) &sys_relay_log_purge,         SHOW_SYS},
+  {"relay_log_space_limit",  (char*) &relay_log_space_limit,        SHOW_LONGLONG},
 #endif
   {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank,       SHOW_SYS},
   {"secure_auth",             (char*) &sys_secure_auth,             SHOW_SYS},
@@ -932,6 +942,7 @@
   {"skip_show_database",      (char*) &opt_skip_show_db,            SHOW_BOOL},
 #ifdef HAVE_REPLICATION
   {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout,	    SHOW_SYS},
+  {sys_slave_trans_retries.name,(char*) &sys_slave_trans_retries,   SHOW_SYS},
 #endif
   {sys_slow_launch_time.name, (char*) &sys_slow_launch_time,        SHOW_SYS},
 #ifdef HAVE_SYS_UN_H
@@ -1291,7 +1302,6 @@
   return 0;
 }
 
-
 static void fix_max_connections(THD *thd, enum_var_type type)
 {
 #ifndef EMBEDDED_LIBRARY
@@ -1312,10 +1322,12 @@
 
 static void fix_trans_mem_root(THD *thd, enum_var_type type)
 {
+#ifdef USING_TRANSACTIONS
   if (type != OPT_GLOBAL)
     reset_root_defaults(&thd->transaction.mem_root,
                         thd->variables.trans_alloc_block_size,
                         thd->variables.trans_prealloc_size);
+#endif
 }
 
 
@@ -2085,27 +2097,6 @@
  }
 }
 
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
-bool sys_var_character_set_server::check(THD *thd, set_var *var)
-{
-  /*
-    To be perfect we should fail even if we are a 5.0.3 slave, a 4.1 master,
-    and user wants to change our global character set variables. Because
-    replicating a 4.1 assumes those are not changed. But that's not easy to
-    do.
-  */
-  if ((var->type == OPT_GLOBAL) &&
-      (mysql_bin_log.is_open() ||
-       active_mi->slave_running || active_mi->rli.slave_running))
-  {
-    my_error(ER_LOGGING_PROHIBIT_CHANGING_OF, MYF(0),
-	     "character set, collation");
-    return 1;
-  }
-  return sys_var_character_set::check(thd,var);
-}
-#endif
-
 CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd,
 						       enum_var_type type)
 {
@@ -2198,20 +2189,6 @@
  }
 }
 
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
-bool sys_var_collation_server::check(THD *thd, set_var *var)
-{
-  if ((var->type == OPT_GLOBAL) &&
-      (mysql_bin_log.is_open() ||
-       active_mi->slave_running || active_mi->rli.slave_running))
-  {
-    my_error(ER_LOGGING_PROHIBIT_CHANGING_OF, MYF(0),
-	     "character set, collation");
-    return 1;
-  }
-  return sys_var_collation::check(thd,var);
-}
-#endif
 
 bool sys_var_collation_server::update(THD *thd, set_var *var)
 {
@@ -2550,16 +2527,6 @@
   String str(buff, sizeof(buff), &my_charset_latin1);
   String *res= var->value->val_str(&str);
 
-#if defined(HAVE_REPLICATION)
-  if ((var->type == OPT_GLOBAL) &&
-      (mysql_bin_log.is_open() ||
-       active_mi->slave_running || active_mi->rli.slave_running))
-  {
-    my_error(ER_LOGGING_PROHIBIT_CHANGING_OF, MYF(0), "time zone");
-    return 1;
-  }
-#endif
-
   if (!(var->save_result.time_zone=
         my_tz_find(res, thd->lex->time_zone_tables_used)))
   {
@@ -2595,7 +2562,18 @@
   if (type == OPT_GLOBAL)
     return (byte *)(global_system_variables.time_zone->get_name()->ptr());
   else
+  {
+    /*
+      This is an ugly fix for replication: we don't replicate properly queries
+      invoking system variables' values to update tables; but
+      CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
+      replicable (i.e. we tell the binlog code to store the session
+      timezone). If it's the global value which was used we can't replicate
+      (binlog code stores session value only).
+    */
+    thd->time_zone_used= 1;
     return (byte *)(thd->variables.time_zone->get_name()->ptr());
+  }
 }
 
 
@@ -2642,7 +2620,7 @@
 {
   DBUG_ASSERT(var->type == OPT_GLOBAL);
   pthread_mutex_lock(&LOCK_global_system_variables);
-  max_user_connections= var->save_result.ulonglong_value;
+  max_user_connections= (uint)var->save_result.ulonglong_value;
   pthread_mutex_unlock(&LOCK_global_system_variables);
   return 0;
 }
@@ -3273,8 +3251,14 @@
   */
 
   if (sql_mode & MODE_ANSI)
+  {
     sql_mode|= (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
-		MODE_IGNORE_SPACE | MODE_ONLY_FULL_GROUP_BY);
+		MODE_IGNORE_SPACE);
+    /* 
+      MODE_ONLY_FULL_GROUP_BY removed from ANSI mode because it is currently
+      overly restrictive (see BUG#8510).
+    */
+  }
   if (sql_mode & MODE_ORACLE)
     sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
 		MODE_IGNORE_SPACE |
Thread
bk commit into 5.0 tree (mronstrom:1.1873)mikael5 Apr