List:Commits« Previous MessageNext Message »
From:jon Date:August 5 2006 4:11pm
Subject:bk commit into 5.2 tree (jon:1.2176)
View as plain text  
Below is the list of changes that have just been committed into a local
5.2 repository of jon. When jon 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@stripped, 2006-08-06 02:11:32+10:00, jon@stripped +16 -0
  Merge jstephens@stripped:/home/bk/mysql-5.2
  into  gigan.homedns.org:/home/jon/bk/mysql-5.2
  MERGE: 1.2174.1.91

  configure.in@stripped, 2006-08-06 02:11:12+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.345.1.4

  mysql-test/lib/mtr_process.pl@stripped, 2006-08-06 02:11:12+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.33.1.2

  mysql-test/mysql-test-run.pl@stripped, 2006-08-06 02:11:12+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.120.1.6

  mysql-test/mysql-test-run.sh@stripped, 2006-08-06 02:11:12+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.311.1.4

  mysql-test/r/innodb.result@stripped, 2006-08-06 02:11:13+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.168.1.2

  mysql-test/r/trigger-grant.result@stripped, 2006-08-06 02:11:13+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.7.1.3

  mysql-test/t/innodb.test@stripped, 2006-08-06 02:11:13+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.134.1.2

  mysql-test/t/trigger-grant.test@stripped, 2006-08-06 02:11:13+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.10.1.2

  scripts/make_binary_distribution.sh@stripped, 2006-08-06 02:11:13+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.114.1.2

  sql/ha_innodb.cc@stripped, 2006-08-06 02:11:13+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.263.1.3

  sql/handler.cc@stripped, 2006-08-06 02:11:14+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.221.1.3

  sql/item.cc@stripped, 2006-08-06 02:11:14+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.176.1.3

  sql/item.h@stripped, 2006-08-06 02:11:14+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.197.1.3

  sql/share/errmsg.txt@stripped, 2006-08-06 02:11:18+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.89.1.4

  sql/sql_trigger.cc@stripped, 2006-08-06 02:11:14+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.53.1.2

  sql/sql_yacc.yy@stripped, 2006-08-06 02:11:15+10:00, jon@stripped +0 -0
    Auto merged
    MERGE: 1.465.1.4

# 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:	jon
# Host:	gigan.site
# Root:	/home/jon/bk/mysql-5.2/RESYNC

--- 1.346/configure.in	2006-08-06 02:11:47 +10:00
+++ 1.347/configure.in	2006-08-06 02:11:47 +10:00
@@ -358,18 +358,18 @@
 AC_SUBST(LD_VERSION_SCRIPT)
 
 # Avoid bug in fcntl on some versions of linux
-AC_MSG_CHECKING("if we should use 'skip-locking' as default for $target_os")
+AC_MSG_CHECKING([if we should use 'skip-external-locking' as default for $target_os])
 # Any variation of Linux
 if expr "$target_os" : "[[Ll]]inux.*" > /dev/null
 then
-  MYSQLD_DEFAULT_SWITCHES="--skip-locking"
+  MYSQLD_DEFAULT_SWITCHES="--skip-external-locking"
   TARGET_LINUX="true"
-  AC_MSG_RESULT("yes")
+  AC_MSG_RESULT([yes])
   AC_DEFINE([TARGET_OS_LINUX], [1], [Whether we build for Linux])
 else
   MYSQLD_DEFAULT_SWITCHES=""
   TARGET_LINUX="false"
-  AC_MSG_RESULT("no")
+  AC_MSG_RESULT([no])
 fi
 AC_SUBST(MYSQLD_DEFAULT_SWITCHES)
 AC_SUBST(TARGET_LINUX)
@@ -482,6 +482,10 @@
 
 # We need an assembler, too
 AM_PROG_AS
+CCASFLAGS="$CCASFLAGS $ASFLAGS"
+
+# Check if we need noexec stack for assembler
+AC_CHECK_NOEXECSTACK
 
 if test "$am_cv_prog_cc_stdc" = "no"
 then
@@ -2474,10 +2478,6 @@
 AC_SUBST(linked_netware_sources)
 AM_CONDITIONAL(HAVE_NETWARE, test "$netware_dir" = "netware")
 
-# Ensure that table handlers gets all modifications to CFLAGS/CXXFLAGS
-export CC CXX CFLAGS CXXFLAGS LD LDFLAGS AR
-ac_configure_args="$ac_configure_args CFLAGS='$CFLAGS' CXXFLAGS='$CXXFLAGS'"
-
 if test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no"
 then
   AC_DEFINE([THREAD], [1],
@@ -2527,22 +2527,6 @@
 AC_SUBST(GXX)
 
 # Set configuration options for make_binary_distribution
-
-CONF_ARGS=
-case $SYSTEM_TYPE in
-  *netware*)
-    MAKE_BINARY_DISTRIBUTION_OPTIONS=--no-strip
-    CONF_ARGS=--host="$MACHINE_TYPE-$SYSTEM_TYPE"
-    ;;
-  *)
-    MAKE_BINARY_DISTRIBUTION_OPTIONS=
-    ;;
-esac
-
-for CONF in $other_configures; do
-  (cd `dirname $CONF`; ./`basename $CONF` $CONF_ARGS --build=$build_alias)
-done
-
 AC_SUBST(MAKE_BINARY_DISTRIBUTION_OPTIONS)
 
 # Output results
@@ -2559,8 +2543,13 @@
  support-files/MacOSX/Makefile mysql-test/Makefile dnl
  mysql-test/ndb/Makefile netware/Makefile dnl
  include/mysql_version.h plugin/Makefile win/Makefile)
- AC_CONFIG_COMMANDS([default], , test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h)
- AC_OUTPUT
+
+AC_CONFIG_COMMANDS([default], , test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h)
+
+# Ensure that table handlers gets all modifications to CFLAGS/CXXFLAGS
+AC_CONFIG_COMMANDS_POST(ac_configure_args="$ac_configure_args CFLAGS='$CFLAGS' CXXFLAGS='$CXXFLAGS'")
+
+AC_OUTPUT
 
 echo
 echo "MySQL has a Web site at http://www.mysql.com/ which carries details on the"

--- 1.312/mysql-test/mysql-test-run.sh	2006-08-06 02:11:47 +10:00
+++ 1.313/mysql-test/mysql-test-run.sh	2006-08-06 02:11:47 +10:00
@@ -1121,7 +1121,10 @@
     if [ ! -z "$USE_NDBCLUSTER" ]
     then
       $ECHO "Installing Master Databases 1"
-      $INSTALL_DB -1
+#     $INSTALL_DB -1
+      $RM -rf var/master-data1
+      mkdir var/master-data1
+      cp -r var/master-data/* var/master-data1
       if [ $? != 0 ]; then
 	error "Could not install master test DBs 1"
 	exit 1
@@ -1129,7 +1132,9 @@
     fi
     $ECHO "Installing Slave Databases"
     $RM -rf $SLAVE_MYDDIR $MY_LOG_DIR/* 
-    $INSTALL_DB -slave
+#    $INSTALL_DB -slave
+    mkdir var/slave-data
+    cp -r var/master-data/* var/slave-data
     if [ $? != 0 ]; then
 	error "Could not install slave test DBs"
 	exit 1
@@ -2155,6 +2160,7 @@
 
   # Remove files that can cause problems
   $RM -rf $MYSQL_TEST_DIR/var/ndbcluster
+  $RM -rf $MYSQL_TEST_DIR/var/tmp/snapshot*
   $RM -f $MYSQL_TEST_DIR/var/run/* $MYSQL_TEST_DIR/var/tmp/*
 
   # Remove old berkeley db log files that can confuse the server
@@ -2172,12 +2178,7 @@
     USE_NDBCLUSTER_OPT=
   fi
 
-# Do not automagically start daemons if we are in gdb or running only one
-# test case
-  if [ -z "$DO_GDB" ] && [ -z "$DO_DDD" ]
-  then
-    mysql_start
-  fi
+  mysql_start
   $ECHO  "Loading Standard Test Databases"
   mysql_loadstd
 fi

--- 1.115/scripts/make_binary_distribution.sh	2006-08-06 02:11:47 +10:00
+++ 1.116/scripts/make_binary_distribution.sh	2006-08-06 02:11:47 +10:00
@@ -138,7 +138,7 @@
   client/mysqlslap$BS \
   client/mysqldump$BS client/mysqlimport$BS \
   client/mysqltest$BS client/mysqlcheck$BS \
-  client/mysqlbinlog$BS \
+  client/mysqlbinlog$BS client/mysql_upgrade$BS \
   tests/mysql_client_test$BS \
   libmysqld/examples/mysql_client_test_embedded$BS \
   libmysqld/examples/mysqltest_embedded$BS \
@@ -181,11 +181,21 @@
 fi
 
 copyfileto $BASE/lib \
-  libmysql/.libs/libmysqlclient.a libmysql/.libs/libmysqlclient.so* \
-  libmysql/libmysqlclient.* libmysql_r/.libs/libmysqlclient_r.a \
-  libmysql_r/.libs/libmysqlclient_r.so* libmysql_r/libmysqlclient_r.* \
+  libmysql/.libs/libmysqlclient.a \
+  libmysql/.libs/libmysqlclient.so* \
+  libmysql/.libs/libmysqlclient.sl* \
+  libmysql/.libs/libmysqlclient*.dylib \
+  libmysql/libmysqlclient.* \
+  libmysql_r/.libs/libmysqlclient_r.a \
+  libmysql_r/.libs/libmysqlclient_r.so* \
+  libmysql_r/.libs/libmysqlclient_r.sl* \
+  libmysql_r/.libs/libmysqlclient_r*.dylib \
+  libmysql_r/libmysqlclient_r.* \
+  libmysqld/.libs/libmysqld.a \
+  libmysqld/.libs/libmysqld.so* \
+  libmysqld/.libs/libmysqld.sl* \
+  libmysqld/.libs/libmysqld*.dylib \
   mysys/libmysys.a strings/libmystrings.a dbug/libdbug.a \
-  libmysqld/.libs/libmysqld.a libmysqld/.libs/libmysqld.so* \
   libmysqld/libmysqld.a netware/libmysql.imp \
   zlib/.libs/libz.a
 

--- 1.222/sql/handler.cc	2006-08-06 02:11:48 +10:00
+++ 1.223/sql/handler.cc	2006-08-06 02:11:48 +10:00
@@ -44,19 +44,22 @@
 #include "ha_innodb.h"
 #endif
 
-/* While we have legacy_db_type, we have this array to
-   check for dups and to find handlerton from legacy_db_type.
-   Remove when legacy_db_type is finally gone */
-static handlerton *installed_htons[128];
+/*
+  While we have legacy_db_type, we have this array to
+  check for dups and to find handlerton from legacy_db_type.
+  Remove when legacy_db_type is finally gone
+*/
 st_plugin_int *hton2plugin[MAX_HA];
 
+static handlerton *installed_htons[128];
+
 #define BITMAP_STACKBUF_SIZE (128/8)
 
 KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0} };
 
 /* static functions defined in this file */
 
-static handler *create_default(TABLE_SHARE *table);
+static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root);
 
 static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
 
@@ -67,14 +70,14 @@
 /* size of savepoint storage area (see ha_init) */
 ulong savepoint_alloc_size= 0;
 
-struct show_table_alias_st sys_table_aliases[]=
+static const LEX_STRING sys_table_aliases[]=
 {
-  {"INNOBASE",  DB_TYPE_INNODB},
-  {"NDB",       DB_TYPE_NDBCLUSTER},
-  {"BDB",       DB_TYPE_BERKELEY_DB},
-  {"HEAP",      DB_TYPE_HEAP},
-  {"MERGE",     DB_TYPE_MRG_MYISAM},
-  {NullS,       DB_TYPE_UNKNOWN}
+  {(char*)STRING_WITH_LEN("INNOBASE")},  {(char*)STRING_WITH_LEN("INNODB")},
+  {(char*)STRING_WITH_LEN("NDB")},       {(char*)STRING_WITH_LEN("NDBCLUSTER")},
+  {(char*)STRING_WITH_LEN("BDB")},       {(char*)STRING_WITH_LEN("BERKELEYDB")},
+  {(char*)STRING_WITH_LEN("HEAP")},      {(char*)STRING_WITH_LEN("MEMORY")},
+  {(char*)STRING_WITH_LEN("MERGE")},     {(char*)STRING_WITH_LEN("MRG_MYISAM")},
+  {NullS, 0}
 };
 
 const char *ha_row_type[] = {
@@ -90,15 +93,50 @@
 static TYPELIB known_extensions= {0,"known_exts", NULL, NULL};
 uint known_extensions_id= 0;
 
-handlerton *ha_resolve_by_name(THD *thd, LEX_STRING *name)
+
+/*
+  Return the default storage engine handlerton for thread
+  
+  SYNOPSIS
+    ha_default_handlerton(thd)
+    thd         current thread
+  
+  RETURN
+    pointer to handlerton
+*/
+
+handlerton *ha_default_handlerton(THD *thd)
 {
-  show_table_alias_st *table_alias;
+  return (thd->variables.table_type != NULL) ?
+          thd->variables.table_type :
+          (global_system_variables.table_type != NULL ?
+           global_system_variables.table_type : &myisam_hton);
+}
+
+
+/*
+  Return the storage engine handlerton for the supplied name
+  
+  SYNOPSIS
+    ha_resolve_by_name(thd, name)
+    thd         current thread
+    name        name of storage engine
+  
+  RETURN
+    pointer to handlerton
+*/
+
+handlerton *ha_resolve_by_name(THD *thd, const LEX_STRING *name)
+{
+  const LEX_STRING *table_alias;
   st_plugin_int *plugin;
 
-  if (thd && !my_strnncoll(&my_charset_latin1,
+redo:
+  /* my_strnncoll is a macro and gcc doesn't do early expansion of macro */
+  if (thd && !my_charset_latin1.coll->strnncoll(&my_charset_latin1,
                            (const uchar *)name->str, name->length,
-                           (const uchar *)"DEFAULT", 7))
-    return ha_resolve_by_legacy_type(thd, DB_TYPE_DEFAULT);
+                           (const uchar *)STRING_WITH_LEN("DEFAULT"), 0))
+    return ha_default_handlerton(thd);
 
   if ((plugin= plugin_lock(name, MYSQL_STORAGE_ENGINE_PLUGIN)))
   {
@@ -111,13 +149,15 @@
   /*
     We check for the historical aliases.
   */
-  for (table_alias= sys_table_aliases; table_alias->type; table_alias++)
+  for (table_alias= sys_table_aliases; table_alias->str; table_alias+= 2)
   {
     if (!my_strnncoll(&my_charset_latin1,
                       (const uchar *)name->str, name->length,
-                      (const uchar *)table_alias->alias,
-                      strlen(table_alias->alias)))
-      return ha_resolve_by_legacy_type(thd, table_alias->type);
+                      (const uchar *)table_alias->str, table_alias->length))
+    {
+      name= table_alias + 1;
+      goto redo;
+    }
   }
 
   return NULL;
@@ -126,37 +166,32 @@
 
 const char *ha_get_storage_engine(enum legacy_db_type db_type)
 {
-  switch (db_type)
-  {
+  switch (db_type) {
   case DB_TYPE_DEFAULT:
     return "DEFAULT";
-  case DB_TYPE_UNKNOWN:
-    return "UNKNOWN";
   default:
     if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT &&
         installed_htons[db_type])
       return hton2plugin[installed_htons[db_type]->slot]->name.str;
-      return "*NONE*";
+    /* fall through */
+  case DB_TYPE_UNKNOWN:
+    return "UNKNOWN";
   }
 }
 
 
-static handler *create_default(TABLE_SHARE *table)
+static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root)
 {
-  handlerton *hton=ha_resolve_by_legacy_type(current_thd, DB_TYPE_DEFAULT);
-  return (hton && hton->create) ? hton->create(table) : NULL;
+  handlerton *hton= ha_default_handlerton(current_thd);
+  return (hton && hton->create) ? hton->create(table, mem_root) : NULL;
 }
 
 
 handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
 {
-  switch (db_type)
-  {
+  switch (db_type) {
   case DB_TYPE_DEFAULT:
-    return (thd->variables.table_type != NULL) ?
-            thd->variables.table_type :
-            (global_system_variables.table_type != NULL ?
-             global_system_variables.table_type : &myisam_hton);
+    return ha_default_handlerton(thd);
   case DB_TYPE_UNKNOWN:
     return NULL;
   default:
@@ -197,43 +232,30 @@
     break;
   }
 
-  return ha_resolve_by_legacy_type(thd, DB_TYPE_DEFAULT);  
+  return ha_default_handlerton(thd);
 } /* ha_checktype */
 
 
 handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
                          handlerton *db_type)
 {
-  handler *file= NULL;
-  /*
-    handlers are allocated with new in the handlerton create() function
-    we need to set the thd mem_root for these to be allocated correctly
-  */
-  THD *thd= current_thd;
-  MEM_ROOT *thd_save_mem_root= thd->mem_root;
-  thd->mem_root= alloc;
-
-  if (db_type != NULL && db_type->state == SHOW_OPTION_YES && db_type->create)
-    file= db_type->create(share);
-
-  thd->mem_root= thd_save_mem_root;
+  handler *file;
+  DBUG_ENTER("get_new_handler");
+  DBUG_PRINT("enter", ("alloc: 0x%lx", (long) alloc));
 
-  if (!file)
-  {
-    handlerton *def= current_thd->variables.table_type;
-    /* Try first with 'default table type' */
-    if (db_type != def)
-      return get_new_handler(share, alloc, def);
-  }
-  if (file)
+  if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create)
   {
-    if (file->ha_initialise())
-    {
-      delete file;
-      file=0;
-    }
+    if ((file= db_type->create(share, alloc)))
+      file->init();
+    DBUG_RETURN(file);
   }
-  return file;
+  /*
+    Try the default table type
+    Here the call to current_thd() is ok as we call this function a lot of
+    times but we enter this branch very seldom.
+  */
+  DBUG_RETURN(get_new_handler(share, alloc,
+                              current_thd->variables.table_type));
 }
 
 
@@ -244,11 +266,13 @@
   DBUG_ENTER("get_ha_partition");
   if ((partition= new ha_partition(part_info)))
   {
-    if (partition->ha_initialise())
+    if (partition->initialise_partition(current_thd->mem_root))
     {
       delete partition;
       partition= 0;
     }
+    else
+      partition->init();
   }
   else
   {
@@ -1335,7 +1359,7 @@
       ! (file=get_new_handler(&dummy_share, thd->mem_root, table_type)))
     DBUG_RETURN(ENOENT);
 
