List:Commits« Previous MessageNext Message »
From:dlenev Date:October 31 2006 2:22pm
Subject:bk commit into 5.1 tree (dlenev:1.2321) BUG#22060
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of dlenev. When dlenev 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-10-31 16:22:23+03:00, dlenev@stripped +7 -0
  Proposed fix for bug #22060 "ALTER TABLE x AUTO_INCREMENT=y in SP
  crashes server".
  
  Re-execution of CREATE DATABASE, CREATE TABLE and ALTER TABLE 
  statements in stored routines or as prepared statements caused
  incorrect results (and crashes in versions before 5.0.25).
  (in 5.1 problem occured only for CREATE DATABASE, CREATE TABLE
  SELECT and CREATE TABLE with INDEX/DATA DIRECTOY options).
  
  The problem stemmed from the fact that code implementing these
  statements modified HA_CREATE_INFO structure in LEX (e.g. making
  it to point to areas in current memory root).
  
  Proposed patch solves this problem by creating and using on-stack
  copy of this structure (note that code in 5.1 already created and
  used copies this structure in mysql_create_table()/alter_table()
  routines but this approach didn't work well for CREATE TABLE
  SELECT statement).
  
  Note that this patch does not make CREATE/ALTER TABLE statements
  totally safe for re-execution. Their implementation still has some
  problems which are to be fixed during work on bugs 4968 and 19182.

  mysql-test/r/ps.result@stripped, 2006-10-31 16:22:19+03:00, dlenev@stripped +88 -0
    Added test for bug #22060 "ALTER TABLE x AUTO_INCREMENT=y in SP crashes server".

  mysql-test/t/ps.test@stripped, 2006-10-31 16:22:19+03:00, dlenev@stripped +71 -0
    Added test for bug #22060 "ALTER TABLE x AUTO_INCREMENT=y in SP crashes server".

  sql/mysql_priv.h@stripped, 2006-10-31 16:22:20+03:00, dlenev@stripped +2 -3
    mysql_create_table() no longer needs use_copy_create_info parameter
    since now it is responsibility of caller to create copy of HA_CREATE_INFO
    structure if it is necessary to ensure its PS-safety. 
    Added const qualifier to the 3rd mysqld_show_create_db()'s argument
    (HA_CREATE_INFO structure) in order to emphasize that this structure
    is not modified in this function.

  sql/sql_insert.cc@stripped, 2006-10-31 16:22:20+03:00, dlenev@stripped +1 -1
    mysql_create_table() no longer needs use_copy_create_info parameter
    since now it is responsibility of caller to create copy of HA_CREATE_INFO
    structure if it is necessary to ensure its PS-safety.

  sql/sql_parse.cc@stripped, 2006-10-31 16:22:20+03:00, dlenev@stripped +48 -21
    Since code which implements CREATE DATABASE, CREATE TABLE and
    ALTER TABLE statements (especially in mysql_create_table() and
    select_create methods) may modify HA_CREATE_INFO structure in LEX,
    we have to create and use copy of this structure to make these
    statements prepared statement/stored routine safe. Before this
    patch this copying happened inside of mysql_create_table() and 
    mysql_alter_table() routines but unfortunately such approach 
    didn't work well for CREATE TABLE SELECT statement (and CREATE
    TABLE with DATA/INDEX DIRECTORY option). So now this copying is
    done in callers of these routines (i.e. in part of
    mysql_execute_command() which is responsible for CREATE/ALTER
    TABLE processing).

  sql/sql_show.cc@stripped, 2006-10-31 16:22:20+03:00, dlenev@stripped +1 -1
    Added const qualifier to the 3rd mysqld_show_create_db()'s argument
    (HA_CREATE_INFO structure) in order to emphasize that this structure
    is not modified in this function.

  sql/sql_table.cc@stripped, 2006-10-31 16:22:20+03:00, dlenev@stripped +44 -64
    We no longer create copies of HA_CREATE_INFO structures inside
    of mysql_create_table()/create_table_like()/alter_table() functions
    as now it is responsibility of caller to create such copies if
    PS-safety required. This new approach works better than old one
    in cases when we want PS-safety on one hand but also need to use
    this structure as out parameter OTOH (for example for CREATE TABLE
    SELECT). It also more consistent with general approach that was
    chosen to make CREATE/ALTER TABLE PS-safe.