-  if (lower_case_table_names == 2 && !(file->table_flags() & HA_FILE_BASED))
+  if (lower_case_table_names == 2 && !(file->ha_table_flags() & HA_FILE_BASED))
   {
     /* Ensure that table handler get path in lower case */
     strmov(tmp_path, path);
@@ -1418,6 +1442,7 @@
 
   table= table_arg;
   DBUG_ASSERT(table->s == table_share);
+  DBUG_ASSERT(alloc_root_inited(&table->mem_root));
 
   if ((error=open(name,mode,test_if_locked)))
   {
@@ -1439,106 +1464,23 @@
       table->db_stat|=HA_READ_ONLY;
     (void) extra(HA_EXTRA_NO_READCHECK);	// Not needed in SQL
 
-    DBUG_ASSERT(alloc_root_inited(&table->mem_root));
-
     if (!(ref= (byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2)))
     {
       close();
       error=HA_ERR_OUT_OF_MEM;
     }
     else
-      dupp_ref=ref+ALIGN_SIZE(ref_length);
-
-    if (ha_allocate_read_write_set(table->s->fields))
-      error= 1;
+      dup_ref=ref+ALIGN_SIZE(ref_length);
+    cached_table_flags= table_flags();
   }
   DBUG_RETURN(error);
 }
 
 
-int handler::ha_initialise()
-{
-  DBUG_ENTER("ha_initialise");
-  DBUG_RETURN(FALSE);
-}
-
-
-/*
-  Initalize bit maps for used fields
-
-  Called from open_table_from_share()
-*/
-
-int handler::ha_allocate_read_write_set(ulong no_fields)
-{
-  uint bitmap_size= bitmap_buffer_size(no_fields+1);
-  uint32 *read_buf, *write_buf;
-  DBUG_ENTER("ha_allocate_read_write_set");
-  DBUG_PRINT("enter", ("no_fields = %d", no_fields));
-
-  if (!multi_alloc_root(&table->mem_root,
-                        &read_set, sizeof(MY_BITMAP),
-                        &write_set, sizeof(MY_BITMAP),
-                        &read_buf, bitmap_size,
-                        &write_buf, bitmap_size,
-                        NullS))
-  {
-    DBUG_RETURN(TRUE);
-  }
-  bitmap_init(read_set, read_buf, no_fields+1, FALSE);
-  bitmap_init(write_set, write_buf, no_fields+1, FALSE);
-  table->read_set= read_set;
-  table->write_set= write_set;
-  ha_clear_all_set();
-  DBUG_RETURN(FALSE);
-}
-
-void handler::ha_clear_all_set()
-{
-  DBUG_ENTER("ha_clear_all_set");
-  bitmap_clear_all(read_set);
-  bitmap_clear_all(write_set);
-  bitmap_set_bit(read_set, 0);
-  bitmap_set_bit(write_set, 0);
-  DBUG_VOID_RETURN;
-}
-
-int handler::ha_retrieve_all_cols()
-{
-  DBUG_ENTER("handler::ha_retrieve_all_cols");
-  bitmap_set_all(read_set);
-  DBUG_RETURN(0);
-}
-
-int handler::ha_retrieve_all_pk()
-{
-  DBUG_ENTER("ha_retrieve_all_pk");
-  ha_set_primary_key_in_read_set();
-  DBUG_RETURN(0);
-}
-
-void handler::ha_set_primary_key_in_read_set()
-{
-  ulong prim_key= table->s->primary_key;
-  DBUG_ENTER("handler::ha_set_primary_key_in_read_set");
-  DBUG_PRINT("info", ("Primary key = %d", prim_key));
-  if (prim_key != MAX_KEY)
-  {
-    KEY_PART_INFO *key_part= table->key_info[prim_key].key_part;
-    KEY_PART_INFO *key_part_end= key_part +
-              table->key_info[prim_key].key_parts;
-    for (;key_part != key_part_end; ++key_part)
-      ha_set_bit_in_read_set(key_part->fieldnr);
-  }
-  DBUG_VOID_RETURN;
-}
-
-
-
 /*
   Read first row (only) from a table
   This is never called for InnoDB or BDB tables, as these table types
-  has the HA_NOT_EXACT_COUNT set.
+  has the HA_STATS_RECORDS_IS_EXACT set.
 */
 
 int handler::read_first_row(byte * buf, uint primary_key)
@@ -1554,7 +1496,7 @@
     scanning the table.
     TODO remove the test for HA_READ_ORDER
   */
-  if (deleted < 10 || primary_key >= MAX_KEY ||
+  if (stats.deleted < 10 || primary_key >= MAX_KEY ||
       !(index_flags(primary_key, 0, 0) & HA_READ_ORDER))
   {
     (void) ha_rnd_init(1);
@@ -1572,7 +1514,10 @@
 }
 
 /*
-  Generate the next auto-increment number based on increment and offset
+  Generate the next auto-increment number based on increment and offset:
+  computes the lowest number
+  - strictly greater than "nr"
+  - of the form: auto_increment_offset + N * auto_increment_increment
 
   In most cases increment= offset= 1, in which case we get:
   1,2,3,4,5,...
@@ -1581,8 +1526,10 @@
 */
 
 inline ulonglong
-next_insert_id(ulonglong nr,struct system_variables *variables)
+compute_next_insert_id(ulonglong nr,struct system_variables *variables)
 {
+  if (variables->auto_increment_increment == 1)
+    return (nr+1); // optimization of the formula below
   nr= (((nr+ variables->auto_increment_increment -
          variables->auto_increment_offset)) /
        (ulonglong) variables->auto_increment_increment);
@@ -1591,11 +1538,63 @@
 }
 
 
+void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr)
+{
+  /*
+    If we have set THD::next_insert_id previously and plan to insert an
+    explicitely-specified value larger than this, we need to increase
+    THD::next_insert_id to be greater than the explicit value.
+  */
+  if ((next_insert_id > 0) && (nr >= next_insert_id))
+    set_next_insert_id(compute_next_insert_id(nr, &table->in_use->variables));
+}
+
+
+/*
+  Computes the largest number X:
+  - smaller than or equal to "nr"
+  - of the form: auto_increment_offset + N * auto_increment_increment
+  where N>=0.
+
+  SYNOPSIS
+    prev_insert_id
+      nr            Number to "round down"
+      variables     variables struct containing auto_increment_increment and
+                    auto_increment_offset
+
+  RETURN
+    The number X if it exists, "nr" otherwise.
+*/
+
+inline ulonglong
+prev_insert_id(ulonglong nr, struct system_variables *variables)
+{
+  if (unlikely(nr < variables->auto_increment_offset))
+  {
+    /*
+      There's nothing good we can do here. That is a pathological case, where
+      the offset is larger than the column's max possible value, i.e. not even
+      the first sequence value may be inserted. User will receive warning.
+    */
+    DBUG_PRINT("info",("auto_increment: nr: %lu cannot honour "
+                       "auto_increment_offset: %lu",
+                       nr, variables->auto_increment_offset));
+    return nr;
+  }
+  if (variables->auto_increment_increment == 1)
+    return nr; // optimization of the formula below
+  nr= (((nr - variables->auto_increment_offset)) /
+       (ulonglong) variables->auto_increment_increment);
+  return (nr * (ulonglong) variables->auto_increment_increment +
+          variables->auto_increment_offset);
+}
+
+
 /*
   Update the auto_increment field if necessary
 
   SYNOPSIS
-     update_auto_increment()
+    update_auto_increment()
 
   RETURN
     0	ok
@@ -1604,7 +1603,7 @@
 
   IMPLEMENTATION
 
-    Updates columns with type NEXT_NUMBER if:
+    Updates the record's Field of type NEXT_NUMBER if:
 
   - If column value is set to NULL (in which case
     auto_increment_field_not_null is 0)
@@ -1612,24 +1611,31 @@
     set. In the future we will only set NEXT_NUMBER fields if one sets them
     to NULL (or they are not included in the insert list).
 
-
-  There are two different cases when the above is true:
-
-  - thd->next_insert_id == 0  (This is the normal case)
-    In this case we set the set the column for the first row to the value
-    next_insert_id(get_auto_increment(column))) which is normally
-    max-used-column-value +1.
-
-    We call get_auto_increment() only for the first row in a multi-row
-    statement. For the following rows we generate new numbers based on the
-    last used number.
-
-  - thd->next_insert_id != 0.  This happens when we have read a statement
-    from the binary log or when one has used SET LAST_INSERT_ID=#.
-
-    In this case we will set the column to the value of next_insert_id.
-    The next row will be given the id
-    next_insert_id(next_insert_id)
+    In those cases, we check if the currently reserved interval still has
+    values we have not used. If yes, we pick the smallest one and use it.
+    Otherwise:
+
+  - If a list of intervals has been provided to the statement via SET
+    INSERT_ID or via an Intvar_log_event (in a replication slave), we pick the
+    first unused interval from this list, consider it as reserved.
+
+  - Otherwise we set the column for the first row to the value
+    next_insert_id(get_auto_increment(column))) which is usually
+    max-used-column-value+1.
+    We call get_auto_increment() for the first row in a multi-row
+    statement. get_auto_increment() will tell us the interval of values it
+    reserved for us.
+
+  - In both cases, for the following rows we use those reserved values without
+    calling the handler again (we just progress in the interval, computing
+    each new value from the previous one). Until we have exhausted them, then
+    we either take the next provided interval or call get_auto_increment()
+    again to reserve a new interval.
+
+  - In both cases, the reserved intervals are remembered in
+    thd->auto_inc_intervals_in_cur_stmt_for_binlog if statement-based
+    binlogging; the last reserved interval is remembered in
+    auto_inc_interval_for_cur_row.
 
     The idea is that generated auto_increment values are predictable and
     independent of the column values in the table.  This is needed to be
@@ -1640,12 +1646,31 @@
     inserts a column with a higher value than the last used one, we will
     start counting from the inserted value.
 
-    thd->next_insert_id is cleared after it's been used for a statement.
+    This function's "outputs" are: the table's auto_increment field is filled
+    with a value, thd->next_insert_id is filled with the value to use for the
+    next row, if a value was autogenerated for the current row it is stored in
+    thd->insert_id_for_cur_row, if get_auto_increment() was called
+    thd->auto_inc_interval_for_cur_row is modified, if that interval is not
+    present in thd->auto_inc_intervals_in_cur_stmt_for_binlog it is added to
+    this list.
+
+   TODO
+
+    Replace all references to "next number" or NEXT_NUMBER to
+    "auto_increment", everywhere (see below: there is
+    table->auto_increment_field_not_null, and there also exists
+    table->next_number_field, it's not consistent).
+
 */
 
+#define AUTO_INC_DEFAULT_NB_ROWS 1 // Some prefer 1024 here
+#define AUTO_INC_DEFAULT_NB_MAX_BITS 16
+#define AUTO_INC_DEFAULT_NB_MAX ((1 << AUTO_INC_DEFAULT_NB_MAX_BITS) - 1)
+
 bool handler::update_auto_increment()
 {
-  ulonglong nr;
+  ulonglong nr, nb_reserved_values;
+  bool append= FALSE;
   THD *thd= table->in_use;
   struct system_variables *variables= &thd->variables;
   bool auto_increment_field_not_null;
@@ -1653,105 +1678,218 @@
   DBUG_ENTER("handler::update_auto_increment");
 
   /*
-    We must save the previous value to be able to restore it if the
-    row was not inserted
+    next_insert_id is a "cursor" into the reserved interval, it may go greater
+    than the interval, but not smaller.
   */
-  thd->prev_insert_id= thd->next_insert_id;
+  DBUG_ASSERT(next_insert_id >= auto_inc_interval_for_cur_row.minimum());
   auto_increment_field_not_null= table->auto_increment_field_not_null;
-  table->auto_increment_field_not_null= FALSE;
+  table->auto_increment_field_not_null= FALSE; // to reset for next row
 
   if ((nr= table->next_number_field->val_int()) != 0 ||
       auto_increment_field_not_null &&
       thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
   {
-    /* Clear flag for next row */
-    /* Mark that we didn't generate a new value **/
-    auto_increment_column_changed=0;
-
-    /* Update next_insert_id if we have already generated a value */
-    if (thd->clear_next_insert_id && nr >= thd->next_insert_id)
-    {
-      if (variables->auto_increment_increment != 1)
-        nr= next_insert_id(nr, variables);
-      else
-        nr++;
-      thd->next_insert_id= nr;
-      DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr));
-    }
+    /*
+      Update next_insert_id if we had already generated a value in this
+      statement (case of INSERT VALUES(null),(3763),(null):
+      the last NULL needs to insert 3764, not the value of the first NULL plus
+      1).
+    */
+    adjust_next_insert_id_after_explicit_value(nr);
+    insert_id_for_cur_row= 0; // didn't generate anything
     DBUG_RETURN(0);
   }
-  if (!(nr= thd->next_insert_id))
-  {
-    if ((nr= get_auto_increment()) == ~(ulonglong) 0)
-      result= 1;                                // Mark failure
 
-    if (variables->auto_increment_increment != 1)
-      nr= next_insert_id(nr-1, variables);
-    /*
-      Update next row based on the found value. This way we don't have to
-      call the handler for every generated auto-increment value on a
-      multi-row statement
-    */
-    thd->next_insert_id= nr;
+  if ((nr= next_insert_id) >= auto_inc_interval_for_cur_row.maximum())
+  {
+    /* next_insert_id is beyond what is reserved, so we reserve more. */
+    const Discrete_interval *forced=
+      thd->auto_inc_intervals_forced.get_next();
+    if (forced != NULL)
+    {
+      nr= forced->minimum();
+      nb_reserved_values= forced->values();
+    }
+    else
+    {
+      /*
+        handler::estimation_rows_to_insert was set by
+        handler::ha_start_bulk_insert(); if 0 it means "unknown".
+      */
+      uint nb_already_reserved_intervals=
+        thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements();
+      ulonglong nb_desired_values;
+      /*
+        If an estimation was given to the engine:
+        - use it.
+        - if we already reserved numbers, it means the estimation was
+        not accurate, then we'll reserve 2*AUTO_INC_DEFAULT_NB_ROWS the 2nd
+        time, twice that the 3rd time etc.
+        If no estimation was given, use those increasing defaults from the
+        start, starting from AUTO_INC_DEFAULT_NB_ROWS.
+        Don't go beyond a max to not reserve "way too much" (because
+        reservation means potentially losing unused values).
+      */
+      if (nb_already_reserved_intervals == 0 &&
+          (estimation_rows_to_insert > 0))
+        nb_desired_values= estimation_rows_to_insert;
+      else /* go with the increasing defaults */
+      {
+        /* avoid overflow in formula, with this if() */
+        if (nb_already_reserved_intervals <= AUTO_INC_DEFAULT_NB_MAX_BITS)
+        {
+          nb_desired_values= AUTO_INC_DEFAULT_NB_ROWS * 
+            (1 << nb_already_reserved_intervals);
+          set_if_smaller(nb_desired_values, AUTO_INC_DEFAULT_NB_MAX);
+        }
+        else
+          nb_desired_values= AUTO_INC_DEFAULT_NB_MAX;
+      }
+      /* This call ignores all its parameters but nr, currently */
+      get_auto_increment(variables->auto_increment_offset,
+                         variables->auto_increment_increment,
+                         nb_desired_values, &nr,
+                         &nb_reserved_values);
+      if (nr == ~(ulonglong) 0)
+        result= 1;                                // Mark failure
+      
+      /*
+        That rounding below should not be needed when all engines actually
+        respect offset and increment in get_auto_increment(). But they don't
+        so we still do it. Wonder if for the not-first-in-index we should do
+        it. Hope that this rounding didn't push us out of the interval; even
+        if it did we cannot do anything about it (calling the engine again
+        will not help as we inserted no row).
+      */
+      nr= compute_next_insert_id(nr-1, variables);
+    }
+    
+    if (table->s->next_number_key_offset == 0)
+    {
+      /* We must defer the appending until "nr" has been possibly truncated */
+      append= TRUE;
+    }
+    else
+    {
+      /*
+        For such auto_increment there is no notion of interval, just a
+        singleton. The interval is not even stored in
+        thd->auto_inc_interval_for_cur_row, so we are sure to call the engine
+        for next row.
+      */
+      DBUG_PRINT("info",("auto_increment: special not-first-in-index"));
+    }
   }
 
   DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr));
 
-  /* Mark that we should clear next_insert_id before next stmt */
-  thd->clear_next_insert_id= 1;
-
-  if (!table->next_number_field->store((longlong) nr, TRUE))
-    thd->insert_id((ulonglong) nr);
-  else
-    thd->insert_id(table->next_number_field->val_int());
-
-  /*
-    We can't set next_insert_id if the auto-increment key is not the
-    first key part, as there is no guarantee that the first parts will be in
-    sequence
-  */
-  if (!table->s->next_number_key_offset)
+  if (unlikely(table->next_number_field->store((longlong) nr, TRUE)))
   {
     /*
-      Set next insert id to point to next auto-increment value to be able to
-      handle multi-row statements
-      This works even if auto_increment_increment > 1
+      field refused this value (overflow) and truncated it, use the result of
+      the truncation (which is going to be inserted); however we try to
+      decrease it to honour auto_increment_* variables.
+      That will shift the left bound of the reserved interval, we don't
+      bother shifting the right bound (anyway any other value from this
+      interval will cause a duplicate key).
     */
-    thd->next_insert_id= next_insert_id(nr, variables);
+    nr= prev_insert_id(table->next_number_field->val_int(), variables);
+    if (unlikely(table->next_number_field->store((longlong) nr, TRUE)))
+      nr= table->next_number_field->val_int();
+  }
+  if (append)
+  {
+    auto_inc_interval_for_cur_row.replace(nr, nb_reserved_values,
+                                          variables->auto_increment_increment);
+    /* Row-based replication does not need to store intervals in binlog */
+    if (!thd->current_stmt_binlog_row_based)
+      result= result ||
+        thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(),
+                                                              auto_inc_interval_for_cur_row.values(),
+                                                              variables->auto_increment_increment);
   }
-  else
-    thd->next_insert_id= 0;
 
-  /* Mark that we generated a new value */
-  auto_increment_column_changed=1;
+  /*
+    Record this autogenerated value. If the caller then
+    succeeds to insert this value, it will call
+    record_first_successful_insert_id_in_cur_stmt()
+    which will set first_successful_insert_id_in_cur_stmt if it's not
+    already set.
+  */
+  insert_id_for_cur_row= nr;
+  /*
+    Set next insert id to point to next auto-increment value to be able to
+    handle multi-row statements.
+  */
+  set_next_insert_id(compute_next_insert_id(nr, variables));
+
   DBUG_RETURN(result);
 }
 
+
 /*
-  restore_auto_increment
+  MySQL signal that it changed the column bitmap
+
+  USAGE
+    This is for handlers that needs to setup their own column bitmaps.
+    Normally the handler should set up their own column bitmaps in
+    index_init() or rnd_init() and in any column_bitmaps_signal() call after
+    this.
 
-  In case of error on write, we restore the last used next_insert_id value
-  because the previous value was not used.
+    The handler is allowd to do changes to the bitmap after a index_init or
+    rnd_init() call is made as after this, MySQL will not use the bitmap
+    for any program logic checking.
 */
 
-void handler::restore_auto_increment()
+void handler::column_bitmaps_signal()
 {
-  THD *thd= table->in_use;
-  if (thd->next_insert_id)
-    thd->next_insert_id= thd->prev_insert_id;
+  DBUG_ENTER("column_bitmaps_signal");
+  DBUG_PRINT("info", ("read_set: 0x%lx  write_set: 0x%lx", table->read_set,
+                      table->write_set));
+  DBUG_VOID_RETURN;
 }
 
 
-ulonglong handler::get_auto_increment()
+/*
+  Reserves an interval of auto_increment values from the handler.
+
+  SYNOPSIS
+    get_auto_increment()
+    offset              
+    increment
+    nb_desired_values   how many values we want
+    first_value         (OUT) the first value reserved by the handler
+    nb_reserved_values  (OUT) how many values the handler reserved
+
+  offset and increment means that we want values to be of the form
+  offset + N * increment, where N>=0 is integer.
+  If the function sets *first_value to ~(ulonglong)0 it means an error.
+  If the function sets *nb_reserved_values to ULONGLONG_MAX it means it has
+  reserved to "positive infinite".
+*/
+
+void handler::get_auto_increment(ulonglong offset, ulonglong increment,
+                                 ulonglong nb_desired_values,
+                                 ulonglong *first_value,
+                                 ulonglong *nb_reserved_values)
 {
   ulonglong nr;
   int error;
 
   (void) extra(HA_EXTRA_KEYREAD);
+  table->mark_columns_used_by_index_no_reset(table->s->next_number_index,
+                                        table->read_set);
+  column_bitmaps_signal();
   index_init(table->s->next_number_index, 1);
   if (!table->s->next_number_key_offset)
   {						// Autoincrement at key-start
     error=index_last(table->record[1]);
+    /*
+      MySQL implicitely assumes such method does locking (as MySQL decides to
+      use nr+increment without checking again with the handler, in
+      handler::update_auto_increment()), so reserves to infinite.
+    */
+    *nb_reserved_values= ULONGLONG_MAX;
   }
   else
   {
@@ -1761,6 +1899,13 @@
              table->s->next_number_key_offset);
     error= index_read(table->record[1], key, table->s->next_number_key_offset,
                       HA_READ_PREFIX_LAST);
+    /*
+      MySQL needs to call us for next row: assume we are inserting ("a",null)
+      here, we return 3, and next this statement will want to insert
+      ("b",null): there is no reason why ("b",3+1) would be the good row to
+      insert: maybe it already exists, maybe 3+1 is too large...
+    */
+    *nb_reserved_values= 1;
   }
 
   if (error)
@@ -1770,11 +1915,28 @@
          val_int_offset(table->s->rec_buff_length)+1);
   index_end();
   (void) extra(HA_EXTRA_NO_KEYREAD);
-  return nr;
+  *first_value= nr;
+}
+
+
+void handler::ha_release_auto_increment()
+{
+  release_auto_increment();
+  insert_id_for_cur_row= 0;
+  auto_inc_interval_for_cur_row.replace(0, 0, 0);
+  if (next_insert_id > 0)
+  {
+    next_insert_id= 0;
+    /*
+      this statement used forced auto_increment values if there were some,
+      wipe them away for other statements.
+    */
+    table->in_use->auto_inc_intervals_forced.empty();
+  }
 }
 
 
-void handler::print_keydupp_error(uint key_nr, const char *msg)
+void handler::print_keydup_error(uint key_nr, const char *msg)
 {
   /* Write the duplicated key in the error message */
   char key[MAX_KEY_LENGTH];
@@ -1831,7 +1993,7 @@
     uint key_nr=get_dup_key(error);
     if ((int) key_nr >= 0)
     {
-      print_keydupp_error(key_nr, ER(ER_DUP_ENTRY));
+      print_keydup_error(key_nr, ER(ER_DUP_ENTRY));
       DBUG_VOID_RETURN;
     }
     textno=ER_DUP_KEY;
@@ -1842,12 +2004,14 @@
     uint key_nr= get_dup_key(error);
     if ((int) key_nr >= 0)
     {
+      uint max_length;
       /* Write the key in the error message */
       char key[MAX_KEY_LENGTH];
       String str(key,sizeof(key),system_charset_info);
       /* Table is opened and defined at this point */
       key_unpack(&str,table,(uint) key_nr);
-      uint max_length= MYSQL_ERRMSG_SIZE-(uint) strlen(ER(ER_FOREIGN_DUPLICATE_KEY));
+      max_length= (MYSQL_ERRMSG_SIZE-
+                   (uint) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
       if (str.length() >= max_length)
       {
         str.length(max_length-4);
@@ -2256,22 +2420,23 @@
 }
 
 
-void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info, uint part_id)
+void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
+                                         uint part_id)
 {
   info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE |
        HA_STATUS_NO_LOCK);
-  stat_info->records= records;
-  stat_info->mean_rec_length= mean_rec_length;
-  stat_info->data_file_length= data_file_length;
-  stat_info->max_data_file_length= max_data_file_length;
-  stat_info->index_file_length= index_file_length;
-  stat_info->delete_length= delete_length;
-  stat_info->create_time= create_time;
-  stat_info->update_time= update_time;
-  stat_info->check_time= check_time;
-  stat_info->check_sum= 0;
+  stat_info->records=              stats.records;
+  stat_info->mean_rec_length=      stats.mean_rec_length;
+  stat_info->data_file_length=     stats.data_file_length;
+  stat_info->max_data_file_length= stats.max_data_file_length;
+  stat_info->index_file_length=    stats.index_file_length;
+  stat_info->delete_length=        stats.delete_length;
+  stat_info->create_time=          stats.create_time;
+  stat_info->update_time=          stats.update_time;
+  stat_info->check_time=           stats.check_time;
+  stat_info->check_sum=            0;
   if (table_flags() & (ulong) HA_HAS_CHECKSUM)
-  stat_info->check_sum= checksum();
+    stat_info->check_sum= checksum();
   return;
 }
 
@@ -2281,11 +2446,11 @@
 ****************************************************************************/
 
 /*
-  Initiates table-file and calls apropriate database-creator
+  Initiates table-file and calls appropriate database-creator
 
   NOTES
     We must have a write lock on LOCK_open to be sure no other thread
-    interfers with table
+    interferes with table
     
   RETURN
    0  ok
@@ -2315,7 +2480,7 @@
 
   name= share.path.str;
   if (lower_case_table_names == 2 &&
-      !(table.file->table_flags() & HA_FILE_BASED))
+      !(table.file->ha_table_flags() & HA_FILE_BASED))
   {
     /* Ensure that handler gets name in lower case */
     strmov(name_buff, name);
@@ -2394,7 +2559,7 @@
   create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE;
 
   if (lower_case_table_names == 2 &&
-      !(table.file->table_flags() & HA_FILE_BASED))
+      !(table.file->ha_table_flags() & HA_FILE_BASED))
   {
     /* Ensure that handler gets name in lower case */
     my_casedn_str(files_charset_info, path);
@@ -2529,7 +2694,7 @@
 
 
 /*
-  Call this function in order to give the handler the possiblity 
+  Call this function in order to give the handler the possibility 
   to ask engine if there are any new tables that should be written to disk 
   or any dropped tables that need to be removed from disk
 */
@@ -2744,6 +2909,9 @@
   multi_range_sorted= sorted;
   multi_range_buffer= buffer;
 
+  table->mark_columns_used_by_index_no_reset(active_index, table->read_set);
+  table->column_bitmaps_set(table->read_set, table->write_set);
+
   for (multi_range_curr= ranges, multi_range_end= ranges + range_count;
        multi_range_curr < multi_range_end;
        multi_range_curr++)
@@ -2986,7 +3154,7 @@
   handlerton *hton= (handlerton *)plugin->data;
   handler *file;
   if (hton->state == SHOW_OPTION_YES && hton->create &&
-      (file= hton->create((TABLE_SHARE*) 0)))
+      (file= hton->create((TABLE_SHARE*) 0, current_thd->mem_root)))
   {
     List_iterator_fast<char> it(*found_exts);
     const char **ext, *old_ext;
@@ -3126,7 +3294,7 @@
     char const *name;
   };
 
-  int table_name_compare(void const *a, void const *b)
+  static int table_name_compare(void const *a, void const *b)
   {
     st_table_data const *x = (st_table_data const*) a;
     st_table_data const *y = (st_table_data const*) b;
@@ -3157,104 +3325,177 @@
     DBUG_ASSERT(table->s->cached_row_logging_check == 0 ||
                 table->s->cached_row_logging_check == 1);
 
-    return
-      thd->current_stmt_binlog_row_based &&
-      thd && (thd->options & OPTION_BIN_LOG) &&
-      mysql_bin_log.is_open() &&
-      table->s->cached_row_logging_check;
+    return (thd->current_stmt_binlog_row_based &&
+            (thd->options & OPTION_BIN_LOG) &&
+            mysql_bin_log.is_open() &&
+            table->s->cached_row_logging_check);
   }
 }
 
-template<class RowsEventT> int binlog_log_row(TABLE* table,
-                                              const byte *before_record,
-                                              const byte *after_record)
+/*
+   Write table maps for all (manually or automatically) locked tables
+   to the binary log.
+
+   SYNOPSIS
+     write_locked_table_maps()
+       thd     Pointer to THD structure
+
+   DESCRIPTION
+       This function will generate and write table maps for all tables
+       that are locked by the thread 'thd'.  Either manually locked
+       (stored in THD::locked_tables) and automatically locked (stored
+       in THD::lock) are considered.
+   
+   RETURN VALUE
+       0   All OK
+       1   Failed to write all table maps
+
+   SEE ALSO
+       THD::lock
+       THD::locked_tables
+ */
+namespace
 {
-  if (table->file->is_injective())
-    return 0;
-  bool error= 0;
-  THD *const thd= current_thd;
+  int write_locked_table_maps(THD *thd)
+  {
+    DBUG_ENTER("write_locked_table_maps");
+    DBUG_PRINT("enter", ("thd=%p, thd->lock=%p, thd->locked_tables=%p, thd->extra_lock",
+                         thd, thd->lock, thd->locked_tables, thd->extra_lock));
 
-  if (check_table_binlog_row_based(thd, table))
+    if (thd->get_binlog_table_maps() == 0)
+    {
+      MYSQL_LOCK *locks[3];
+      locks[0]= thd->extra_lock;
+      locks[1]= thd->lock;
+      locks[2]= thd->locked_tables;
+      for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
+      {
+        MYSQL_LOCK const *const lock= locks[i];
+        if (lock == NULL)
+          continue;
+
+        TABLE **const end_ptr= lock->table + lock->table_count;
+        for (TABLE **table_ptr= lock->table ; 
+             table_ptr != end_ptr ;
+             ++table_ptr)
+        {
+          TABLE *const table= *table_ptr;
+          DBUG_PRINT("info", ("Checking table %s", table->s->table_name));
+          if (table->current_lock == F_WRLCK &&
+              check_table_binlog_row_based(thd, table))
+          {
+            int const has_trans= table->file->has_transactions();
+            int const error= thd->binlog_write_table_map(table, has_trans);
+            /*
+              If an error occurs, it is the responsibility of the caller to
+              roll back the transaction.
+            */
+            if (unlikely(error))
+              DBUG_RETURN(1);
+          }
+        }
+      }
+    }
+    DBUG_RETURN(0);
+  }
+
+  template<class RowsEventT> int
+  binlog_log_row(TABLE* table,
+                 const byte *before_record,
+                 const byte *after_record)
   {
-    MY_BITMAP cols;
-    /* Potential buffer on the stack for the bitmap */
-    uint32 bitbuf[BITMAP_STACKBUF_SIZE/sizeof(uint32)];
-    uint n_fields= table->s->fields;
-    my_bool use_bitbuf= n_fields <= sizeof(bitbuf)*8;
-    if (likely(!(error= bitmap_init(&cols,
-                                    use_bitbuf ? bitbuf : NULL,
-                                    (n_fields + 7) & ~7UL,
-                                    false))))
+    if (table->file->ha_table_flags() & HA_HAS_OWN_BINLOGGING)
+      return 0;
+    bool error= 0;
+    THD *const thd= table->in_use;
+
+    if (check_table_binlog_row_based(thd, table))
     {
-      bitmap_set_all(&cols);
-      error=
-        RowsEventT::binlog_row_logging_function(thd, table,
-                                                table->file->has_transactions(),
-                                                &cols, table->s->fields,
-                                                before_record, after_record);
-      if (!use_bitbuf)
-        bitmap_free(&cols);
+      MY_BITMAP cols;
+      /* Potential buffer on the stack for the bitmap */
+      uint32 bitbuf[BITMAP_STACKBUF_SIZE/sizeof(uint32)];
+      uint n_fields= table->s->fields;
+      my_bool use_bitbuf= n_fields <= sizeof(bitbuf)*8;
+
+      /*
+        If there are no table maps written to the binary log, this is
+        the first row handled in this statement. In that case, we need
+        to write table maps for all locked tables to the binary log.
+      */
+      if (likely(!(error= bitmap_init(&cols,
+                                      use_bitbuf ? bitbuf : NULL,
+                                      (n_fields + 7) & ~7UL,
+                                      FALSE))))
+      {
+        bitmap_set_all(&cols);
+        if (likely(!(error= write_locked_table_maps(thd))))
+        {
+          error=
+            RowsEventT::binlog_row_logging_function(thd, table,
+                                                    table->file->
+                                                    has_transactions(),
+                                                    &cols, table->s->fields,
+                                                    before_record,
+                                                    after_record);
+        }
+        if (!use_bitbuf)
+          bitmap_free(&cols);
+      }
     }
+    return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
   }
-  return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
-}
 
+  /*
+    Instantiate the versions we need for the above template function,
+    because we have -fno-implicit-template as compiling option.
+  */
 
-/*
-  Instantiate the versions we need for the above template function, because we
-  have -fno-implicit-template as compiling option.
-*/
+  template int
+  binlog_log_row<Write_rows_log_event>(TABLE *, const byte *, const byte *);
+
+  template int
+  binlog_log_row<Delete_rows_log_event>(TABLE *, const byte *, const byte *);
 
-template int binlog_log_row<Write_rows_log_event>(TABLE *, const byte *, const byte *);
-template int binlog_log_row<Delete_rows_log_event>(TABLE *, const byte *, const byte *);
-template int binlog_log_row<Update_rows_log_event>(TABLE *, const byte *, const byte *);
+  template int
+  binlog_log_row<Update_rows_log_event>(TABLE *, const byte *, const byte *);
+}
 
 #endif /* HAVE_ROW_BASED_REPLICATION */
 
 int handler::ha_external_lock(THD *thd, int lock_type)
 {
   DBUG_ENTER("handler::ha_external_lock");
-  int error;
-  if (unlikely(error= external_lock(thd, lock_type)))
-    DBUG_RETURN(error);
-#ifdef HAVE_ROW_BASED_REPLICATION
-  if (table->file->is_injective())
-    DBUG_RETURN(0);
-
   /*
-    There is a number of statements that are logged statement-based
-    but call external lock. For these, we do not need to generate a
-    table map.
-
-    TODO: The need for this switch is an indication that the model for
-    locking combined with row-based replication needs to be looked
-    over. Ideally, no such special handling should be needed.
-   */
-  switch (thd->lex->sql_command) {
-  case SQLCOM_TRUNCATE:
-  case SQLCOM_ALTER_TABLE:
-  case SQLCOM_OPTIMIZE:
-  case SQLCOM_REPAIR:
-    DBUG_RETURN(0);
-  default:
-    break;
-  }
+    Whether this is lock or unlock, this should be true, and is to verify that
+    if get_auto_increment() was called (thus may have reserved intervals or
+    taken a table lock), ha_release_auto_increment() was too.
+  */
+  DBUG_ASSERT(next_insert_id == 0);
+  DBUG_RETURN(external_lock(thd, lock_type));
+}
 
-  /*
-    If we are locking a table for writing, we generate a table map.
-    For all other kinds of locks, we don't do anything.
-   */
-  if (lock_type == F_WRLCK && check_table_binlog_row_based(thd, table))
-  {
-    int const has_trans= table->file->has_transactions();
-    error= thd->binlog_write_table_map(table, has_trans);
-    if (unlikely(error))
-      DBUG_RETURN(error);
-  }
-#endif
-  DBUG_RETURN(0);
+
+/*
+  Check handler usage and reset state of file to after 'open'
+*/
+
+int handler::ha_reset()
+{
+  DBUG_ENTER("ha_reset");
+  /* Check that we have called all proper delallocation functions */
+  DBUG_ASSERT((byte*) table->def_read_set.bitmap +
+              table->s->column_bitmap_size ==
+              (char*) table->def_write_set.bitmap);
+  DBUG_ASSERT(bitmap_is_set_all(&table->s->all_set));
+  DBUG_ASSERT(table->key_read == 0);
+  /* ensure that ha_index_end / ha_rnd_end has been called */
+  DBUG_ASSERT(inited == NONE);
+  /* Free cache used by filesort */
+  free_io_cache(table);
+  DBUG_RETURN(reset());
 }
 
+
 int handler::ha_write_row(byte *buf)
 {
   int error;
@@ -3297,3 +3538,200 @@
 #endif
   return 0;
 }