# 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:	dlenev
# Host:	mockturtle.local
# Root:	/home/dlenev/src/mysql-5.1-bg22060-3

--- 1.453/sql/mysql_priv.h	2006-10-31 16:22:29 +03:00
+++ 1.454/sql/mysql_priv.h	2006-10-31 16:22:29 +03:00
@@ -916,8 +916,7 @@
 bool mysql_create_table(THD *thd,const char *db, const char *table_name,
                         HA_CREATE_INFO *create_info,
                         List<create_field> &fields, List<Key> &keys,
-                        bool tmp_table, uint select_field_count,
-                        bool use_copy_create_info);
+                        bool tmp_table, uint select_field_count);
 
 bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
                        HA_CREATE_INFO *create_info,
@@ -1043,7 +1042,7 @@
 void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
 int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
 bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
-bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
+bool mysqld_show_create_db(THD *thd, char *dbname, const HA_CREATE_INFO *create);
 
 void mysqld_list_processes(THD *thd,const char *user,bool verbose);
 int mysqld_show_status(THD *thd);

--- 1.232/sql/sql_insert.cc	2006-10-31 16:22:29 +03:00
+++ 1.233/sql/sql_insert.cc	2006-10-31 16:22:29 +03:00
@@ -2884,7 +2884,7 @@
     tmp_disable_binlog(thd);
     if (!mysql_create_table(thd, create_table->db, create_table->table_name,
                             create_info, *extra_fields, *keys, 0,
-                            select_field_count, 0))
+                            select_field_count))
     {
       /*
         If we are here in prelocked mode we either create temporary table

--- 1.585/sql/sql_parse.cc	2006-10-31 16:22:29 +03:00
+++ 1.586/sql/sql_parse.cc	2006-10-31 16:22:29 +03:00
@@ -2884,17 +2884,27 @@
     // Skip first table, which is the table we are creating
     TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
     TABLE_LIST *select_tables= lex->query_tables;
+    HA_CREATE_INFO create_info;
 
     if ((res= create_table_precheck(thd, select_tables, create_table)))
       goto end_with_restore_list;
 
+    /*
+      Code below (especially in mysql_create_table() and select_create
+      methods) may modify HA_CREATE_INFO structure in LEX, so we have to
+      use copy of this structure to make execution prepared statement safe.
+      Shallow copy is enough as this code won't modify memory referenced
+      from this structure.
+    */
+    create_info= lex->create_info;
+
 #ifndef HAVE_READLINK
-    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
+    create_info.data_file_name= create_info.index_file_name= 0;
 #else
     /* Fix names if symlinked tables */
-    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
+    if (append_file_to_dir(thd, &create_info.data_file_name,
 			   create_table->table_name) ||
-	append_file_to_dir(thd, &lex->create_info.index_file_name,
+	append_file_to_dir(thd, &create_info.index_file_name,
 			   create_table->table_name))
       goto end_with_restore_list;
 #endif
@@ -2902,14 +2912,14 @@
       If we are using SET CHARSET without DEFAULT, add an implicit
       DEFAULT to not confuse old users. (This may change).
     */
-    if ((lex->create_info.used_fields & 
+    if ((create_info.used_fields &
 	 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
 	HA_CREATE_USED_CHARSET)
     {
-      lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
-      lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
-      lex->create_info.default_table_charset= lex->create_info.table_charset;
-      lex->create_info.table_charset= 0;
+      create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
+      create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+      create_info.default_table_charset= create_info.table_charset;
+      create_info.table_charset= 0;
     }
     /*
       The create-select command will open and read-lock the select table
@@ -2954,7 +2964,7 @@
           Is table which we are changing used somewhere in other parts
           of query
         */
-        if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+        if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
         {
           TABLE_LIST *duplicate;
           if ((duplicate= unique_table(thd, create_table, select_tables)))
@@ -2965,10 +2975,10 @@
           }
         }
         /* If we create merge table, we have to test tables in merge, too */
-        if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
+        if (create_info.used_fields & HA_CREATE_USED_UNION)
         {
           TABLE_LIST *tab;
-          for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
+          for (tab= (TABLE_LIST*) create_info.merge_list.first;
                tab;
                tab= tab->next_local)
           {
@@ -2983,7 +2993,7 @@
         }
 
         if ((result= new select_create(create_table,
-				       &lex->create_info,
+				       &create_info,
 				       lex->create_list,
 				       lex->key_list,
 				       select_lex->item_list,
@@ -3005,18 +3015,18 @@
     else
     {
       /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
-      if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+      if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
         thd->options|= OPTION_KEEP_LOG;
       /* regular create */
       if (lex->like_name)
-        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
+        res= mysql_create_like_table(thd, create_table, &create_info,
                                      lex->like_name); 
       else
       {
         res= mysql_create_table(thd, create_table->db,
-				create_table->table_name, &lex->create_info,
+				create_table->table_name, &create_info,
 				lex->create_list,
-				lex->key_list, 0, 0, 1);
+				lex->key_list, 0, 0);
       }
       if (!res)
 	send_ok(thd);
@@ -3083,6 +3093,7 @@
     {
       ulong priv=0;
       ulong priv_needed= ALTER_ACL;
+      HA_CREATE_INFO create_info;
       /* We also require DROP priv for ALTER TABLE ... DROP PARTITION */
       if (lex->alter_info.flags & ALTER_DROP_PARTITION)
         priv_needed|= DROP_ACL;
@@ -3119,14 +3130,22 @@
 	    goto error;
 	}
       }
+      /*
+        Code in mysql_alter_table() may modify HA_CREATE_INFO structure
+        in LEX, so we have to use copy of this structure to make execution
+        prepared statement safe.
+        Shallow copy is enough as memory referenced from this structure
+        won't be modified.
+      */
+      create_info= lex->create_info;
       /* Don't yet allow changing of symlinks with ALTER TABLE */
-      if (lex->create_info.data_file_name)
+      if (create_info.data_file_name)
         push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                      "DATA DIRECTORY option ignored");
-      if (lex->create_info.index_file_name)
+      if (create_info.index_file_name)
         push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                      "INDEX DIRECTORY option ignored");
-      lex->create_info.data_file_name=lex->create_info.index_file_name=0;
+      create_info.data_file_name= create_info.index_file_name= 0;
       /* ALTER TABLE ends previous transaction */
       if (end_active_trans(thd))
 	goto error;
@@ -3140,7 +3159,7 @@
 
       thd->enable_slow_log= opt_log_slow_admin_statements;
       res= mysql_alter_table(thd, select_lex->db, lex->name,
-                             &lex->create_info,
+                             &create_info,
                              first_table, lex->create_list,
                              lex->key_list,
                              select_lex->order_list.elements,
@@ -3726,6 +3745,8 @@
     break;
   case SQLCOM_CREATE_DB:
   {
+    HA_CREATE_INFO create_info;
+
     if (end_active_trans(thd))
     {
       res= -1;
@@ -3755,8 +3776,14 @@
 #endif
     if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
       break;
+    /*
+      As mysql_create_db() may modify HA_CREATE_INFO structure passed to
+      it, we need to use copy of LEX::create_info to make execution prepared
+      statement safe.
+    */
+    create_info= lex->create_info;
     res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
-			 &lex->create_info, 0);
+			 &create_info, 0);
     break;
   }
   case SQLCOM_DROP_DB:

--- 1.367/sql/sql_show.cc	2006-10-31 16:22:29 +03:00
+++ 1.368/sql/sql_show.cc	2006-10-31 16:22:30 +03:00
@@ -693,7 +693,7 @@
 }
 
 bool mysqld_show_create_db(THD *thd, char *dbname,
-                           HA_CREATE_INFO *create_info)
+                           const HA_CREATE_INFO *create_info)
 {
   Security_context *sctx= thd->security_ctx;
   int length;

--- 1.368/sql/sql_table.cc	2006-10-31 16:22:30 +03:00
+++ 1.369/sql/sql_table.cc	2006-10-31 16:22:30 +03:00
@@ -3136,31 +3136,6 @@
 
 
 /*
-  Copy HA_CREATE_INFO struct
-  SYNOPSIS
-    copy_create_info()
-    lex_create_info         The create_info struct setup by parser
-  RETURN VALUES
-    > 0                     A pointer to a copy of the lex_create_info
-    0                       Memory allocation error
-  DESCRIPTION
-  Allocate memory for copy of HA_CREATE_INFO structure from parser
-  to ensure we can reuse the parser struct in stored procedures
-  and prepared statements.
-*/
-
-static HA_CREATE_INFO *copy_create_info(HA_CREATE_INFO *lex_create_info)
-{
-  HA_CREATE_INFO *create_info;
-  if (!(create_info= (HA_CREATE_INFO*)sql_alloc(sizeof(HA_CREATE_INFO))))
-    mem_alloc_error(sizeof(HA_CREATE_INFO));
-  else
-    memcpy((void*)create_info, (void*)lex_create_info, sizeof(HA_CREATE_INFO));
-  return create_info;
-}
-
-
-/*
   Create a table
 
   SYNOPSIS
@@ -3168,15 +3143,12 @@
     thd			Thread object
     db			Database
     table_name		Table name
-    lex_create_info	Create information (like MAX_ROWS)
+    create_info         Create information (like MAX_ROWS)
     fields		List of fields to create
     keys		List of keys to create
     internal_tmp_table  Set to 1 if this is an internal temporary table
 			(From ALTER TABLE)
     select_field_count  
-    use_copy_create_info Should we make a copy of create info (we do this
-                         when this is called from sql_parse.cc where we
-                         want to ensure lex object isn't manipulated.
 
   DESCRIPTION
     If one creates a temporary table, this is automatically opened
@@ -3186,6 +3158,10 @@
     select_field_count is also used for CREATE ... SELECT,
     and must be zero for standard create of table.
 
+    Note that structure passed as 'create_info' parameter may be modified by
+    this function. It is responsibility of caller to make its copies in order
+    to provide correct execution in prepared statements/stored routines.
+
   RETURN VALUES
     FALSE OK
     TRUE  error
@@ -3193,34 +3169,22 @@
 
 bool mysql_create_table_internal(THD *thd,
                                 const char *db, const char *table_name,
-                                HA_CREATE_INFO *lex_create_info,
+                                HA_CREATE_INFO *create_info,
                                 List<create_field> &fields,
                                 List<Key> &keys,bool internal_tmp_table,
-                                uint select_field_count,
-                                bool use_copy_create_info)
+                                uint select_field_count)
 {
   char		path[FN_REFLEN];
   uint          path_length;
   const char	*alias;
   uint		db_options, key_count;
   KEY		*key_info_buffer;
-  HA_CREATE_INFO *create_info;
   handler	*file;
   bool		error= TRUE;
   DBUG_ENTER("mysql_create_table_internal");
   DBUG_PRINT("enter", ("db: '%s'  table: '%s'  tmp: %d",
                        db, table_name, internal_tmp_table));
 
-  if (use_copy_create_info)
-  {
-    if (!(create_info= copy_create_info(lex_create_info)))
-    {
-      DBUG_RETURN(TRUE);
-    }
-  }
-  else
-    create_info= lex_create_info;
- 
   /* Check for duplicate fields and check type of table to create */
   if (!fields.elements)
   {
@@ -3562,8 +3526,7 @@
                         HA_CREATE_INFO *create_info,
                         List<create_field> &fields,
                         List<Key> &keys,bool internal_tmp_table,
-                        uint select_field_count,
-                        bool use_copy_create_info)
+                        uint select_field_count)
 {
   bool result;
   DBUG_ENTER("mysql_create_table");
@@ -3587,8 +3550,7 @@
 
   result= mysql_create_table_internal(thd, db, table_name, create_info,
                                       fields, keys, internal_tmp_table,
-                                      select_field_count,
-                                      use_copy_create_info);
+                                      select_field_count);
 
   pthread_mutex_lock(&LOCK_lock_db);
   if (!--creating_table && creating_database)
@@ -4568,7 +4530,7 @@
 */
 
 bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
-                             HA_CREATE_INFO *lex_create_info,
+                             HA_CREATE_INFO *create_info,
                              Table_ident *table_ident)
 {
   TABLE *tmp_table;
@@ -4581,15 +4543,10 @@
   int  err;
   bool res= TRUE;
   enum legacy_db_type not_used;
-  HA_CREATE_INFO *create_info;
 
   TABLE_LIST src_tables_list;
   DBUG_ENTER("mysql_create_like_table");
 
-  if (!(create_info= copy_create_info(lex_create_info)))
-  {
-    DBUG_RETURN(TRUE);
-  }
   DBUG_ASSERT(table_ident->db.str); /* Must be set in the parser */
   src_db= table_ident->db.str;
 
@@ -5132,11 +5089,38 @@
 
 
 /*
-  Alter table
+  Alter table's definition.
+
+  SYNOPSIS
+    mysql_alter_table()
+      thd          Thread object
+      new_db       New database for table
+      new_name     New name for table
+      create_info  Create informaton (like MAX_ROWS or COMMENT)
+      table_list   Element of table list for table to be altered
+      fields       List of fields to be modified or added
+      keys         List of keys to be added
+      order_num    Number of order list elements
+      order        Order list
+      ignore       TRUE - if non-fatal errors which occur during
+                   copying of data between old and new versions
+                   of table must be ignored (for example duplicate
+                   key errors). FALSE - otherwise.
+      alter_info   Structure which describes alter operation (partially)
+      do_send_ok   TRUE  - if ok packet should be suppressed
+                   FALSE - otherwise
+
+  NOTE
+    Note that structure passed as 'create_info' parameter may be modified by
+    this function. It is responsibility of caller to make its copies in order
+    to provide correct execution in prepared statements/stored routines.
+
+  RETURN VALUE
+    FALSE/TRUE - Success/Failure
 */
 
 bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
-                       HA_CREATE_INFO *lex_create_info,
+                       HA_CREATE_INFO *create_info,
                        TABLE_LIST *table_list,
                        List<create_field> &fields, List<Key> &keys,
                        uint order_num, ORDER *order, bool ignore,
@@ -5153,7 +5137,6 @@
   uint db_create_options, used_fields;
   handlerton *old_db_type, *new_db_type;
   legacy_db_type table_type;
-  HA_CREATE_INFO *create_info;
   frm_type_enum frm_type;
   uint need_copy_table= 0;
   bool no_table_reopen= FALSE, varchar= FALSE;
@@ -5206,9 +5189,9 @@
 
     /* Disable alter of log tables to unsupported engine */
     if ((table_kind == GENERAL_LOG || table_kind == SLOW_LOG) &&
-        (lex_create_info->used_fields & HA_CREATE_USED_ENGINE) &&
-        (!lex_create_info->db_type || /* unknown engine */
-        !(lex_create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
+        (create_info->used_fields & HA_CREATE_USED_ENGINE) &&
+        (!create_info->db_type || /* unknown engine */
+        !(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
     {
       my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0));
       DBUG_RETURN(TRUE);
@@ -5216,10 +5199,7 @@
   }
 
   thd->proc_info="init";
-  if (!(create_info= copy_create_info(lex_create_info)))
-  {
-    DBUG_RETURN(TRUE);
-  }
+
   table_name=table_list->table_name;
   alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
   db=table_list->db;
@@ -6020,7 +6000,7 @@
   */
   tmp_disable_binlog(thd);
   error= mysql_create_table(thd, new_db, tmp_name,
-                            create_info,create_list,key_list,1,0,0);
+                            create_info, create_list, key_list, 1, 0);
   reenable_binlog(thd);
   if (error)
     DBUG_RETURN(error);

--- 1.78/mysql-test/r/ps.result	2006-10-31 16:22:30 +03:00
+++ 1.79/mysql-test/r/ps.result	2006-10-31 16:22:30 +03:00
@@ -2243,3 +2243,91 @@
 Note	1051	Unknown table 't1'
 Note	1051	Unknown table 't2'
 deallocate prepare abc;
+drop database if exists mysqltest;
+drop table if exists t1, t2;
+create table t1 (i int primary key auto_increment) comment='comment for table t1';
+create table t2 (i int, j int, k int);
+prepare stmt from "alter table t1 auto_increment=100";
+execute stmt;
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `i` int(11) NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`i`)
+) ENGINE=MyISAM AUTO_INCREMENT=100 DEFAULT CHARSET=latin1 COMMENT='comment for table t1'
+flush tables;
+select * from t2;
+i	j	k
+execute stmt;
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `i` int(11) NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`i`)
+) ENGINE=MyISAM AUTO_INCREMENT=100 DEFAULT CHARSET=latin1 COMMENT='comment for table t1'
+deallocate prepare stmt;
+drop table t1, t2;
+create database mysqltest character set utf8;
+prepare stmt1 from "create table mysqltest.t1 (c char(10))";
+prepare stmt2 from "create table mysqltest.t2 select 'test'";
+execute stmt1;
+execute stmt2;
+show create table mysqltest.t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c` char(10) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=utf8
+show create table mysqltest.t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `test` varchar(4) CHARACTER SET latin1 NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=utf8
+drop table mysqltest.t1;
+drop table mysqltest.t2;
+alter database mysqltest character set latin1;
+execute stmt1;
+execute stmt2;
+show create table mysqltest.t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c` char(10) CHARACTER SET utf8 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+show create table mysqltest.t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `test` varchar(4) NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop database mysqltest;
+deallocate prepare stmt1;
+deallocate prepare stmt2;
+execute stmt;
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c` char(10) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQLTEST_VARDIR/tmp/'
+drop table t1;
+execute stmt;
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c` char(10) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQLTEST_VARDIR/tmp/'
+drop table t1;
+deallocate prepare stmt;
+set @old_character_set_server= @@character_set_server;
+set @@character_set_server= latin1;
+prepare stmt from "create database mysqltest";
+execute stmt;
+show create database mysqltest;
+Database	Create Database
+mysqltest	CREATE DATABASE `mysqltest` /*!40100 DEFAULT CHARACTER SET latin1 */
+drop database mysqltest;
+set @@character_set_server= utf8;
+execute stmt;
+show create database mysqltest;
+Database	Create Database
+mysqltest	CREATE DATABASE `mysqltest` /*!40100 DEFAULT CHARACTER SET utf8 */
+drop database mysqltest;
+deallocate prepare stmt;
+set @@character_set_server= @old_character_set_server;

--- 1.75/mysql-test/t/ps.test	2006-10-31 16:22:30 +03:00
+++ 1.76/mysql-test/t/ps.test	2006-10-31 16:22:30 +03:00
@@ -2307,3 +2307,74 @@
 drop table if exists t1, t2;
 execute abc;
 deallocate prepare abc;
+
+
+#
+# Bug #22060 "ALTER TABLE x AUTO_INCREMENT=y in SP crashes server"
+#
+# Code which implemented CREATE/ALTER TABLE and CREATE DATABASE
+# statement modified HA_CREATE_INFO structure in LEX, making these
+# statements PS/SP-unsafe (their re-execution might have resulted
+# in incorrect results).
+#
+--disable_warnings
+drop database if exists mysqltest;
+drop table if exists t1, t2;
+--enable_warnings
+# ALTER TABLE
+create table t1 (i int primary key auto_increment) comment='comment for table t1';
+create table t2 (i int, j int, k int);
+prepare stmt from "alter table t1 auto_increment=100";
+execute stmt;
+show create table t1;
+# Let us trash table-cache's memory
+flush tables;
+select * from t2;
+execute stmt;
+show create table t1;
+deallocate prepare stmt;
+drop table t1, t2;
+# CREATE TABLE and CREATE TABLE ... SELECT
+create database mysqltest character set utf8;
+prepare stmt1 from "create table mysqltest.t1 (c char(10))";
+prepare stmt2 from "create table mysqltest.t2 select 'test'";
+execute stmt1;
+execute stmt2;
+show create table mysqltest.t1;
+show create table mysqltest.t2;
+drop table mysqltest.t1;
+drop table mysqltest.t2;
+alter database mysqltest character set latin1;
+execute stmt1;
+execute stmt2;
+show create table mysqltest.t1;
+show create table mysqltest.t2;
+drop database mysqltest;
+deallocate prepare stmt1;
+deallocate prepare stmt2;
+# CREATE TABLE with DATA DIRECTORY option
+--disable_query_log
+eval prepare stmt from "create table t1 (c char(10)) data
directory='$MYSQLTEST_VARDIR/tmp'";
+--enable_query_log
+execute stmt;
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+show create table t1;
+drop table t1;
+execute stmt;
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+show create table t1;
+drop table t1;
+deallocate prepare stmt;
+# CREATE DATABASE
+set @old_character_set_server= @@character_set_server;
+set @@character_set_server= latin1; 
+prepare stmt from "create database mysqltest";
+execute stmt;
+show create database mysqltest;
+drop database mysqltest;
+set @@character_set_server= utf8; 
+execute stmt;
+show create database mysqltest;
+drop database mysqltest;
+deallocate prepare stmt;
+set @@character_set_server= @old_character_set_server;
Thread
bk commit into 5.1 tree (dlenev:1.2321) BUG#22060dlenev31 Oct