+
+
+
+/*
+  use_hidden_primary_key() is called in case of an update/delete when
+  (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
+  but we don't have a primary key
+*/
+
+void handler::use_hidden_primary_key()
+{
+  /* fallback to use all columns in the table to identify row */
+  table->use_all_columns();
+}
+
+
+/*
+  Dummy function which accept information about log files which is not need
+  by handlers
+*/
+
+void signal_log_not_needed(struct handlerton, char *log_file)
+{
+  DBUG_ENTER("signal_log_not_needed");
+  DBUG_PRINT("enter", ("logfile '%s'", log_file));
+  DBUG_VOID_RETURN;
+}
+
+
+#ifdef TRANS_LOG_MGM_EXAMPLE_CODE
+/*
+  Example of transaction log management functions based on assumption that logs
+  placed into a directory
+*/
+#include <my_dir.h>
+#include <my_sys.h>
+int example_of_iterator_using_for_logs_cleanup(handlerton *hton)
+{
+  void *buffer;
+  int res= 1;
+  struct handler_iterator iterator;
+  struct handler_log_file_data data;
+
+  if (!hton->create_iterator)
+    return 1; /* iterator creator is not supported */
+
+  if ((*hton->create_iterator)(HA_TRANSACTLOG_ITERATOR, &iterator) !=
+      HA_ITERATOR_OK)
+  {
+    /* error during creation of log iterator or iterator is not supported */
+    return 1;
+  }
+  while((*iterator.next)(&iterator, (void*)&data) == 0)
+  {
+    printf("%s\n", data.filename.str);
+    if (data.status == HA_LOG_STATUS_FREE &&
+        my_delete(data.filename.str, MYF(MY_WME)))
+      goto err;
+  }
+  res= 0;
+err:
+  (*iterator.destroy)(&iterator);
+  return res;
+}
+
+
+/*
+  Here we should get info from handler where it save logs but here is
+  just example, so we use constant.
+  IMHO FN_ROOTDIR ("/") is safe enough for example, because nobody has
+  rights on it except root and it consist of directories only at lest for
+  *nix (sorry, can't find windows-safe solution here, but it is only example).
+*/
+#define fl_dir FN_ROOTDIR
+
+
+/*
+  Dummy function to return log status should be replaced by function which
+  really detect the log status and check that the file is a log of this
+  handler.
+*/
+
+enum log_status fl_get_log_status(char *log)
+{
+  MY_STAT stat_buff;
+  if (my_stat(log, &stat_buff, MYF(0)))
+    return HA_LOG_STATUS_INUSE;
+  return HA_LOG_STATUS_NOSUCHLOG;
+}
+
+
+struct fl_buff
+{
+  LEX_STRING *names;
+  enum log_status *statuses;
+  uint32 entries;
+  uint32 current;
+};
+
+
+int fl_log_iterator_next(struct handler_iterator *iterator,
+                          void *iterator_object)
+{
+  struct fl_buff *buff= (struct fl_buff *)iterator->buffer;
+  struct handler_log_file_data *data=
+    (struct handler_log_file_data *) iterator_object;
+  if (buff->current >= buff->entries)
+    return 1;
+  data->filename= buff->names[buff->current];
+  data->status= buff->statuses[buff->current];
+  buff->current++;
+  return 0;
+}
+
+
+void fl_log_iterator_destroy(struct handler_iterator *iterator)
+{
+  my_free((gptr)iterator->buffer, MYF(MY_ALLOW_ZERO_PTR));
+}
+
+
+/*
+  returns buffer, to be assigned in handler_iterator struct
+*/
+enum handler_create_iterator_result
+fl_log_iterator_buffer_init(struct handler_iterator *iterator)
+{
+  MY_DIR *dirp;
+  struct fl_buff *buff;
+  char *name_ptr;
+  byte *ptr;
+  FILEINFO *file;
+  uint32 i;
+
+  /* to be able to make my_free without crash in case of error */
+  iterator->buffer= 0;
+
+  if (!(dirp = my_dir(fl_dir, MYF(0))))
+  {
+    return HA_ITERATOR_ERROR;
+  }
+  if ((ptr= (byte*)my_malloc(ALIGN_SIZE(sizeof(fl_buff)) +
+                             ((ALIGN_SIZE(sizeof(LEX_STRING)) +
+                               sizeof(enum log_status) +
+                               + FN_REFLEN) *
+                              (uint) dirp->number_off_files),
+                             MYF(0))) == 0)
+  {
+    return HA_ITERATOR_ERROR;
+  }
+  buff= (struct fl_buff *)ptr;
+  buff->entries= buff->current= 0;
+  ptr= ptr + (ALIGN_SIZE(sizeof(fl_buff)));
+  buff->names= (LEX_STRING*) (ptr);
+  ptr= ptr + ((ALIGN_SIZE(sizeof(LEX_STRING)) *
+               (uint) dirp->number_off_files));
+  buff->statuses= (enum log_status *)(ptr);
+  name_ptr= (char *)(ptr + (sizeof(enum log_status) *
+                            (uint) dirp->number_off_files));
+  for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
+  {
+    enum log_status st;
+    file= dirp->dir_entry + i;
+    if ((file->name[0] == '.' &&
+         ((file->name[1] == '.' && file->name[2] == '\0') ||
+            file->name[1] == '\0')))
+      continue;
+    if ((st= fl_get_log_status(file->name)) == HA_LOG_STATUS_NOSUCHLOG)
+      continue;
+    name_ptr= strxnmov(buff->names[buff->entries].str= name_ptr,
+                       FN_REFLEN, fl_dir, file->name, NullS);
+    buff->names[buff->entries].length= (name_ptr -
+                                        buff->names[buff->entries].str) - 1;
+    buff->statuses[buff->entries]= st;
+    buff->entries++;
+  }
+
+  iterator->buffer= buff;
+  iterator->next= &fl_log_iterator_next;
+  iterator->destroy= &fl_log_iterator_destroy;
+  return HA_ITERATOR_OK;
+}
+
+
+/* An example of a iterator creator */
+enum handler_create_iterator_result
+fl_create_iterator(enum handler_iterator_type type,
+                   struct handler_iterator *iterator)
+{
+  switch(type) {
+  case HA_TRANSACTLOG_ITERATOR:
+    return fl_log_iterator_buffer_init(iterator);
+  default:
+    return HA_ITERATOR_UNSUPPORTED;
+  }
+}
+#endif /*TRANS_LOG_MGM_EXAMPLE_CODE*/

--- 1.177/sql/item.cc	2006-08-06 02:11:48 +10:00
+++ 1.178/sql/item.cc	2006-08-06 02:11:48 +10:00
@@ -61,7 +61,7 @@
 String *
 Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const
 {
-  to->set(val->real, decimals, &my_charset_bin);
+  to->set_real(val->real, decimals, &my_charset_bin);
   return to;
 }
 
@@ -202,7 +202,7 @@
   double nr= val_real();
   if (null_value)
     return 0;					/* purecov: inspected */
-  str->set(nr,decimals, &my_charset_bin);
+  str->set_real(nr,decimals, &my_charset_bin);
   return str;
 }
 
@@ -212,10 +212,7 @@
   longlong nr= val_int();
   if (null_value)
     return 0;
-  if (unsigned_flag)
-    str->set((ulonglong) nr, &my_charset_bin);
-  else
-    str->set(nr, &my_charset_bin);
+  str->set_int(nr, unsigned_flag, &my_charset_bin);
   return str;
 }
 
@@ -551,6 +548,23 @@
 }
 
 
+/*
+  Mark field in read_map
+
+  NOTES
+    This is used by filesort to register used fields in a a temporary
+    column read set or to register used fields in a view
+*/
+
+bool Item_field::register_field_in_read_map(byte *arg)
+{
+  TABLE *table= (TABLE *) arg;
+  if (field->table == table || !table)
+    bitmap_set_bit(field->table->read_set, field->field_index);
+  return 0;
+}
+
+
 bool Item::check_cols(uint c)
 {
   if (c != 1)
@@ -790,14 +804,25 @@
 }
 
 
+/*
+  Save value in field, but don't give any warnings
+
+  NOTES
+   This is used to temporary store and retrieve a value in a column,
+   for example in opt_range to adjust the key value to fit the column.
+*/
+
 int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
 {
   int res;
-  THD *thd= field->table->in_use;
+  TABLE *table= field->table;
+  THD *thd= table->in_use;
   enum_check_fields tmp= thd->count_cuted_fields;
+  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
   thd->count_cuted_fields= CHECK_FIELD_IGNORE;
   res= save_in_field(field, no_conversions);
   thd->count_cuted_fields= tmp;
+  dbug_tmp_restore_column_map(table->write_set, old_map);
   return res;
 }
 
@@ -1318,35 +1343,37 @@
 
 
 static
-void my_coll_agg_error(Item** args, uint count, const char *fname)
+void my_coll_agg_error(Item** args, uint count, const char *fname,
+                       int item_sep)
 {
   if (count == 2)
-    my_coll_agg_error(args[0]->collation, args[1]->collation, fname);
+    my_coll_agg_error(args[0]->collation, args[item_sep]->collation, fname);
   else if (count == 3)
-    my_coll_agg_error(args[0]->collation, args[1]->collation,
-                      args[2]->collation, fname);
+    my_coll_agg_error(args[0]->collation, args[item_sep]->collation,
+                      args[2*item_sep]->collation, fname);
   else
     my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname);
 }
 
 
 bool agg_item_collations(DTCollation &c, const char *fname,
-                         Item **av, uint count, uint flags)
+                         Item **av, uint count, uint flags, int item_sep)
 {
   uint i;
+  Item **arg;
   c.set(av[0]->collation);
-  for (i= 1; i < count; i++)
+  for (i= 1, arg= &av[item_sep]; i < count; i++, arg++)
   {
-    if (c.aggregate(av[i]->collation, flags))
+    if (c.aggregate((*arg)->collation, flags))
     {
-      my_coll_agg_error(av, count, fname);
+      my_coll_agg_error(av, count, fname, item_sep);
       return TRUE;
     }
   }
   if ((flags & MY_COLL_DISALLOW_NONE) &&
       c.derivation == DERIVATION_NONE)
   {
-    my_coll_agg_error(av, count, fname);
+    my_coll_agg_error(av, count, fname, item_sep);
     return TRUE;
   }
   return FALSE;
@@ -1357,7 +1384,7 @@
                                         Item **av, uint count, uint flags)
 {
   return (agg_item_collations(c, fname, av, count,
-                              flags | MY_COLL_DISALLOW_NONE));
+                              flags | MY_COLL_DISALLOW_NONE, 1));
 }
 
 
@@ -1380,16 +1407,26 @@
   For functions with more than two arguments:
 
     collect(A,B,C) ::= collect(collect(A,B),C)
+
+  Since this function calls THD::change_item_tree() on the passed Item **
+  pointers, it is necessary to pass the original Item **'s, not copies.
+  Otherwise their values will not be properly restored (see BUG#20769).
+  If the items are not consecutive (eg. args[2] and args[5]), use the
+  item_sep argument, ie.
+
+    agg_item_charsets(coll, fname, &args[2], 2, flags, 3)
+
 */
 
 bool agg_item_charsets(DTCollation &coll, const char *fname,
-                       Item **args, uint nargs, uint flags)
+                       Item **args, uint nargs, uint flags, int item_sep)
 {
   Item **arg, **last, *safe_args[2];
 
   LINT_INIT(safe_args[0]);
   LINT_INIT(safe_args[1]);
-  if (agg_item_collations(coll, fname, args, nargs, flags))
+
+  if (agg_item_collations(coll, fname, args, nargs, flags, item_sep))
     return TRUE;
 
   /*
@@ -1402,19 +1439,20 @@
   if (nargs >=2 && nargs <= 3)
   {
     safe_args[0]= args[0];
-    safe_args[1]= args[1];
+    safe_args[1]= args[item_sep];
   }
 
   THD *thd= current_thd;
   Query_arena *arena, backup;
   bool res= FALSE;
+  uint i;
   /*
     In case we're in statement prepare, create conversion item
     in its memory: it will be reused on each execute.
   */
   arena= thd->activate_stmt_arena_if_needed(&backup);
 
-  for (arg= args, last= args + nargs; arg < last; arg++)
+  for (i= 0, arg= args; i < nargs; i++, arg+= item_sep)
   {
     Item* conv;
     uint32 dummy_offset;
@@ -1429,9 +1467,9 @@
       {
         /* restore the original arguments for better error message */
         args[0]= safe_args[0];
-        args[1]= safe_args[1];
+        args[item_sep]= safe_args[1];
       }
-      my_coll_agg_error(args, nargs, fname);
+      my_coll_agg_error(args, nargs, fname, item_sep);
       res= TRUE;
       break; // we cannot return here, we need to restore "arena".
     }
@@ -1463,7 +1501,18 @@
 }
 
 
-
+void Item_ident_for_show::make_field(Send_field *tmp_field)
+{
+  tmp_field->table_name= tmp_field->org_table_name= table_name;
+  tmp_field->db_name= db_name;
+  tmp_field->col_name= tmp_field->org_col_name= field->field_name;
+  tmp_field->charsetnr= field->charset()->number;
+  tmp_field->length=field->field_length;
+  tmp_field->type=field->type();
+  tmp_field->flags= field->table->maybe_null ? 
+    (field->flags & ~NOT_NULL_FLAG) : field->flags;
+  tmp_field->decimals= 0;
+}
 
 /**********************************************/
 
@@ -2013,7 +2062,7 @@
 {
   // following assert is redundant, because fixed=1 assigned in constructor
   DBUG_ASSERT(fixed == 1);
-  str->set(value,decimals,&my_charset_bin);
+  str->set_real(value,decimals,&my_charset_bin);
   return str;
 }
 
@@ -2366,7 +2415,8 @@
       CHARSET_INFO *tocs= thd->variables.collation_connection;
       uint32 dummy_offset;
 
-      value.cs_info.character_set_of_placeholder= fromcs;
+      value.cs_info.character_set_of_placeholder= 
+        value.cs_info.character_set_client= fromcs;
       /*
         Setup source and destination character sets so that they
         are different only if conversion is necessary: this will
@@ -2607,7 +2657,7 @@
   case LONG_DATA_VALUE:
     return &str_value_ptr;
   case REAL_VALUE:
-    str->set(value.real, NOT_FIXED_DEC, &my_charset_bin);
+    str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
     return str;
   case INT_VALUE:
     str->set(value.integer, &my_charset_bin);
@@ -2647,7 +2697,7 @@
     str->set(value.integer, &my_charset_bin);
     break;
   case REAL_VALUE:
-    str->set(value.real, NOT_FIXED_DEC, &my_charset_bin);
+    str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
     break;
   case DECIMAL_VALUE:
     if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
@@ -3569,7 +3619,8 @@
         Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
                                       &counter, REPORT_EXCEPT_NOT_FOUND,
                                       &not_used);
-        if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM)
+        if (res != (Item **)not_found_item &&
+            (*res)->type() == Item::FIELD_ITEM)
         {
           set_field((*((Item_field**)res))->field);
           return 0;
@@ -3588,7 +3639,7 @@
       if it is not expression from merged VIEW we will set this field.
 
       We can leave expression substituted from view for next PS/SP rexecution
-      (i.e. do not register this substitution for reverting on cleupup()
+      (i.e. do not register this substitution for reverting on cleanup()
       (register_item_tree_changing())), because this subtree will be
       fix_field'ed during setup_tables()->setup_underlying() (i.e. before
       all other expressions of query, and references on tables which do
@@ -3600,13 +3651,13 @@
       return FALSE;
 
     if (!outer_fixed && cached_table && cached_table->select_lex &&
-          context->select_lex &&
-          cached_table->select_lex != context->select_lex)
+        context->select_lex &&
+        cached_table->select_lex != context->select_lex)
     {
       int ret;
       if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
         goto error;
-      else if (!ret)
+      if (!ret)
         return FALSE;
     }
 
@@ -3617,17 +3668,28 @@
       set_if_bigger(thd->lex->in_sum_func->max_arg_level,
                     thd->lex->current_select->nest_level);
   }
-  else if (thd->set_query_id)
+  else if (thd->mark_used_columns != MARK_COLUMNS_NONE)
   {
     TABLE *table= field->table;
-    table->file->ha_set_bit_in_rw_set(field->fieldnr,
-                                      (bool)(thd->set_query_id-1));
-    if (field->query_id != thd->query_id)
-    {
-      /* We only come here in unions */
-      field->query_id=thd->query_id;
-      table->used_fields++;
-      table->used_keys.intersect(field->part_of_key);
+    MY_BITMAP *current_bitmap, *other_bitmap;
+    if (thd->mark_used_columns == MARK_COLUMNS_READ)
+    {
+      current_bitmap= table->read_set;
+      other_bitmap=   table->write_set;
+    }
+    else
+    {
+      current_bitmap= table->write_set;
+      other_bitmap=   table->read_set;
+    }
+    if (!bitmap_fast_test_and_set(current_bitmap, field->field_index))
+    {
+      if (!bitmap_is_set(other_bitmap, field->field_index))
+      {
+        /* First usage of column */
+        table->used_fields++;                     // Used to optimize loops
+        table->used_keys.intersect(field->part_of_key);
+      }
     }
   }
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -4288,7 +4350,7 @@
   }
   char buffer[20];
   String num(buffer, sizeof(buffer), &my_charset_bin);
-  num.set(value, decimals, &my_charset_bin);
+  num.set_real(value, decimals, &my_charset_bin);
   str->append(num);
 }
 
@@ -5398,17 +5460,22 @@
 void Item_trigger_field::setup_field(THD *thd, TABLE *table,
                                      GRANT_INFO *table_grant_info)
 {
-  bool save_set_query_id= thd->set_query_id;
-
-  /* TODO: Think more about consequences of this step. */
-  thd->set_query_id= 0;
+  /*
+    It is too early to mark fields used here, because before execution
+    of statement that will invoke trigger other statements may use same
+    TABLE object, so all such mark-up will be wiped out.
+    So instead we do it in Table_triggers_list::mark_fields_used()
+    method which is called during execution of these statements.
+  */
+  enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
+  thd->mark_used_columns= MARK_COLUMNS_NONE;
   /*
     Try to find field by its name and if it will be found
     set field_idx properly.
   */
   (void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
                             0, &field_idx);
-  thd->set_query_id= save_set_query_id;
+  thd->mark_used_columns= save_mark_used_columns;
   triggers= table->triggers;
   table_grants= table_grant_info;
 }
@@ -5730,7 +5797,7 @@
 String* Item_cache_real::val_str(String *str)
 {
   DBUG_ASSERT(fixed == 1);
-  str->set(value, decimals, default_charset());
+  str->set_real(value, decimals, default_charset());
   return str;
 }
 

--- 1.198/sql/item.h	2006-08-06 02:11:48 +10:00
+++ 1.199/sql/item.h	2006-08-06 02:11:48 +10:00
@@ -762,7 +762,7 @@
   static CHARSET_INFO *default_charset();
   virtual CHARSET_INFO *compare_collation() { return NULL; }
 
-  virtual bool walk(Item_processor processor, byte *arg)
+  virtual bool walk(Item_processor processor, bool walk_subquery, byte *arg)
   {
     return (this->*processor)(arg);
   }
@@ -784,7 +784,7 @@
   virtual bool collect_item_field_processor(byte * arg) { return 0; }
   virtual bool find_item_in_field_list_processor(byte *arg) { return 0; }
   virtual bool change_context_processor(byte *context) { return 0; }
-  virtual bool reset_query_id_processor(byte *query_id) { return 0; }
+  virtual bool register_field_in_read_map(byte *arg) { return 0; }
   /*
     Check if a partition function is allowed
     SYNOPSIS
@@ -857,6 +857,14 @@
   {
     return 0;
   }
+  /*
+    result_as_longlong() must return TRUE for Items representing DATE/TIME
+    functions and DATE/TIME table fields.
+    Those Items have result_type()==STRING_RESULT (and not INT_RESULT), but
+    their values should be compared as integers (because the integer
+    representation is more precise than the string one).
+  */
+  virtual bool result_as_longlong() { return FALSE; }
 };
 
 
@@ -882,13 +890,6 @@
 public:
   LEX_STRING m_name;
 
-  /*
-    Buffer, pointing to the string value of the item. We need it to
-    protect internal buffer from changes. See comment to analogous
-    member in Item_param for more details.
-  */
-  String str_value_ptr;
-
 public:
 #ifndef DBUG_OFF
   /*
@@ -1131,12 +1132,11 @@
 };
 
 bool agg_item_collations(DTCollation &c, const char *name,
-                         Item **items, uint nitems, uint flags= 0);
+                         Item **items, uint nitems, uint flags, int item_sep);
 bool agg_item_collations_for_comparison(DTCollation &c, const char *name,
-                                        Item **items, uint nitems,
-                                        uint flags= 0);
+                                        Item **items, uint nitems, uint flags);
 bool agg_item_charsets(DTCollation &c, const char *name,
-                       Item **items, uint nitems, uint flags= 0);
+                       Item **items, uint nitems, uint flags, int item_sep);
 
 
 class Item_num: public Item
@@ -1199,6 +1199,28 @@
                             bool any_privileges);
 };
 
+
+class Item_ident_for_show :public Item
+{
+public:
+  Field *field;
+  const char *db_name;
+  const char *table_name;
+
+  Item_ident_for_show(Field *par_field, const char *db_arg,
+                      const char *table_name_arg)
+    :field(par_field), db_name(db_arg), table_name(table_name_arg)
+  {}
+
+  enum Type type() const { return FIELD_ITEM; }
+  double val_real() { return field->val_real(); }
+  longlong val_int() { return field->val_int(); }
+  String *val_str(String *str) { return field->val_str(str); }
+  my_decimal *val_decimal(my_decimal *dec) { return field->val_decimal(dec); }
+  void make_field(Send_field *tmp_field);
+};
+
+
 class Item_equal;
 class COND_EQUAL;
 
@@ -1280,15 +1302,13 @@
   Item *get_tmp_table_item(THD *thd);
   bool collect_item_field_processor(byte * arg);
   bool find_item_in_field_list_processor(byte *arg);
-  bool reset_query_id_processor(byte *arg)
-  {
-    field->query_id= *((query_id_t *) arg);
-    if (result_field)
-      result_field->query_id= field->query_id;
-    return 0;
-  }
+  bool register_field_in_read_map(byte *arg);
   bool check_partition_func_processor(byte *bool_arg) { return 0; }
   void cleanup();
+  bool result_as_longlong()
+  {
+    return field->can_be_compared_as_longlong();
+  }
   Item_equal *find_item_equal(COND_EQUAL *cond_equal);
   Item *equal_fields_propagator(byte *arg);
   Item *set_no_const_sub(byte *arg);
@@ -1907,9 +1927,13 @@
   {
     return ref ? (*ref)->real_item() : this;
   }
-  bool walk(Item_processor processor, byte *arg)
-  { return (*ref)->walk(processor, arg); }
+  bool walk(Item_processor processor, bool walk_subquery, byte *arg)
+  { return (*ref)->walk(processor, walk_subquery, arg); }
   void print(String *str);
+  bool result_as_longlong()
+  {
+    return (*ref)->result_as_longlong();
+  }
   void cleanup();
   Item_field *filed_for_view_update()
     { return (*ref)->filed_for_view_update(); }
@@ -2159,9 +2183,9 @@
   int save_in_field(Field *field_arg, bool no_conversions);
   table_map used_tables() const { return (table_map)0L; }
 
-  bool walk(Item_processor processor, byte *args)
+  bool walk(Item_processor processor, bool walk_subquery, byte *args)
   {
-    return arg->walk(processor, args) ||
+    return arg->walk(processor, walk_subquery, args) ||
       (this->*processor)(args);
   }
 
@@ -2206,9 +2230,9 @@
   }
   table_map used_tables() const { return (table_map)0L; }
 
-  bool walk(Item_processor processor, byte *args)
+  bool walk(Item_processor processor, bool walk_subquery, byte *args)
   {
-    return arg->walk(processor, args) ||
+    return arg->walk(processor, walk_subquery, args) ||
 	    (this->*processor)(args);
   }
 };

--- 1.466/sql/sql_yacc.yy	2006-08-06 02:11:48 +10:00
+++ 1.467/sql/sql_yacc.yy	2006-08-06 02:11:48 +10:00
@@ -38,16 +38,10 @@
 #include "sp_pcontext.h"
 #include "sp_rcontext.h"
 #include "sp.h"
-#include "event.h"
+#include "event_timed.h"
 #include <myisam.h>
 #include <myisammrg.h>
 
-typedef struct p_elem_val
-{ 
-  longlong value;
-  bool null_value;
-} part_elem_value;
-
 int yylex(void *yylval, void *yythd);
 
 const LEX_STRING null_lex_str={0,0};
@@ -1385,7 +1379,7 @@
                   String str(buff,(uint32) sizeof(buff), system_charset_info);
                   String *str2= $2->val_str(&str);
                   my_error(ER_WRONG_VALUE, MYF(0), "AT",
-                           str2? str2->c_ptr():"NULL");
+                           str2? str2->c_ptr_safe():"NULL");
                   YYABORT;
                   break;
                 }
@@ -1436,8 +1430,8 @@
                   char buff[20];
                   String str(buff,(uint32) sizeof(buff), system_charset_info);
                   String *str2= $2->val_str(&str);
-                  my_error(ER_WRONG_VALUE, MYF(0), "STARTS", str2? str2->c_ptr():
-                                                                   NULL);
+                  my_error(ER_WRONG_VALUE, MYF(0), "STARTS",
+	                   str2 ? str2->c_ptr_safe() : NULL);
                   YYABORT;
                   break;
                 }
@@ -1600,12 +1594,18 @@
 	  }
 	| ident
 	  {
+            THD *thd= YYTHD;
+            LEX_STRING db;
 	    if (check_routine_name($1))
             {
 	      my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
 	      YYABORT;
 	    }
-	    $$= sp_name_current_db_new(YYTHD, $1);
+            if (thd->copy_db_to(&db.str, &db.length))
+              YYABORT;
+	    $$= new sp_name(db, $1);
+            if ($$)
+	      $$->init_qname(YYTHD);
 	  }
 	;
 
@@ -2064,16 +2064,19 @@
 	  {
 	    Lex->sphead->reset_lex(YYTHD);
 
-	    /* We use statement here just be able to get a better
-	       error message. Using 'select' works too, but will then
-	       result in a generic "syntax error" if a non-select
-	       statement is given. */
+	    /*
+	      We use statement here just be able to get a better
+	      error message. Using 'select' works too, but will then
+	      result in a generic "syntax error" if a non-select
+	      statement is given.
+	    */
 	  }
 	  statement
 	  {
 	    LEX *lex= Lex;
 
-	    if (lex->sql_command != SQLCOM_SELECT)
+	    if (lex->sql_command != SQLCOM_SELECT &&
+	       !(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND))
 	    {
 	      my_message(ER_SP_BAD_CURSOR_QUERY, ER(ER_SP_BAD_CURSOR_QUERY),
                          MYF(0));
@@ -3187,14 +3190,26 @@
         | LIKE table_ident
           {
             LEX *lex=Lex;
+            THD *thd= lex->thd;
             if (!(lex->like_name= $2))
               YYABORT;
+            if ($2->db.str == NULL &&
+                thd->copy_db_to(&($2->db.str), &($2->db.length)))
+            {
+              YYABORT;
+            }
           }
         | '(' LIKE table_ident ')'
           {
             LEX *lex=Lex;
+            THD *thd= lex->thd;
             if (!(lex->like_name= $3))
               YYABORT;
+            if ($3->db.str == NULL &&
+                thd->copy_db_to(&($3->db.str), &($3->db.length)))
+            {
+              YYABORT;
+            }
           }
         ;
 
@@ -3553,7 +3568,7 @@
         ;
 
 part_func_max:
-        MAX_VALUE_SYM
+        max_value_sym
         {
           LEX *lex= Lex;
           if (lex->part_info->defined_max_value)
@@ -3562,6 +3577,7 @@
             YYABORT;
           }
           lex->part_info->defined_max_value= TRUE;
+          lex->part_info->curr_part_elem->max_value= TRUE;
           lex->part_info->curr_part_elem->range_value= LONGLONG_MAX;
         }
         | part_range_func
@@ -3579,10 +3595,18 @@
         }
         ;
 
+max_value_sym:
+        MAX_VALUE_SYM
+        | '(' MAX_VALUE_SYM ')'
+        ;
+        
 part_range_func:
         '(' part_bit_expr ')' 
         {
-          Lex->part_info->curr_part_elem->range_value= $2->value;
+          partition_info *part_info= Lex->part_info;
+          if (!($2->unsigned_flag))
+            part_info->curr_part_elem->signed_flag= TRUE;
+          part_info->curr_part_elem->range_value= $2->value;
         }
         ;
 
@@ -3595,9 +3619,12 @@
         part_bit_expr
         {
           part_elem_value *value_ptr= $1;
+          partition_info *part_info= Lex->part_info;
+          if (!value_ptr->unsigned_flag)
+            part_info->curr_part_elem->signed_flag= TRUE;
           if (!value_ptr->null_value &&
-             Lex->part_info->curr_part_elem->
-              list_val_list.push_back((longlong*) &value_ptr->value))
+             part_info->curr_part_elem->
+              list_val_list.push_back(value_ptr))
           {
             mem_alloc_error(sizeof(part_elem_value));
             YYABORT;
@@ -3638,6 +3665,10 @@
           }
           thd->where= save_where;
           value_ptr->value= part_expr->val_int();
+          value_ptr->unsigned_flag= TRUE;
+          if (!part_expr->unsigned_flag &&
+              value_ptr->value < 0)
+            value_ptr->unsigned_flag= FALSE;
           if ((value_ptr->null_value= part_expr->null_value))
           {
             if (Lex->part_info->curr_part_elem->has_null_value)
@@ -3703,14 +3734,15 @@
         {
           LEX *lex= Lex;
           partition_info *part_info= lex->part_info;
-          partition_element *p_elem= new partition_element();
-          if (!p_elem ||
-           part_info->current_partition->subpartitions.push_back(p_elem))
+          partition_element *curr_part= part_info->current_partition;
+          partition_element *sub_p_elem= new partition_element(curr_part);
+          if (!sub_p_elem ||
+           curr_part->subpartitions.push_back(sub_p_elem))
           {
             mem_alloc_error(sizeof(partition_element));
             YYABORT;
           }
-          part_info->curr_part_elem= p_elem;
+          part_info->curr_part_elem= sub_p_elem;
           part_info->use_default_subpartitions= FALSE;
           part_info->use_default_no_subpartitions= FALSE;
           part_info->count_curr_subparts++;
@@ -3848,7 +3880,7 @@
 	| MIN_ROWS opt_equal ulonglong_num	{ Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;}
 	| AVG_ROW_LENGTH opt_equal ulong_num	{ Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
 	| PASSWORD opt_equal TEXT_STRING_sys	{ Lex->create_info.password=$3.str; Lex->create_info.used_fields|= HA_CREATE_USED_PASSWORD; }
-	| COMMENT_SYM opt_equal TEXT_STRING_sys	{ Lex->create_info.comment=$3.str; Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT; }
+	| COMMENT_SYM opt_equal TEXT_STRING_sys	{ Lex->create_info.comment=$3; Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT; }
 	| AUTO_INC opt_equal ulonglong_num	{ Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;}
         | PACK_KEYS_SYM opt_equal ulong_num
           {
@@ -4627,8 +4659,10 @@
 	  lex->key_list.empty();
 	  lex->col_list.empty();
           lex->select_lex.init_order();
-	  lex->select_lex.db=lex->name= 0;
+	  lex->name= 0;
 	  lex->like_name= 0;
+	  lex->select_lex.db=
+            ((TABLE_LIST*) lex->select_lex.table_list.first)->db;
 	  bzero((char*) &lex->create_info,sizeof(lex->create_info));
 	  lex->create_info.db_type= 0;
 	  lex->create_info.default_table_charset= NULL;
@@ -4647,8 +4681,11 @@
           opt_create_database_options
 	  {
 	    LEX *lex=Lex;
+            THD *thd= Lex->thd;
 	    lex->sql_command=SQLCOM_ALTER_DB;
 	    lex->name= $3;
+            if (lex->name == NULL && thd->copy_db_to(&lex->name, NULL))
+              YYABORT;
 	  }
 	| ALTER PROCEDURE sp_name
 	  {
@@ -5083,14 +5120,20 @@
 	| RENAME opt_to table_ident
 	  {
 	    LEX *lex=Lex;
+            THD *thd= lex->thd;
 	    lex->select_lex.db=$3->db.str;
-	    lex->name= $3->table.str;
+            if (lex->select_lex.db == NULL &&
+                thd->copy_db_to(&lex->select_lex.db, NULL))
+            {
+              YYABORT;
+            }
             if (check_table_name($3->table.str,$3->table.length) ||
                 $3->db.str && check_db_name($3->db.str))
             {
               my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str);
               YYABORT;
             }
+	    lex->name= $3->table.str;
 	    lex->alter_info.flags|= ALTER_RENAME;
 	  }
 	| CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate
@@ -5665,10 +5708,21 @@
 	      YYABORT;
 	    Select->options|= OPTION_FOUND_ROWS;
 	  }
-	| SQL_NO_CACHE_SYM { Lex->safe_to_cache_query=0; }
+	| SQL_NO_CACHE_SYM
+          {
+            Lex->safe_to_cache_query=0;
+	    Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE;
+            Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE;
+          }
 	| SQL_CACHE_SYM
 	  {
-	    Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
+            /* Honor this flag only if SQL_NO_CACHE wasn't specified. */
+            if (Lex->select_lex.sql_cache != SELECT_LEX::SQL_NO_CACHE)
+            {
+              Lex->safe_to_cache_query=1;
+	      Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
+              Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE;
+            }
 	  }
 	| ALL		    { Select->options|= SELECT_ALL; }
 	;
@@ -6361,7 +6415,7 @@
               if (udf->type == UDFTYPE_AGGREGATE)
                 Select->in_sum_expr--;
 
-              Lex->binlog_row_based_if_mixed= 1;
+              Lex->binlog_row_based_if_mixed= TRUE;
 
               switch (udf->returns) {
               case STRING_RESULT:
@@ -6436,7 +6490,13 @@
 #endif /* HAVE_DLOPEN */
             {
 	      LEX *lex= Lex;
-              sp_name *name= sp_name_current_db_new(YYTHD, $1);
+              THD *thd= lex->thd;
+              LEX_STRING db;
+              if (thd->copy_db_to(&db.str, &db.length))
+                YYABORT;
+              sp_name *name= new sp_name(db, $1);
+              if (name)
+                name->init_qname(thd);
 
               sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION);
               if ($4)
@@ -8025,6 +8085,7 @@
 	  LEX* lex= Lex;
 	  lex->sql_command= SQLCOM_TRUNCATE;
 	  lex->select_lex.options= 0;
+          lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
 	  lex->select_lex.init_order();
 	}
 	;
@@ -8052,16 +8113,14 @@
          DATABASES wild_and_where
          {
            LEX *lex= Lex;
-           lex->sql_command= SQLCOM_SELECT;
-           lex->orig_sql_command= SQLCOM_SHOW_DATABASES;
+           lex->sql_command= SQLCOM_SHOW_DATABASES;
            if (prepare_schema_table(YYTHD, lex, 0, SCH_SCHEMATA))
              YYABORT;
          }
          | opt_full TABLES opt_db wild_and_where
            {
              LEX *lex= Lex;
-             lex->sql_command= SQLCOM_SELECT;
-             lex->orig_sql_command= SQLCOM_SHOW_TABLES;
+             lex->sql_command= SQLCOM_SHOW_TABLES;
              lex->select_lex.db= $3;
              if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
                YYABORT;
@@ -8069,8 +8128,7 @@
          | opt_full TRIGGERS_SYM opt_db wild_and_where
            {
              LEX *lex= Lex;
-             lex->sql_command= SQLCOM_SELECT;
-             lex->orig_sql_command= SQLCOM_SHOW_TRIGGERS;
+             lex->sql_command= SQLCOM_SHOW_TRIGGERS;
              lex->select_lex.db= $3;
              if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS))
                YYABORT;
@@ -8078,8 +8136,7 @@
          | EVENTS_SYM opt_db wild_and_where
            {
              LEX *lex= Lex;
-             lex->sql_command= SQLCOM_SELECT;
-             lex->orig_sql_command= SQLCOM_SHOW_EVENTS;
+             lex->sql_command= SQLCOM_SHOW_EVENTS;
              lex->select_lex.db= $2;
              if (prepare_schema_table(YYTHD, lex, 0, SCH_EVENTS))
                YYABORT;
@@ -8096,8 +8153,7 @@
          | TABLE_SYM STATUS_SYM opt_db wild_and_where
            {
              LEX *lex= Lex;
-             lex->sql_command= SQLCOM_SELECT;
-             lex->orig_sql_command= SQLCOM_SHOW_TABLE_STATUS;
+             lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
              lex->select_lex.db= $3;
              if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLES))
                YYABORT;
@@ -8105,8 +8161,7 @@
         | OPEN_SYM TABLES opt_db wild_and_where
 	  {
 	    LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_OPEN_TABLES;
+            lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
 	    lex->select_lex.db= $3;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_OPEN_TABLES))
               YYABORT;
@@ -8115,16 +8170,14 @@
 	  {
 	    LEX *lex= Lex;
 	    WARN_DEPRECATED(yythd, "5.2", "SHOW PLUGIN", "'SHOW PLUGINS'");
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_PLUGINS;
+            lex->sql_command= SQLCOM_SHOW_PLUGINS;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_PLUGINS))
               YYABORT;
 	  }
         | PLUGINS_SYM
 	  {
 	    LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_PLUGINS;
+            lex->sql_command= SQLCOM_SHOW_PLUGINS;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_PLUGINS))
               YYABORT;
 	  }
@@ -8137,8 +8190,7 @@
 	| opt_full COLUMNS from_or_in table_ident opt_db wild_and_where
 	  {
  	    LEX *lex= Lex;
-	    lex->sql_command= SQLCOM_SELECT;
-	    lex->orig_sql_command= SQLCOM_SHOW_FIELDS;
+	    lex->sql_command= SQLCOM_SHOW_FIELDS;
 	    if ($5)
 	      $4->change_db($5);
 	    if (prepare_schema_table(YYTHD, lex, $4, SCH_COLUMNS))
@@ -8170,8 +8222,7 @@
         | keys_or_index from_or_in table_ident opt_db where_clause
           {
             LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_KEYS;
+            lex->sql_command= SQLCOM_SHOW_KEYS;
 	    if ($4)
 	      $3->change_db($4);
             if (prepare_schema_table(YYTHD, lex, $3, SCH_STATISTICS))
@@ -8192,7 +8243,6 @@
 	  {
 	    LEX *lex=Lex;
 	    lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES;
-            lex->orig_sql_command= SQLCOM_SHOW_AUTHORS;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_ENGINES))
               YYABORT;
 	  }
@@ -8222,8 +8272,7 @@
         | opt_var_type STATUS_SYM wild_and_where
           {
             LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_STATUS;
+            lex->sql_command= SQLCOM_SHOW_STATUS;
             lex->option_type= $1;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_STATUS))
               YYABORT;
@@ -8257,8 +8306,7 @@
         | opt_var_type  VARIABLES wild_and_where
 	  {
             LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_VARIABLES;
+            lex->sql_command= SQLCOM_SHOW_VARIABLES;
             lex->option_type= $1;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_VARIABLES))
               YYABORT;
@@ -8266,16 +8314,14 @@
         | charset wild_and_where
           {
             LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_CHARSETS;
+            lex->sql_command= SQLCOM_SHOW_CHARSETS;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_CHARSETS))
               YYABORT;
           }
         | COLLATION_SYM wild_and_where
           {
             LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_COLLATIONS;
+            lex->sql_command= SQLCOM_SHOW_COLLATIONS;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_COLLATIONS))
               YYABORT;
           }
@@ -8307,24 +8353,10 @@
 	  {
 	    LEX *lex=Lex;
 	    lex->sql_command= SQLCOM_SHOW_GRANTS;
-	    THD *thd= lex->thd;
-            Security_context *sctx= thd->security_ctx;
 	    LEX_USER *curr_user;
-            if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(st_lex_user))))
+            if (!(curr_user= (LEX_USER*) lex->thd->alloc(sizeof(st_lex_user))))
               YYABORT;
-            curr_user->user.str= sctx->priv_user;
-            curr_user->user.length= strlen(sctx->priv_user);
-            if (*sctx->priv_host != 0)
-            {
-              curr_user->host.str= sctx->priv_host;
-              curr_user->host.length= strlen(sctx->priv_host);
-            }
-            else
-            {
-              curr_user->host.str= (char *) "%";
-              curr_user->host.length= 1;
-            }
-            curr_user->password=null_lex_str;
+            bzero(curr_user, sizeof(st_lex_user));
 	    lex->grant_user= curr_user;
 	  }
 	| GRANTS FOR_SYM user
@@ -8381,8 +8413,7 @@
 	| PROCEDURE STATUS_SYM wild_and_where
 	  {
             LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_STATUS_PROC;
+            lex->sql_command= SQLCOM_SHOW_STATUS_PROC;
 	    if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
 	      YYABORT;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
@@ -8391,8 +8422,7 @@
 	| FUNCTION_SYM STATUS_SYM wild_and_where
 	  {
             LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->orig_sql_command= SQLCOM_SHOW_STATUS_FUNC;
+            lex->sql_command= SQLCOM_SHOW_STATUS_FUNC;
 	    if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
 	      YYABORT;
             if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
@@ -8487,8 +8517,7 @@
           lex->lock_option= TL_READ;
           mysql_init_select(lex);
           lex->current_select->parsing_place= SELECT_LIST;
-          lex->sql_command= SQLCOM_SELECT;
-          lex->orig_sql_command= SQLCOM_SHOW_FIELDS;
+          lex->sql_command= SQLCOM_SHOW_FIELDS;
           lex->select_lex.db= 0;
           lex->verbose= 0;
           if (prepare_schema_table(YYTHD, lex, $2, SCH_COLUMNS))
@@ -9274,22 +9303,14 @@
 	  }
 	| CURRENT_USER optional_braces
 	{
-          THD *thd= YYTHD;
-          Security_context *sctx= thd->security_ctx;
-          if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
+          if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user))))
             YYABORT;
-          $$->user.str= sctx->priv_user;
-          $$->user.length= strlen(sctx->priv_user);
-          if (*sctx->priv_host != 0)
-          {
-            $$->host.str= sctx->priv_host;
-            $$->host.length= strlen(sctx->priv_host);
-          }
-          else
-          {
-            $$->host.str= (char *) "%";
-            $$->host.length= 1;
-          }
+          /* 
+            empty LEX_USER means current_user and 
+            will be handled in the  get_current_user() function
+            later
+          */
+          bzero($$, sizeof(LEX_USER));
 	};
 
 /* Keyword that we allow for identifiers (except SP labels) */
@@ -10333,7 +10354,9 @@
 	'*'
 	  {
 	    LEX *lex= Lex;
-	    lex->current_select->db= lex->thd->db;
+            THD *thd= lex->thd;
+            if (thd->copy_db_to(&lex->current_select->db, NULL))
+              YYABORT;
 	    if (lex->grant == GLOBAL_ACLS)
 	      lex->grant = DB_ACLS & ~GRANT_ACL;
 	    else if (lex->columns.elements)
@@ -10625,6 +10648,8 @@
             yyerror(ER(ER_SYNTAX_ERROR));
 	    YYABORT;
 	  }
+          /* This counter shouldn't be incremented for UNION parts */
+          Lex->nest_level--;
 	  if (mysql_new_select(lex, 0))
 	    YYABORT;
           mysql_init_select(lex);

--- 1.90/sql/share/errmsg.txt	2006-08-06 02:11:48 +10:00
+++ 1.91/sql/share/errmsg.txt	2006-08-06 02:11:48 +10:00
@@ -54,7 +54,7 @@
 	dan "Kan ikke oprette filen '%-.64s' (Fejlkode: %d)"
 	nla "Kan file '%-.64s' niet aanmaken (Errcode: %d)"
-	eng "Can't create file '%-.64s' (errno: %d)"
+	eng "Can't create file '%-.200s' (errno: %d)"
 	est "Ei suuda luua faili '%-.64s' (veakood: %d)"
 	ger "Kann Datei '%-.64s' nicht erzeugen (Fehler: %d)"
@@ -278,7 +278,7 @@
 	nla "Kan de status niet krijgen van '%-.64s' (Errcode: %d)"
-	eng "Can't get status of '%-.64s' (errno: %d)"
+	eng "Can't get status of '%-.200s' (errno: %d)"
 	est "Ei suuda lugeda '%-.64s' olekut (veakood: %d)"
 	fre "Ne peut obtenir le status de '%-.64s' (Errcode: %d)"
@@ -353,7 +353,7 @@
 	nla "Kan de file '%-.64s' niet openen (Errcode: %d)"
-	eng "Can't open file: '%-.64s' (errno: %d)"
+	eng "Can't open file: '%-.200s' (errno: %d)"
 	est "Ei suuda avada faili '%-.64s' (veakood: %d)"
 	fre "Ne peut ouvrir le fichier: '%-.64s' (Errcode: %d)"
@@ -378,7 +378,7 @@
 	dan "Kan ikke finde fila: '%-.64s' (Fejlkode: %d)"
 	nla "Kan de file: '%-.64s' niet vinden (Errcode: %d)"
-	eng "Can't find file: '%-.64s' (errno: %d)"
+	eng "Can't find file: '%-.200s' (errno: %d)"
 	est "Ei suuda leida faili '%-.64s' (veakood: %d)"
 	fre "Ne peut trouver le fichier: '%-.64s' (Errcode: %d)"
@@ -549,7 +549,7 @@
 	nla "Fout bij het lezen van file '%-.64s' (Errcode: %d)"
-	eng "Error reading file '%-.64s' (errno: %d)"
+	eng "Error reading file '%-.200s' (errno: %d)"
 	est "Viga faili '%-.64s' lugemisel (veakood: %d)"
 	fre "Erreur en lecture du fichier '%-.64s' (Errcode: %d)"
@@ -599,7 +599,7 @@
 	dan "Fejl ved skriving av filen '%-.64s' (Fejlkode: %d)"
 	nla "Fout bij het wegschrijven van file '%-.64s' (Errcode: %d)"
-	eng "Error writing file '%-.64s' (errno: %d)"
+	eng "Error writing file '%-.200s' (errno: %d)"
 	est "Viga faili '%-.64s' kirjutamisel (veakood: %d)"
@@ -772,7 +772,7 @@
 	dan "Forkert indhold i: '%-.64s'"
 	nla "Verkeerde info in file: '%-.64s'"
-	eng "Incorrect information in file: '%-.64s'"
+	eng "Incorrect information in file: '%-.200s'"
 	est "Vigane informatsioon failis '%-.64s'"
@@ -797,7 +797,7 @@
 	nla "Verkeerde zoeksleutel file voor tabel: '%-.64s'; probeer het te repareren"
-	eng "Incorrect key file for table '%-.64s'; try to repair it"
+	eng "Incorrect key file for table '%-.200s'; try to repair it"
@@ -2044,7 +2044,7 @@
 	nla "Het bestand '%-.64s' dient in de database directory voor the komen of leesbaar voor iedereen te zijn."
-	eng "The file '%-.64s' must be in the database directory or be readable by all"
+	eng "The file '%-.128s' must be in the database directory or be readable by all"
@@ -2069,7 +2069,7 @@
 	dan "Filen '%-.64s' eksisterer allerede"
 	nla "Het bestand '%-.64s' bestaat reeds"
-	eng "File '%-.80s' already exists"
+	eng "File '%-.200s' already exists"
 	est "Fail '%-.80s' juba eksisteerib"
@@ -2345,7 +2345,7 @@
 	dan "Kan ikke lave unikt log-filnavn %s.(1-999)\n"
 	nla "Het is niet mogelijk een unieke naam te maken voor de logfile %s.(1-999)\n"
-	eng "Can't generate a unique log-filename %-.64s.(1-999)\n"
+	eng "Can't generate a unique log-filename %-.200s.(1-999)\n"
 	est "Ei suuda luua unikaalset logifaili nime %-.64s.(1-999)\n"
@@ -2865,30 +2865,8 @@
 	swe "Felaktigt referens i OUTER JOIN.  Kontrollera ON-uttrycket"
 ER_NULL_COLUMN_IN_INDEX 42000 
-	dan "Kolonne '%-.32s' bruges som UNIQUE eller INDEX men er ikke defineret som NOT NULL"
-	nla "Kolom '%-.64s' wordt gebruikt met UNIQUE of INDEX maar is niet gedefinieerd als NOT NULL"
-	eng "Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
-	ger "Spalte '%-.64s' wurde mit UNIQUE oder INDEX benutzt, ist aber nicht als NOT NULL definiert"
-	hun "A(z) '%-.64s' oszlop INDEX vagy UNIQUE (egyedi), de a definicioja szerint nem NOT NULL"
-	ita "La colonna '%-.64s' e` usata con UNIQUE o INDEX ma non e` definita come NOT NULL"
-	nor "Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
-	norwegian-ny "Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
-	pol "Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
-	rum "Coloana '%-.64s' e folosita cu UNIQUE sau INDEX dar fara sa fie definita ca NOT NULL"
-	serbian "Kolona '%-.64s' je upotrebljena kao 'UNIQUE' ili 'INDEX' ali nije definisana kao 'NOT NULL'"
+	eng "Table handler doesn't support NULL in given index. Please change column '%-.64s' to be NOT NULL or use another handler"
 ER_CANT_FIND_UDF  
@@ -3957,7 +3935,7 @@
-ER_KEY_DOES_NOT_EXITS  
+ER_KEY_DOES_NOT_EXITS 42000 S1009
 	nla "Zoeksleutel '%-.64s' bestaat niet in tabel '%-.64s'"
@@ -5215,7 +5193,7 @@
 ER_FPARSER_EOF_IN_COMMENT  
-	eng "Unexpected end of file while parsing comment '%-.64s'"
+	eng "Unexpected end of file while parsing comment '%-.200s'"
 	ger "Unerwartetes Dateiende beim Parsen des Kommentars '%-.64s'"
@@ -5384,7 +5362,7 @@
 	eng "Binary logging and replication forbid changing the global server %s"
 ER_NO_FILE_MAPPING  
-	eng "Can't map file: %-.64s, errno: %d"
+	eng "Can't map file: %-.200s, errno: %d"
 	ger "Kann Datei nicht abbilden: %-.64s, Fehler: %d"
 ER_WRONG_MAGIC  
 	eng "Wrong magic in %-.64s"
@@ -5832,6 +5810,9 @@
 	eng "The NDB cluster engine does not support changing the binlog format on the fly yet"
 ER_PARTITION_NO_TEMPORARY
 	eng "Cannot create temporary table with partitions"
+ER_PARTITION_CONST_DOMAIN_ERROR
+        eng "Partition constant is out of partition function domain"
 ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
         eng "This partition function is not allowed"
@@ -5852,5 +5833,11 @@
 ER_EVENT_SET_VAR_ERROR
         eng "Error during starting/stopping of the scheduler. Error code %u"
 ER_PARTITION_MERGE_ERROR
-        eng "MyISAM Merge handler cannot be used in partitioned tables"
+        eng "%s handler cannot be used in partitioned tables"
+ER_CANT_ACTIVATE_LOG
+        eng "Cannot activate '%-.64s' log."
+ER_RBR_NOT_AVAILABLE
+        eng "The server was not built with row-based replication"
+ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
+	eng "Triggers can not be created on system tables"

--- 1.9/mysql-test/r/trigger-grant.result	2006-08-06 02:11:48 +10:00
+++ 1.10/mysql-test/r/trigger-grant.result	2006-08-06 02:11:48 +10:00
@@ -51,8 +51,8 @@
 ---> connection: wl2818_definer_con
 INSERT INTO t1 VALUES(0);
 DROP TRIGGER trg1;
-DELETE FROM t1;
-DELETE FROM t2;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
 
 ---> connection: default
 REVOKE SUPER ON *.* FROM mysqltest_dfn@localhost;

--- 1.11/mysql-test/t/trigger-grant.test	2006-08-06 02:11:48 +10:00
+++ 1.12/mysql-test/t/trigger-grant.test	2006-08-06 02:11:48 +10:00
@@ -151,8 +151,8 @@
 
 # Cleanup for further tests.
 DROP TRIGGER trg1;
-DELETE FROM t1;
-DELETE FROM t2;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
 
 --disconnect wl2818_definer_con
 

--- 1.54/sql/sql_trigger.cc	2006-08-06 02:11:48 +10:00
+++ 1.55/sql/sql_trigger.cc	2006-08-06 02:11:48 +10:00
@@ -183,6 +183,15 @@
       !(tables= add_table_for_trigger(thd, thd->lex->spname)))
     DBUG_RETURN(TRUE);
 
+  /*
+    We don't allow creating triggers on tables in the 'mysql' schema
+  */
+  if (create && !my_strcasecmp(system_charset_info, "mysql", tables->db))
+  {
+    my_error(ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA, MYF(0));
+    DBUG_RETURN(TRUE);
+  }
+
   /* We should have only one table in table list. */
   DBUG_ASSERT(tables->next_global == 0);
 
@@ -372,7 +381,9 @@
   /* We don't allow creation of several triggers of the same type yet */
   if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time])
   {
-    my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0));
+    my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+             "multiple triggers with the same action time"
+             " and event for one table");
     return 1;
   }
 
@@ -733,7 +744,8 @@
       QQ: it is supposed that it is ok to use this function for field
       cloning...
     */
-    if (!(*old_fld= (*fld)->new_field(&table->mem_root, table)))
+    if (!(*old_fld= (*fld)->new_field(&table->mem_root, table,
+                                      table == (*fld)->table)))
       return 1;
     (*old_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] -
                                           table->record[0]));
@@ -928,8 +940,7 @@
 
       save_db.str= thd->db;
       save_db.length= thd->db_length;
-      thd->db_length= strlen(db);
-      thd->db= (char *) db;
+      thd->reset_db((char*) db, strlen(db));
       while ((trg_create_str= it++))
       {
         trg_sql_mode= itm++;
@@ -1010,8 +1021,15 @@
         }
 
         /*
-          Let us bind Item_trigger_field objects representing access to fields
-          in old/new versions of row in trigger to Field objects in table being
+          Gather all Item_trigger_field objects representing access to fields
+          in old/new versions of row in trigger into lists containing all such
+          objects for the triggers with same action and timing.
+        */
+        triggers->trigger_fields[lex.trg_chistics.event]
+                                [lex.trg_chistics.action_time]=
+          (Item_trigger_field *)(lex.trg_table_fields.first);
+        /*
+          Also let us bind these objects to Field objects in table being
           opened.
 
           We ignore errors here, because if even something is wrong we still
@@ -1031,8 +1049,7 @@
 
         lex_end(&lex);
       }
-      thd->db= save_db.str;
-      thd->db_length= save_db.length;
+      thd->reset_db(save_db.str, save_db.length);
       thd->lex= old_lex;
       thd->spcont= save_spcont;
       thd->variables.sql_mode= save_sql_mode;
@@ -1045,8 +1062,7 @@
       thd->lex= old_lex;
       thd->spcont= save_spcont;
       thd->variables.sql_mode= save_sql_mode;
-      thd->db= save_db.str;
-      thd->db_length= save_db.length;
+      thd->reset_db(save_db.str, save_db.length);
       DBUG_RETURN(1);
     }
 
@@ -1523,6 +1539,44 @@
   }
 
   return err_status;
+}
+
+
+/*
+  Mark fields of subject table which we read/set in its triggers as such.
+
+  SYNOPSIS
+    mark_fields_used()
+      thd    Current thread context
+      event  Type of event triggers for which we are going to inspect
+
+  DESCRIPTION
+    This method marks fields of subject table which are read/set in its
+    triggers as such (by properly updating TABLE::read_set/write_set)
+    and thus informs handler that values for these fields should be
+    retrieved/stored during execution of statement.
+*/
+
+void Table_triggers_list::mark_fields_used(trg_event_type event)
+{
+  int action_time;
+  Item_trigger_field *trg_field;
+
+  for (action_time= 0; action_time < (int)TRG_ACTION_MAX; action_time++)
+  {
+    for (trg_field= trigger_fields[event][action_time]; trg_field;
+         trg_field= trg_field->next_trg_field)
+    {
+      /* We cannot mark fields which does not present in table. */
+      if (trg_field->field_idx != (uint)-1)
+      {
+        bitmap_set_bit(table->read_set, trg_field->field_idx);
+        if (trg_field->get_settable_routine_parameter())
+          bitmap_set_bit(table->write_set, trg_field->field_idx);
+      }
+    }
+  }
+  table->file->column_bitmaps_signal();
 }
 
 

--- 1.34/mysql-test/lib/mtr_process.pl	2006-08-06 02:11:48 +10:00
+++ 1.35/mysql-test/lib/mtr_process.pl	2006-08-06 02:11:48 +10:00
@@ -880,19 +880,28 @@
 sub mtr_kill_process ($$$$) {
   my $pid= shift;
   my $signal= shift;
-  my $retries= shift;
+  my $total_retries= shift;
   my $timeout= shift;
 
-  while (1)
+  for (my $cur_attempt= 1; $cur_attempt <= $total_retries; ++$cur_attempt)
   {
+    mtr_debug("Sending $signal to $pid...");
+
     kill($signal, $pid);
 
-    last unless kill (0, $pid) and $retries--;
+    unless (kill (0, $pid))
+    {
+      mtr_debug("Process $pid died.");
+      return;
+    }
 
-    mtr_debug("Sleep $timeout second waiting for processes to die");
+    mtr_debug("Sleeping $timeout second(s) waiting for processes to die...");
 
     sleep($timeout);
   }
+
+  mtr_debug("Process $pid is still alive after $total_retries " .
+            "of sending signal $signal.");
 }
 
 ##############################################################################

--- 1.121/mysql-test/mysql-test-run.pl	2006-08-06 02:11:48 +10:00
+++ 1.122/mysql-test/mysql-test-run.pl	2006-08-06 02:11:48 +10:00
@@ -216,6 +216,7 @@
 our $opt_fast;
 our $opt_force;
 our $opt_reorder;
+our $opt_enable_disabled;
 
 our $opt_gcov;
 our $opt_gcov_err;
@@ -290,7 +291,7 @@
 our $opt_valgrind= 0;
 our $opt_valgrind_mysqld= 0;
 our $opt_valgrind_mysqltest= 0;
-our $opt_valgrind_all= 0;
+our $default_valgrind_options= "--show-reachable=yes";
 our $opt_valgrind_options;
 our $opt_valgrind_path;
 
@@ -555,6 +556,11 @@
               "($opt_master_myport - $opt_master_myport + 10)");
   }
 
+  # This is needed for test log evaluation in "gen-build-status-page"
+  # in all cases where the calling tool does not log the commands
+  # directly before it executes them, like "make test-force-pl" in RPM builds.
+  print "Logging: $0 ", join(" ", @ARGV), "\n";
+
   # Read the command line
   # Note: Keep list, and the order, in sync with usage at end of this file
 
@@ -629,10 +635,9 @@
              # Coverage, profiling etc
              'gcov'                     => \$opt_gcov,
              'gprof'                    => \$opt_gprof,
-             'valgrind'                 => \$opt_valgrind,
+             'valgrind|valgrind-all'    => \$opt_valgrind,
              'valgrind-mysqltest'       => \$opt_valgrind_mysqltest,
              'valgrind-mysqld'          => \$opt_valgrind_mysqld,
-             'valgrind-all'             => \$opt_valgrind_all,
              'valgrind-options=s'       => \$opt_valgrind_options,
              'valgrind-path=s'          => \$opt_valgrind_path,
 
@@ -661,6 +666,7 @@
              'netware'                  => \$opt_netware,
              'old-master'               => \$opt_old_master,
              'reorder'                  => \$opt_reorder,
+             'enable-disabled'          => \$opt_enable_disabled,
              'script-debug'             => \$opt_script_debug,
              'sleep=i'                  => \$opt_sleep,
              'socket=s'                 => \$opt_socket,
@@ -694,6 +700,12 @@
     {
       push(@opt_extra_mysqld_opt, $arg);
     }
+    elsif ( $arg =~ /^--$/ )
+    {
+      # It is an effect of setting 'pass_through' in option processing
+      # that the lone '--' separating options from arguments survives,
+      # simply ignore it.
+    }
     elsif ( $arg =~ /^-/ )
     {
       usage("Invalid option \"$arg\"");
@@ -810,20 +822,32 @@
     }
   }
 
-  # Turn on valgrinding of all executables if "valgrind" or "valgrind-all"
-  if ( $opt_valgrind or $opt_valgrind_all )
+  # Check valgrind arguments
+  if ( $opt_valgrind or $opt_valgrind_path or defined $opt_valgrind_options)
   {
     mtr_report("Turning on valgrind for all executables");
     $opt_valgrind= 1;
     $opt_valgrind_mysqld= 1;
     $opt_valgrind_mysqltest= 1;
   }
-  elsif ( $opt_valgrind_mysqld or $opt_valgrind_mysqltest )
+  elsif ( $opt_valgrind_mysqld )
   {
-    # If test's are run for a specific executable, turn on
-    # verbose and show-reachable
+    mtr_report("Turning on valgrind for mysqld(s) only");
     $opt_valgrind= 1;
-    $opt_valgrind_all= 1;
+  }
+  elsif ( $opt_valgrind_mysqltest )
+  {
+    mtr_report("Turning on valgrind for mysqltest only");
+    $opt_valgrind= 1;
+  }
+
+  if ( $opt_valgrind )
+  {
+    # Set valgrind_options to default unless already defined
+    $opt_valgrind_options=$default_valgrind_options
+      unless defined $opt_valgrind_options;
+
+    mtr_report("Running valgrind with options \"$opt_valgrind_options\"");
   }
 
   if ( ! $opt_testcase_timeout )
@@ -1032,7 +1056,9 @@
                                            # New CMake locations.
                                            "$glob_basedir/client/release",
                                            "$glob_basedir/client/debug");
-      $exe_mysqld=         mtr_exe_exists ("$path_client_bindir/mysqld-nt",
+      $exe_mysqld=         mtr_exe_exists ("$path_client_bindir/mysqld-max-nt",
+                                           "$path_client_bindir/mysqld-max",
+                                           "$path_client_bindir/mysqld-nt",
                                            "$path_client_bindir/mysqld",
                                            "$path_client_bindir/mysqld-debug",
                                            "$path_client_bindir/mysqld-max",
@@ -1775,12 +1801,12 @@
 
   mtr_print_thick_line();
 
-  mtr_report("Finding  Tests in the '$suite' suite");
-
   mtr_timer_start($glob_timers,"suite", 60 * $opt_suite_timeout);
 
   mtr_report("Starting Tests in the '$suite' suite");
 
+  mtr_report_tests_not_skipped_though_disabled($tests);
+
   mtr_print_header();
 
   foreach my $tinfo ( @$tests )
@@ -1943,6 +1969,7 @@
   mtr_add_arg($args, "--skip-innodb");
   mtr_add_arg($args, "--skip-ndbcluster");
   mtr_add_arg($args, "--skip-bdb");
+  mtr_add_arg($args, "--tmpdir=.");
 
   if ( ! $opt_netware )
   {
@@ -3102,22 +3129,58 @@
 
   # Try graceful shutdown.
 
+  mtr_debug("IM-main pid: $instance_manager->{'pid'}");
+  mtr_debug("Stopping IM-main...");
+
   mtr_kill_process($instance_manager->{'pid'}, 'TERM', 10, 1);
 
+  # If necessary, wait for angel process to die.
+
+  if (defined $instance_manager->{'angel_pid'})
+  {
+    mtr_debug("IM-angel pid: $instance_manager->{'angel_pid'}");
+    mtr_debug("Waiting for IM-angel to die...");
+
+    my $total_attempts= 10;
+
+    for (my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt)
+    {
+      unless (kill (0, $instance_manager->{'angel_pid'}))
+      {
+        mtr_debug("IM-angel died.");
+        last;
+      }
+
+      sleep(1);
+    }
+  }
+
   # Check that all processes died.
 
   my $clean_shutdown= 0;
 
   while (1)
   {
-    last if kill (0, $instance_manager->{'pid'});
+    if (kill (0, $instance_manager->{'pid'}))
+    {
+      mtr_debug("IM-main is still alive.");
+      last;
+    }
 
-    last if (defined $instance_manager->{'angel_pid'}) &&
-            kill (0, $instance_manager->{'angel_pid'});
+    if (defined $instance_manager->{'angel_pid'} &&
+        kill (0, $instance_manager->{'angel_pid'}))
+    {
+      mtr_debug("IM-angel is still alive.");
+      last;
+    }
 
     foreach my $pid (@mysqld_pids)
     {
-      last if kill (0, $pid);
+      if (kill (0, $pid))
+      {
+        mtr_debug("Guarded mysqld ($pid) is still alive.");
+        last;
+      }
     }
 
     $clean_shutdown= 1;
@@ -3128,15 +3191,21 @@
 
   unless ($clean_shutdown)
   {
-    mtr_kill_process($instance_manager->{'angel_pid'}, 'KILL', 10, 1)
-      if defined $instance_manager->{'angel_pid'};
+
+    if (defined $instance_manager->{'angel_pid'})
+    {
+      mtr_debug("Killing IM-angel...");
+      mtr_kill_process($instance_manager->{'angel_pid'}, 'KILL', 10, 1)
+    }
     
+    mtr_debug("Killing IM-main...");
     mtr_kill_process($instance_manager->{'pid'}, 'KILL', 10, 1);
 
     # Shutdown managed mysqld-processes. Some of them may be nonguarded, so IM
     # will not stop them on shutdown. So, we should firstly try to end them
     # legally.
 
+    mtr_debug("Killing guarded mysqld(s)...");
     mtr_kill_processes(\@mysqld_pids);
 
     # Complain in error log so that a warning will be shown.
@@ -3211,9 +3280,16 @@
 }
 
 
+sub generate_cmdline_mysqldump ($) {
+  my($info) = @_;
+  return
+    "$exe_mysqldump --no-defaults -uroot " .
+      "--port=$info->[0]->{'path_myport'} " .
+        "--socket=$info->[0]->{'path_mysock'} --password=";
+}
+
 sub run_mysqltest ($) {
   my $tinfo=       shift;
-
   my $cmdline_mysqlcheck= "$exe_mysqlcheck --no-defaults -uroot " .
                           "--port=$master->[0]->{'path_myport'} " .
                           "--socket=$master->[0]->{'path_mysock'} --password=";
@@ -3223,17 +3299,15 @@
       " --debug=d:t:A,$opt_vardir_trace/log/mysqlcheck.trace";
   }
 
-  my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " .
-                         "--port=$master->[0]->{'path_myport'} " .
-                         "--socket=$master->[0]->{'path_mysock'} --password=";
-
- my $cmdline_mysqldumpslave= "$exe_mysqldump --no-defaults -uroot " .
-                         "--socket=$slave->[0]->{'path_mysock'} --password=";
+  my $cmdline_mysqldump= generate_cmdline_mysqldump $master;
+  my $cmdline_mysqldumpslave= generate_cmdline_mysqldump $slave;
 
   if ( $opt_debug )
   {
     $cmdline_mysqldump .=
-      " --debug=d:t:A,$opt_vardir_trace/log/mysqldump.trace";
+      " --debug=d:t:A,$opt_vardir_trace/log/mysqldump-master.trace";
+    $cmdline_mysqldumpslave .=
+      " --debug=d:t:A,$opt_vardir_trace/log/mysqldump-slave.trace";
   }
 
   my $cmdline_mysqlslap;
@@ -3290,6 +3364,12 @@
     "--port=$master->[0]->{'path_myport'} " .
     "--socket=$master->[0]->{'path_mysock'}";
 
+  if ( $opt_debug )
+  {
+    $cmdline_mysql_client_test .=
+      " --debug=d:t:A,$opt_vardir_trace/log/mysql_client_test.trace";
+  }
+
   if ( $glob_use_embedded_server )
   {
     $cmdline_mysql_client_test.=
@@ -3687,17 +3767,8 @@
   mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)
     if -f "$glob_mysql_test_dir/valgrind.supp";
 
-  if ( $opt_valgrind_all )
-  {
-    mtr_add_arg($args, "-v");
-    mtr_add_arg($args, "--show-reachable=yes");
-  }
-
-  if ( $opt_valgrind_options )
-  {
-    mtr_add_arg($args, '%s', $_) for (split(' ', $opt_valgrind_options));
-  }
-
+  # Add valgrind options, can be overriden by user
+  mtr_add_arg($args, '%s', $_) for (split(' ', $opt_valgrind_options));
 
   mtr_add_arg($args, $$exe);
 
@@ -3712,6 +3783,13 @@
 ##############################################################################
 
 sub usage ($) {
+  my $message= shift;
+
+  if ( $message )
+  {
+    print STDERR "$message \n";
+  }
+
   print STDERR <<HERE;
 
 mysql-test-run [ OPTIONS ] [ TESTCASE ]
@@ -3802,12 +3880,11 @@
   gcov                  FIXME
   gprof                 FIXME
   valgrind              Run the "mysqltest" and "mysqld" executables using
-                        valgrind
-  valgrind-all          Same as "valgrind" but will also add "verbose" and
-                        "--show-reachable" flags to valgrind
+                        valgrind with options($default_valgrind_options)
+  valgrind-all          Synonym for --valgrind
   valgrind-mysqltest    Run the "mysqltest" executable with valgrind
   valgrind-mysqld       Run the "mysqld" executable with valgrind
-  valgrind-options=ARGS Extra options to give valgrind
+  valgrind-options=ARGS Options to give valgrind, replaces default options
   valgrind-path=[EXE]   Path to the valgrind executable
 
 Misc options

--- 1.169/mysql-test/r/innodb.result	2006-08-06 02:11:48 +10:00
+++ 1.170/mysql-test/r/innodb.result	2006-08-06 02:11:48 +10:00
@@ -1378,9 +1378,9 @@
 create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb;
 insert into `t3`values ( 1 ) ;
 delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`))
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`))
 update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7  where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`))
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`))
 update t3 set  t3.id=7  where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
 ERROR 42S22: Unknown column 't1.id' in 'where clause'
 drop table t3,t2,t1;
@@ -1392,7 +1392,7 @@
 insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6),
 (8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14);
 delete from t1 where id=0;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `t1` (`id`) ON DELETE CASCADE)
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `t1` (`id`) ON DELETE CASCADE)
 delete from t1 where id=15;
 delete from t1 where id=0;
 drop table t1;
@@ -2633,18 +2633,18 @@
 CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id)
 ) ENGINE=InnoDB;
 INSERT INTO t2 VALUES(2);
-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
 INSERT INTO t1 VALUES(1);
 INSERT INTO t2 VALUES(1);
 DELETE FROM t1 WHERE id = 1;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
 DROP TABLE t1;
 ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
 SET FOREIGN_KEY_CHECKS=0;
 DROP TABLE t1;
 SET FOREIGN_KEY_CHECKS=1;
 INSERT INTO t2 VALUES(3);
-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
 DROP TABLE t2;
 create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
 insert into t1 values (1),(2);
@@ -2922,23 +2922,23 @@
 insert into t1 values(1);
 insert into t3 values(1);
 insert into t2 values(2);
-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
 insert into t4 values(2);
-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
 insert into t2 values(1);
 insert into t4 values(1);
 update t1 set a=2;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
 update t2 set a=2;
-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
 update t3 set a=2;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
 update t4 set a=2;
-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
 truncate t1;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
 truncate t3;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
 truncate t2;
 truncate t4;
 truncate t1;
@@ -2993,7 +2993,7 @@
 create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb;
 insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42);
 insert into t2 values(0x42);
-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
 insert into t2 values(0x41);
 select hex(s1) from t2;
 hex(s1)
@@ -3003,11 +3003,11 @@
 hex(s1)
 4100
 update t1 set s1=0x12 where a=1;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
 update t1 set s1=0x12345678 where a=1;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
 update t1 set s1=0x123457 where a=1;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
 update t1 set s1=0x1220 where a=1;
 select hex(s1) from t2;
 hex(s1)
@@ -3021,11 +3021,11 @@
 hex(s1)
 4200
 delete from t1 where a=1;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
 delete from t1 where a=2;
 update t2 set s1=0x4120;
 delete from t1;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
 delete from t1 where a!=3;
 select a,hex(s1) from t1;
 a	hex(s1)
@@ -3051,7 +3051,7 @@
 12
 delete from t1 where a=1;
 delete from t1 where a=2;
-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
 select a,hex(s1) from t1;
 a	hex(s1)
 2	12

--- 1.135/mysql-test/t/innodb.test	2006-08-06 02:11:48 +10:00
+++ 1.136/mysql-test/t/innodb.test	2006-08-06 02:11:48 +10:00
@@ -2510,3 +2510,16 @@
 INSERT INTO t1 VALUES (1);
 OPTIMIZE TABLE t1;
 DROP TABLE t1;
+
+#######################################################################
+#                                                                     #
+# Please, DO NOT TOUCH this file as well as the innodb.result file.   #
+# These files are to be modified ONLY BY INNOBASE guys.               #
+#                                                                     #
+# Use innodb_mysql.[test|result] files instead.                       #
+#                                                                     #
+# If nevertheless you need to make some changes here, please, forward #
+# your commit message To: dev@stripped Cc: dev-innodb@stripped     #
+# (otherwise your changes may be erased).                             #
+#                                                                     #
+#######################################################################

--- 1.264/sql/ha_innodb.cc	2006-08-06 02:11:48 +10:00
+++ 1.265/sql/ha_innodb.cc	2006-08-06 02:11:48 +10:00
@@ -42,6 +42,8 @@
 
 #define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1))
 
+#ifdef WITH_INNOBASE_STORAGE_ENGINE
+
 #include "ha_innodb.h"
 
 pthread_mutex_t innobase_share_mutex,	/* to protect innobase_open_files */
@@ -133,6 +135,7 @@
 #include "../storage/innobase/include/fil0fil.h"
 #include "../storage/innobase/include/trx0xa.h"
 #include "../storage/innobase/include/thr0loc.h"
+#include "../storage/innobase/include/ha_prototypes.h"
 }
 
 #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */
@@ -202,15 +205,15 @@
 static int innobase_rollback_to_savepoint(THD* thd, void *savepoint);
 static int innobase_savepoint(THD* thd, void *savepoint);
 static int innobase_release_savepoint(THD* thd, void *savepoint);
-static handler *innobase_create_handler(TABLE_SHARE *table);
+static handler *innobase_create_handler(TABLE_SHARE *table,
+                                        MEM_ROOT *mem_root);
 
 static const char innobase_hton_name[]= "InnoDB";
-
 handlerton innobase_hton;
 
-static handler *innobase_create_handler(TABLE_SHARE *table)
+static handler *innobase_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
 {
-  return new ha_innobase(table);
+  return new (mem_root) ha_innobase(table);
 }
 
 
@@ -666,6 +669,61 @@
 }
 
 /**********************************************************************
+Converts an identifier to a table name.
+
+NOTE that the exact prototype of this function has to be in
+/innobase/dict/dict0dict.c! */
+extern "C"
+void
+innobase_convert_from_table_id(
+/*===========================*/
+	char*		to,	/* out: converted identifier */
+	const char*	from,	/* in: identifier to convert */
+	ulint		len)	/* in: length of 'to', in bytes */
+{
+	uint	errors;
+
+	strconvert(current_thd->charset(), from,
+		   &my_charset_filename, to, len, &errors);
+}
+
+/**********************************************************************
+Converts an identifier to UTF-8.
+
+NOTE that the exact prototype of this function has to be in
+/innobase/dict/dict0dict.c! */
+extern "C"
+void
+innobase_convert_from_id(
+/*=====================*/
+	char*		to,	/* out: converted identifier */
+	const char*	from,	/* in: identifier to convert */
+	ulint		len)	/* in: length of 'to', in bytes */
+{
+	uint	errors;
+
+	strconvert(current_thd->charset(), from,
+		   system_charset_info, to, len, &errors);
+}
+
+/**********************************************************************
+Removes the filename encoding of a table or database name.
+
+NOTE that the exact prototype of this function has to be in
+/innobase/dict/dict0dict.c! */
+extern "C"
+void
+innobase_convert_from_filename(
+/*===========================*/
+	char*		s)	/* in: identifier; out: decoded identifier */
+{
+	uint	errors;
+
+	strconvert(&my_charset_filename, s,
+		   system_charset_info, s, strlen(s), &errors);
+}
+
+/**********************************************************************
 Compares NUL-terminated UTF-8 strings case insensitively.
 
 NOTE that the exact prototype of this function has to be in
@@ -695,6 +753,21 @@
 	my_casedn_str(system_charset_info, a);
 }
 
+/**************************************************************************
+Determines the connection character set.
+
+NOTE that the exact prototype of this function has to be in
+/innobase/dict/dict0dict.c! */
+extern "C"
+struct charset_info_st*
+innobase_get_charset(
+/*=================*/
+				/* out: connection character set */
+	void*	mysql_thd)	/* in: MySQL thread handle */
+{
+	return(((THD*) mysql_thd)->charset());
+}
+
 /*************************************************************************
 Creates a temporary file. */
 extern "C"
@@ -741,6 +814,25 @@
 }
 
 /*************************************************************************
+Wrapper around MySQL's copy_and_convert function, see it for
+documentation. */
+extern "C"
+ulint
+innobase_convert_string(
+/*====================*/
+	void*		to,
+	ulint		to_length,
+	CHARSET_INFO*	to_cs,
+	const void*	from,
+	ulint		from_length,
+	CHARSET_INFO*	from_cs,
+	uint*		errors)
+{
+	return(copy_and_convert((char*)to, to_length, to_cs,
+		       (const char*)from, from_length, from_cs, errors));
+}
+
+/*************************************************************************
 Gets the InnoDB transaction handle for a MySQL handler object, creates
 an InnoDB transaction struct if the corresponding MySQL thread struct still
 lacks one. */
@@ -803,10 +895,9 @@
 		  HA_NULL_IN_KEY |
 		  HA_CAN_INDEX_BLOBS |
 		  HA_CAN_SQL_HANDLER |
-		  HA_NOT_EXACT_COUNT |
-		  HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS |
+		  HA_PRIMARY_KEY_REQUIRED_FOR_POSITION |
 		  HA_PRIMARY_KEY_IN_READ_INDEX |
-		  HA_CAN_GEOMETRY |
+		  HA_CAN_GEOMETRY | HA_PARTIAL_COLUMN_READ |
 		  HA_TABLE_SCAN_ON_INDEX),
   start_of_scan(0),
   num_write_row(0)
@@ -1075,23 +1166,69 @@
 }
 
 /*********************************************************************
-Get the quote character to be used in SQL identifiers.
+Display an SQL identifier.
 This definition must match the one in innobase/ut/ut0ut.c! */
 extern "C"
-int
-mysql_get_identifier_quote_char(
-/*============================*/
-				/* out: quote character to be
-				used in SQL identifiers; EOF if none */
+void
+innobase_print_identifier(
+/*======================*/
+	FILE*		f,	/* in: output stream */
 	trx_t*		trx,	/* in: transaction */
+	ibool		table_id,/* in: TRUE=decode table name */
 	const char*	name,	/* in: name to print */
 	ulint		namelen)/* in: length of name */
 {
+	const char*	s	= name;
+	char*		qname	= NULL;
+	int		q;
+
+	if (table_id) {
+		/* Decode the table name.  The filename_to_tablename()
+		function expects a NUL-terminated string.  The input and
+		output strings buffers must not be shared.  The function
+		only produces more output when the name contains other
+		characters than [0-9A-Z_a-z]. */
+		char*	temp_name = my_malloc(namelen + 1, MYF(MY_WME));
+		uint	qnamelen = namelen
+				+ (1 + sizeof srv_mysql50_table_name_prefix);
+
+		if (temp_name) {
+			qname = my_malloc(qnamelen, MYF(MY_WME));
+			if (qname) {
+				memcpy(temp_name, name, namelen);
+				temp_name[namelen] = 0;
+				s = qname;
+				namelen = filename_to_tablename(temp_name,
+						qname, qnamelen);
+			}
+			my_free(temp_name, MYF(0));
+		}
+	}
+
 	if (!trx || !trx->mysql_thd) {
-		return(EOF);
+
+		q = '"';
+	} else {
+		q = get_quote_char_for_identifier((THD*) trx->mysql_thd,
+						s, (int) namelen);
+	}
+
+	if (q == EOF) {
+		fwrite(s, 1, namelen, f);
+	} else {
+		const char*	e = s + namelen;
+		putc(q, f);
+		while (s < e) {
+			int	c = *s++;
+			if (c == q) {
+				putc(c, f);
+			}
+			putc(c, f);
+		}
+		putc(q, f);
 	}
-	return(get_quote_char_for_identifier((THD*) trx->mysql_thd,
-						name, (int) namelen));
+
+	my_free(qname, MYF(MY_ALLOW_ZERO_PTR));
 }
 
 /**************************************************************************
@@ -1231,6 +1368,24 @@
 
 	ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
 
+#ifdef UNIV_DEBUG
+	static const char	test_filename[] = "-@";
+	char			test_tablename[sizeof test_filename
+				+ sizeof srv_mysql50_table_name_prefix];
+	if ((sizeof test_tablename) - 1
+			!= filename_to_tablename(test_filename, test_tablename,
+			sizeof test_tablename)
+			|| strncmp(test_tablename,
+			srv_mysql50_table_name_prefix,
+			sizeof srv_mysql50_table_name_prefix)
+			|| strcmp(test_tablename
+			+ sizeof srv_mysql50_table_name_prefix,
+			test_filename)) {
+		sql_print_error("tablename encoding has been changed");
+		goto error;
+	}
+#endif /* UNIV_DEBUG */
+
 	/* Check that values don't overflow on 32-bit systems. */
 	if (sizeof(ulint) == 4) {
 		if (innobase_buffer_pool_size > UINT_MAX32) {
@@ -2199,8 +2354,7 @@
 
 	/* Get pointer to a table object in InnoDB dictionary cache */
 
-	ib_table = dict_table_get_and_increment_handle_count(
-		norm_name, NULL);
+	ib_table = dict_table_get_and_increment_handle_count(norm_name);
 
 	if (NULL == ib_table) {
 		ut_print_timestamp(stderr);
@@ -2306,7 +2460,7 @@
 		}
 	}
 
-	block_size = 16 * 1024;	/* Index block size in InnoDB: used by MySQL
+	stats.block_size = 16 * 1024;	/* Index block size in InnoDB: used by MySQL
 				in query optimization */
 
 	/* Init table lock structure */
@@ -2901,16 +3055,15 @@
 /******************************************************************
 Builds a 'template' to the prebuilt struct. The template is used in fast
 retrieval of just those column values MySQL needs in its processing. */
-static
 void
-build_template(
+ha_innobase::build_template(
 /*===========*/
 	row_prebuilt_t*	prebuilt,	/* in: prebuilt struct */
 	THD*		thd,		/* in: current user thread, used
 					only if templ_type is
 					ROW_MYSQL_REC_FIELDS */
 	TABLE*		table,		/* in: MySQL table */
-	ulint		templ_type)	/* in: ROW_MYSQL_WHOLE_ROW or
+	uint		templ_type)	/* in: ROW_MYSQL_WHOLE_ROW or
 					ROW_MYSQL_REC_FIELDS */
 {
 	dict_index_t*	index;
@@ -3019,8 +3172,8 @@
 				goto include_field;
 			}
 
-			if (table->file->ha_get_bit_in_read_set(i+1) ||
-				table->file->ha_get_bit_in_write_set(i+1)) {
+                        if (bitmap_is_set(table->read_set, i) ||
+                            bitmap_is_set(table->write_set, i)) {
 				/* This field is needed in the query */
 
 				goto include_field;
@@ -4116,6 +4269,9 @@
 	mysql_byte*	buf)	/* in/out: buffer for previous row in MySQL
 				format */
 {
+	statistic_increment(current_thd->status_var.ha_read_prev_count,
+		&LOCK_status);
+
 	return(general_fetch(buf, ROW_SEL_PREV, 0));
 }
 
@@ -4652,7 +4808,7 @@
 	/* Get the transaction associated with the current thd, or create one
 	if not yet created */
 
-	parent_trx = check_trx_exists(current_thd);
+	parent_trx = check_trx_exists(thd);
 
 	/* In case MySQL calls this in the middle of a SELECT query, release
 	possible adaptive hash latch to avoid deadlocks of threads */
@@ -4748,20 +4904,9 @@
 		}
 	}
 
-	if (current_thd->query != NULL) {
-		LEX_STRING q;
-
-		if (thd->convert_string(&q, system_charset_info,
-					current_thd->query,
-					current_thd->query_length,
-					current_thd->charset())) {
-			error = HA_ERR_OUT_OF_MEM;
-
-			goto cleanup;
-		}
-
+	if (thd->query != NULL) {
 		error = row_table_add_foreign_constraints(trx,
-			q.str, norm_name,
+			thd->query, norm_name,
 			create_info->options & HA_LEX_CREATE_TMP_TABLE);
 
 		error = convert_error_code_to_mysql(error, NULL);
@@ -4781,7 +4926,7 @@
 
 	log_buffer_flush_to_disk();
 
-	innobase_table = dict_table_get(norm_name, NULL);
+	innobase_table = dict_table_get(norm_name);
 
 	DBUG_ASSERT(innobase_table != 0);
 
@@ -4917,7 +5062,7 @@
 	/* Get the transaction associated with the current thd, or create one
 	if not yet created */
 
-	parent_trx = check_trx_exists(current_thd);
+	parent_trx = check_trx_exists(thd);
 
 	/* In case MySQL calls this in the middle of a SELECT query, release
 	possible adaptive hash latch to avoid deadlocks of threads */
@@ -5404,7 +5549,7 @@
 		nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
 
 		if (os_file_get_status(path,&stat_info)) {
-			create_time = stat_info.ctime;
+			stats.create_time = stat_info.ctime;
 		}
 	}
 
@@ -5432,21 +5577,21 @@
 			n_rows++;
 		}
 
-		records = (ha_rows)n_rows;
-		deleted = 0;
-		data_file_length = ((ulonglong)
+		stats.records = (ha_rows)n_rows;
+		stats.deleted = 0;
+		stats.data_file_length = ((ulonglong)
 				ib_table->stat_clustered_index_size)
 					* UNIV_PAGE_SIZE;
-		index_file_length = ((ulonglong)
+		stats.index_file_length = ((ulonglong)
 				ib_table->stat_sum_of_other_index_sizes)
 					* UNIV_PAGE_SIZE;
-		delete_length = 0;
-		check_time = 0;
+		stats.delete_length = 0;
+		stats.check_time = 0;
 
-		if (records == 0) {
-			mean_rec_length = 0;
+		if (stats.records == 0) {
+			stats.mean_rec_length = 0;
 		} else {
-			mean_rec_length = (ulong) (data_file_length / records);
+			stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
 		}
 	}
 
@@ -5495,9 +5640,9 @@
 
 				if (index->stat_n_diff_key_vals[j + 1] == 0) {
 
-					rec_per_key = records;
+					rec_per_key = stats.records;
 				} else {
-					rec_per_key = (ha_rows)(records /
+					rec_per_key = (ha_rows)(stats.records /
 					 index->stat_n_diff_key_vals[j + 1]);
 				}
 
@@ -5552,7 +5697,7 @@
 			}
 		}
 
-		auto_increment_value = auto_inc;
+		stats.auto_increment_value = auto_inc;
 	}
 
 	prebuilt->trx->op_info = (char*)"";
@@ -5947,8 +6092,7 @@
 /*===============*/
 			   /* out: 0 or error number */
 	enum ha_extra_function operation)
-			   /* in: HA_EXTRA_RETRIEVE_ALL_COLS or some
-			   other flag */
+			   /* in: HA_EXTRA_FLUSH or some other flag */
 {
 	row_prebuilt_t*	prebuilt = (row_prebuilt_t*) innobase_prebuilt;
 
@@ -5962,13 +6106,6 @@
 				row_mysql_prebuilt_free_blob_heap(prebuilt);
 			}
 			break;
-		case HA_EXTRA_RESET:
-			if (prebuilt->blob_heap) {
-				row_mysql_prebuilt_free_blob_heap(prebuilt);
-			}
-			prebuilt->keep_other_fields_on_keyread = 0;
-			prebuilt->read_just_key = 0;
-			break;
 		case HA_EXTRA_RESET_STATE:
 			prebuilt->keep_other_fields_on_keyread = 0;
 			prebuilt->read_just_key = 0;
@@ -5976,16 +6113,6 @@
 		case HA_EXTRA_NO_KEYREAD:
 			prebuilt->read_just_key = 0;
 			break;
-		case HA_EXTRA_RETRIEVE_ALL_COLS:
-			prebuilt->hint_need_to_fetch_extra_cols
-					= ROW_RETRIEVE_ALL_COLS;
-			break;
-		case HA_EXTRA_RETRIEVE_PRIMARY_KEY:
-			if (prebuilt->hint_need_to_fetch_extra_cols == 0) {
-				prebuilt->hint_need_to_fetch_extra_cols
-					= ROW_RETRIEVE_PRIMARY_KEY;
-			}
-			break;
 		case HA_EXTRA_KEYREAD:
 			prebuilt->read_just_key = 1;
 			break;
@@ -5999,6 +6126,18 @@
 	return(0);
 }
 
+int ha_innobase::reset()
+{
+  row_prebuilt_t*	prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+  if (prebuilt->blob_heap) {
+    row_mysql_prebuilt_free_blob_heap(prebuilt);
+  }
+  prebuilt->keep_other_fields_on_keyread = 0;
+  prebuilt->read_just_key = 0;
+  return 0;
+}
+
+
 /**********************************************************************
 MySQL calls this function at the start of each SQL statement inside LOCK
 TABLES. Inside LOCK TABLES the ::external_lock method does not work to
@@ -6771,17 +6910,28 @@
 		stored function call (MySQL does have thd->in_lock_tables
 		TRUE there). */
 
-		if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
-		&& lock_type <= TL_WRITE)
-		&& !(thd->in_lock_tables
-			&& thd->lex->sql_command == SQLCOM_LOCK_TABLES)
-		&& !thd->tablespace_op
-		&& thd->lex->sql_command != SQLCOM_TRUNCATE
-		&& thd->lex->sql_command != SQLCOM_OPTIMIZE
-		&& thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
+    		if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
+		    && lock_type <= TL_WRITE)
+		    && !(thd->in_lock_tables
+			    && thd->lex->sql_command == SQLCOM_LOCK_TABLES)
+		    && !thd->tablespace_op
+		    && thd->lex->sql_command != SQLCOM_TRUNCATE
+		    && thd->lex->sql_command != SQLCOM_OPTIMIZE
+#ifdef __WIN__
+                /* 
+                   for alter table on win32 for succesfull operation 
+                   completion it is used TL_WRITE(=10) lock instead of
+                   TL_WRITE_ALLOW_READ(=6), however here in innodb handler
+                   TL_WRITE is lifted to TL_WRITE_ALLOW_WRITE, which causes
+                   race condition when several clients do alter table 
+                   simultaneously (bug #17264). This fix avoids the problem.
+                */
+                    && thd->lex->sql_command != SQLCOM_ALTER_TABLE
+#endif
+		    && thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
 
 			lock_type = TL_WRITE_ALLOW_WRITE;
-		}
+      		}
 
 		/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
 		MySQL would use the lock TL_READ_NO_INSERT on t2, and that
@@ -6947,17 +7097,21 @@
 	return(error);
 }
 
-/***********************************************************************
+/*******************************************************************************
 This function initializes the auto-inc counter if it has not been
 initialized yet. This function does not change the value of the auto-inc
 counter if it already has been initialized. Returns the value of the
-auto-inc counter. */
+auto-inc counter in *first_value, and ULONGLONG_MAX in *nb_reserved_values (as
+we have a table-level lock). offset, increment, nb_desired_values are ignored.
+*first_value is set to -1 if error (deadlock or lock wait timeout)            */
 
-ulonglong
-ha_innobase::get_auto_increment()
-/*=============================*/
-			 /* out: auto-increment column value, -1 if error
-			 (deadlock or lock wait timeout) */
+void ha_innobase::get_auto_increment(
+/*=================================*/
+        ulonglong offset,              /* in */
+        ulonglong increment,           /* in */
+        ulonglong nb_desired_values,   /* in */
+        ulonglong *first_value,        /* out */
+        ulonglong *nb_reserved_values) /* out */
 {
 	longlong	nr;
 	int		error;
@@ -6972,10 +7126,13 @@
 		ut_print_timestamp(stderr);
 		sql_print_error("Error %lu in ::get_auto_increment()",
 				(ulong) error);
-		return(~(ulonglong) 0);
+                *first_value= (~(ulonglong) 0);
+		return;
 	}
 
-	return((ulonglong) nr);
+        *first_value= (ulonglong) nr;
+        /* table-level autoinc lock reserves up to +inf */
+        *nb_reserved_values= ULONGLONG_MAX;
 }
 
 /* See comment in handler.h */
@@ -7459,4 +7616,6 @@
   0
 }
 mysql_declare_plugin_end;
+
+#endif
 
Thread
bk commit into 5.2 tree (jon:1.2176)jon5 Aug