MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:konstantin Date:October 31 2006 6:46pm
Subject:bk commit into 5.0 tree (kostja:1.2298) BUG#19182
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of kostja. When kostja 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 21:45:59+03:00, kostja@stripped +13 -0
  A fix and test cases for
  Bug#4968 "Stored procedure crash if cursor opened on altered table"
  Bug#19733 "Repeated alter, or repeated create/drop, fails"
  Bug#19182 "CREATE TABLE bar (m INT) SELECT n FROM foo; doesn't work from 
  stored procedure."
  
  Bug#19182 affects 4.1 and this fix will be ported to 4.1 when (if) it's 
  approved.
  
  The problem that caused all of the above bugs is that functions
  mysql_prepare_table, mysql_create_table and mysql_alter_table are not
  re-execution friendly: during their operation they modify contents
  of LEX (members create_info, alter_info, key_list, create_list),
  thus making the LEX unusable for the next execution.
  In particular, these function remove processed columns and keys from
  create_list, key_list and drop_list. Search the code for drop_it.remove()
  and similar to find evidence.
  
  The fix is to supply to these functions a usable copy of each of the
  above structures at every re-execution of an SQL statement. 
  To simplify memory management, LEX::key_list and LEX::create_list
  were added to LEX::alter_info, a fresh copy of which is created for
  every execution.

  mysql-test/r/ps.result@stripped, 2006-10-31 21:45:54+03:00, kostja@stripped +25 -0
    Update test results (Bug#19182, Bug#4968)

  mysql-test/r/sp.result@stripped, 2006-10-31 21:45:54+03:00, kostja@stripped +17 -0
    Update test results (Bug#19733)

  mysql-test/t/ps.test@stripped, 2006-10-31 21:45:54+03:00, kostja@stripped +46 -0
    Add a test case for Bug#19182, Bug#4968

  mysql-test/t/sp.test@stripped, 2006-10-31 21:45:54+03:00, kostja@stripped +28 -0
    Add a test case for Bug#19733

  sql/mysql_priv.h@stripped, 2006-10-31 21:45:54+03:00, kostja@stripped +4 -9
    LEX::key_list and LEX::create_list were moved to LEX::alter_info.
    Update declarations to use LEX::alter_info instead of these two
    members.

  sql/sql_class.h@stripped, 2006-10-31 21:45:55+03:00, kostja@stripped +9 -9
    select_create is currently created for every execution of a PS/SP.
    In constructor, create a copy of LEX::create_info and LEX::alter_info,
    as these structures are modified in mysql_create_table_from_items.

  sql/sql_insert.cc@stripped, 2006-10-31 21:45:55+03:00, kostja@stripped +11 -12
    Parameters create_list + key_list were replaced with Alter_info 
    *alter_info.
    select_create now has a copy of create_info (so that updates
    of table_existed at previous execution do not affect subsequent
    executions).

  sql/sql_lex.cc@stripped, 2006-10-31 21:45:55+03:00, kostja@stripped +11 -0
    Implement Alter_info::Alter_info that would make a "deep" copy
    of all definition lists (keys, columns).

  sql/sql_lex.h@stripped, 2006-10-31 21:45:55+03:00, kostja@stripped +40 -8
    Move key_list and create_list to class Alter_info. Implement
    Alter_info::Alter_info that can be used with PS and SP.

  sql/sql_list.h@stripped, 2006-10-31 21:45:55+03:00, kostja@stripped +41 -9
    Implement a copy constructor of class List that makes a deep copy
    of all list nodes.

  sql/sql_parse.cc@stripped, 2006-10-31 21:45:55+03:00, kostja@stripped +64 -83
    Adjust to new signatures of mysql_create_table, mysql_alter_table,
    select_create. mysql_create_index and mysql_drop_index has become
    identical after initialization of alter_info was moved to the parser
    and were merged. Flag enable_slow_log was not updated for 
    SQLCOM_DROP_INDEX, which is a bug. Just like CREATE INDEX, DROP INDEX
    is currently done via complete table rebuild and is rightfully a slow
    administrative statement.

  sql/sql_table.cc@stripped, 2006-10-31 21:45:55+03:00, kostja@stripped +59 -57
    Adjust mysql_alter_table, mysql_recreate_table, mysql_create_table,
    mysql_prepare_table to new signatures.

  sql/sql_yacc.yy@stripped, 2006-10-31 21:45:56+03:00, kostja@stripped +21 -22
    LEX::key_list and LEX::create_list moved to class Alter_info

# 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:	kostja
# Host:	bodhi.local
# Root:	/opt/local/work/mysql-5.0-19733

--- 1.417/sql/mysql_priv.h	2006-10-31 21:46:09 +03:00
+++ 1.418/sql/mysql_priv.h	2006-10-31 21:46:09 +03:00
@@ -767,17 +767,15 @@ int prepare_create_field(create_field *s
 			 uint table_flags);
 bool mysql_create_table(THD *thd,const char *db, const char *table_name,
                         HA_CREATE_INFO *create_info,
-                        List<create_field> &fields, List<Key> &keys,
+                        Alter_info *alter_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,
                        TABLE_LIST *table_list,
-                       List<create_field> &fields,
-                       List<Key> &keys,
-                       uint order_num, ORDER *order, bool ignore,
-                       ALTER_INFO *alter_info, bool do_send_ok);
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
+                       Alter_info *alter_info,
+                       uint order_num, ORDER *order, bool ignore);
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
 bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
                              HA_CREATE_INFO *create_info,
                              Table_ident *src_table);
@@ -786,9 +784,6 @@ bool mysql_rename_table(enum db_type bas
 			const char * old_name,
 			const char *new_db,
 			const char * new_name);
-bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
-bool mysql_drop_index(THD *thd, TABLE_LIST *table_list,
-                      ALTER_INFO *alter_info);
 bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
                           Item **conds, uint order_num, ORDER *order);
 int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,

--- 1.306/sql/sql_class.h	2006-10-31 21:46:09 +03:00
+++ 1.307/sql/sql_class.h	2006-10-31 21:46:09 +03:00
@@ -1822,19 +1822,19 @@ class select_insert :public select_resul
 class select_create: public select_insert {
   ORDER *group;
   TABLE_LIST *create_table;
-  List<create_field> *extra_fields;
-  List<Key> *keys;
-  HA_CREATE_INFO *create_info;
+  HA_CREATE_INFO create_info;
+  Alter_info alter_info;
   MYSQL_LOCK *lock;
   Field **field;
 public:
-  select_create (TABLE_LIST *table,
-		 HA_CREATE_INFO *create_info_par,
-		 List<create_field> &fields_par,
-		 List<Key> &keys_par,
+  select_create(THD *thd, TABLE_LIST *table,
+		 HA_CREATE_INFO *create_info_arg,
+                 Alter_info *alter_info_arg,
 		 List<Item> &select_fields,enum_duplicates duplic, bool ignore)
-    :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore), create_table(table),
-    extra_fields(&fields_par),keys(&keys_par), create_info(create_info_par),
+    :select_insert(NULL, NULL, &select_fields, 0, 0, duplic, ignore),
+    create_table(table),
+    create_info(*create_info_arg),
+    alter_info(*alter_info_arg, thd->mem_root),
     lock(0)
     {}
   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);

--- 1.206/sql/sql_insert.cc	2006-10-31 21:46:09 +03:00
+++ 1.207/sql/sql_insert.cc	2006-10-31 21:46:09 +03:00
@@ -2620,11 +2620,11 @@ bool select_insert::send_eof()
                           temporary table flag)
       create_table in     Pointer to TABLE_LIST object providing database
                           and name for table to be created or to be open
-      extra_fields in/out Initial list of fields for table to be created
-      keys         in     List of keys for table to be created
+      alter_info   in/out Initial list of columns and indexes for the table
+                          to be created
       items        in     List of items which should be used to produce rest
                           of fields for the table (corresponding fields will
-                          be added to the end of 'extra_fields' list)
+                          be added to the end of alter_info->create_list)
       lock         out    Pointer to the MYSQL_LOCK object for table created
                           (open) will be returned in this parameter. Since
                           this table is not included in THD::lock caller is
@@ -2646,8 +2646,8 @@ bool select_insert::send_eof()
 
 static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
                                       TABLE_LIST *create_table,
-                                      List<create_field> *extra_fields,
-                                      List<Key> *keys, List<Item> *items,
+                                      Alter_info *alter_info,
+                                      List<Item> *items,
                                       MYSQL_LOCK **lock)
 {
   TABLE tmp_table;		// Used during 'create_field()'
@@ -2686,7 +2686,7 @@ static TABLE *create_table_from_items(TH
       DBUG_RETURN(0);
     if (item->maybe_null)
       cr_field->flags &= ~NOT_NULL_FLAG;
-    extra_fields->push_back(cr_field);
+    alter_info->create_list.push_back(cr_field);
   }
   /*
     create and lock table
@@ -2707,8 +2707,7 @@ static TABLE *create_table_from_items(TH
   {
     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))
+                            create_info, alter_info, 0, select_field_count))
     {
       /*
         If we are here in prelocked mode we either create temporary table
@@ -2763,8 +2762,8 @@ select_create::prepare(List<Item> &value
   DBUG_ENTER("select_create::prepare");
 
   unit= u;
-  table= create_table_from_items(thd, create_info, create_table,
-				 extra_fields, keys, &values, &lock);
+  table= create_table_from_items(thd, &create_info, create_table,
+                                 &alter_info, &values, &lock);
   if (!table)
     DBUG_RETURN(-1);				// abort() deletes table
 
@@ -2875,13 +2874,13 @@ void select_create::abort()
     {
       ulong version= table->s->version;
       hash_delete(&open_cache,(byte*) table);
-      if (!create_info->table_existed)
+      if (!create_info.table_existed)
         quick_rm_table(table_type, create_table->db, create_table->table_name);
       /* Tell threads waiting for refresh that something has happened */
       if (version != refresh_version)
         broadcast_refresh();
     }
-    else if (!create_info->table_existed)
+    else if (!create_info.table_existed)
       close_temporary_table(thd, create_table->db, create_table->table_name);
     table=0;
   }

--- 1.203/sql/sql_lex.cc	2006-10-31 21:46:09 +03:00
+++ 1.204/sql/sql_lex.cc	2006-10-31 21:46:09 +03:00
@@ -1077,6 +1077,17 @@ uchar *skip_rear_comments(uchar *begin, 
   return end;
 }
 
+
+Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
+  :drop_list(rhs.drop_list, mem_root),
+  alter_list(rhs.alter_list, mem_root),
+  key_list(rhs.key_list, mem_root),
+  create_list(rhs.create_list, mem_root),
+  flags(rhs.flags),
+  keys_onoff(rhs.keys_onoff),
+  tablespace_op(rhs.tablespace_op)
+{}
+
 /*
   st_select_lex structures initialisations
 */

--- 1.230/sql/sql_lex.h	2006-10-31 21:46:09 +03:00
+++ 1.231/sql/sql_lex.h	2006-10-31 21:46:09 +03:00
@@ -684,18 +684,52 @@ typedef class st_select_lex SELECT_LEX;
 #define ALTER_CONVERT          1024
 #define ALTER_FORCE		2048
 
-typedef struct st_alter_info
+/**
+  @brief Parsing data for CREATE or ALTER TABLE.
+
+  This structure contains a list of columns or indexes to be created,
+  altered or dropped.
+*/
+
+class Alter_info
 {
+public:
   List<Alter_drop>            drop_list;
   List<Alter_column>          alter_list;
+  List<Key>	              key_list;
+  List<create_field>          create_list;
   uint                        flags;
   enum enum_enable_or_disable keys_onoff;
   enum tablespace_op_type     tablespace_op;
 
-  st_alter_info(){clear();}
-  void clear(){keys_onoff= LEAVE_AS_IS;tablespace_op= NO_TABLESPACE_OP;}
-  void reset(){drop_list.empty();alter_list.empty();clear();}
-} ALTER_INFO;
+  Alter_info() :
+    flags(0),
+    keys_onoff(LEAVE_AS_IS),
+    tablespace_op(NO_TABLESPACE_OP)
+  {}
+  void reset()
+  {
+    drop_list.empty();
+    alter_list.empty();
+    key_list.empty();
+    create_list.empty();
+    flags= 0;
+    keys_onoff= LEAVE_AS_IS;
+    tablespace_op= NO_TABLESPACE_OP;
+  }
+  /**
+    Construct a copy of this object to be used for mysql_alter_table
+    and mysql_create_table. Historically, these two functions modify
+    their Alter_info arguments. This behaviour breaks re-execution of
+    prepared statements and stored procedures and is compensated by
+    always supplying a copy of Alter_info to these functions.
+  */
+
+  Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root);
+private:
+  Alter_info &operator=(const Alter_info &rhs); // not implemented
+  Alter_info(const Alter_info &rhs);            // not implemented
+};
 
 struct st_sp_chistics
 {
@@ -877,8 +911,6 @@ typedef struct st_lex : public Query_tab
   List<String>	      interval_list;
   List<LEX_USER>      users_list;
   List<LEX_COLUMN>    columns;
-  List<Key>	      key_list;
-  List<create_field>  create_list;
   List<Item>	      *insert_list,field_list,value_list,update_list;
   List<List_item>     many_values;
   List<set_var_base>  var_list;
@@ -971,7 +1003,7 @@ typedef struct st_lex : public Query_tab
   bool safe_to_cache_query;
   bool subqueries, ignore;
   st_parsing_options parsing_options;
-  ALTER_INFO alter_info;
+  Alter_info alter_info;
   /* Prepared statements SQL syntax:*/
   LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
   /*

--- 1.40/sql/sql_list.h	2006-10-31 21:46:09 +03:00
+++ 1.41/sql/sql_list.h	2006-10-31 21:46:09 +03:00
@@ -62,21 +62,18 @@ public:
   pointer.
 */
 
-class list_node :public Sql_alloc
+struct list_node :public Sql_alloc
 {
-public:
   list_node *next;
   void *info;
   list_node(void *info_par,list_node *next_par)
     :next(next_par),info(info_par)
-    {}
+  {}
   list_node()					/* For end_of_list */
-    {
-      info=0;
-      next= this;
-    }
-  friend class base_list;
-  friend class base_list_iterator;
+  {
+    info= 0;
+    next= this;
+  }
 };
 
 
@@ -92,12 +89,45 @@ public:
 
   inline void empty() { elements=0; first= &end_of_list; last=&first;}
   inline base_list() { empty(); }
+  /**
+    This form of construction passes the ownership from the source list
+    to the new instance. It is deprecated, please consider using the deep
+    copy constructor instead.
+  */
   inline base_list(const base_list &tmp) :Sql_alloc()
   {
     elements= tmp.elements;
     first= tmp.first;
     last= elements ? tmp.last : &first;
   }
+  /**
+    Construct a deep copy of the argument in memory root mem_root.
+    The elements themselves are copied by pointer.
+  */
+  inline base_list(const base_list &rhs, MEM_ROOT *mem_root) :
+    elements(rhs.elements)
+  {
+    if (elements)
+    {
+      first= (list_node*) alloc_root(mem_root, sizeof(list_node)*elements);
+      if (first)
+      {
+        list_node *dst= first;
+        list_node *src= rhs.first;
+        for (; dst < first + elements; dst++, src= src->next)
+        {
+          dst->info= src->info;
+          dst->next= dst + 1;
+        }
+        last= &dst[-1].next;
+        *last= &end_of_list;               // close list tail
+        return;
+      }
+      elements= 0;
+    }
+    first= &end_of_list;
+    last= &first;
+  }
   inline base_list(bool error) { }
   inline bool push_back(void *info)
   {
@@ -348,6 +378,8 @@ template <class T> class List :public ba
 public:
   inline List() :base_list() {}
   inline List(const List<T> &tmp) :base_list(tmp) {}
+  inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
+    base_list(tmp, mem_root) {}
   inline bool push_back(T *a) { return base_list::push_back(a); }
   inline bool push_back(T *a, MEM_ROOT *mem_root)
   { return base_list::push_back(a, mem_root); }

--- 1.586/sql/sql_parse.cc	2006-10-31 21:46:09 +03:00
+++ 1.587/sql/sql_parse.cc	2006-10-31 21:46:09 +03:00
@@ -2953,11 +2953,13 @@ mysql_execute_command(THD *thd)
             }
           }
         }
-
-        if ((result= new select_create(create_table,
-				       &lex->create_info,
-				       lex->create_list,
-				       lex->key_list,
+        /*
+          select_create is currently not re-execution friendly and
+          needs to be created for every execution of a PS/SP.
+        */
+        if ((result= new select_create(thd, create_table,
+                                       &lex->create_info,
+                                       &lex->alter_info,
 				       select_lex->item_list,
 				       lex->duplicates,
 				       lex->ignore)))
@@ -2969,23 +2971,21 @@ mysql_execute_command(THD *thd)
           res= handle_select(thd, lex, result, 0);
           delete result;
         }
-	/* reset for PS */
-	lex->create_list.empty();
-	lex->key_list.empty();
       }
     }
     else
     {
+      HA_CREATE_INFO create_info(lex->create_info);
       /* regular create */
       if (lex->name)
-        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
+        res= mysql_create_like_table(thd, create_table, &create_info,
                                      (Table_ident *)lex->name); 
       else
       {
+        Alter_info alter_info(lex->alter_info, thd->mem_root);
         res= mysql_create_table(thd, create_table->db,
-				create_table->table_name, &lex->create_info,
-				lex->create_list,
-				lex->key_list, 0, 0);
+                                create_table->table_name, &create_info,
+                                &alter_info, 0, 0);
       }
       if (!res)
 	send_ok(thd);
@@ -2997,16 +2997,44 @@ end_with_restore_list:
     break;
   }
   case SQLCOM_CREATE_INDEX:
+    /* Fall through */
+  case SQLCOM_DROP_INDEX:
+  {
+    Alter_info alter_info(lex->alter_info, thd->mem_root);
+    HA_CREATE_INFO create_info;
+    /*
+      CREATE INDEX and DROP INDEX are implemented by calling ALTER
+      TABLE with proper arguments. This isn't very fast but it
+      should work for most cases.
+
+      In the future ALTER TABLE will notice that only added
+      indexes and create these one by one for the existing table
+      without having to do a full rebuild.
+
+      One should normally create all indexes with CREATE TABLE or
+      ALTER TABLE.
+    */
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
     if (check_one_table_access(thd, INDEX_ACL, all_tables))
       goto error; /* purecov: inspected */
+    /*
+      Currently CREATE INDEX or DROP INDEX cause a full table rebuild
+      and thus classify as slow administrative statements just like
+      ALTER TABLE.
+    */
     thd->enable_slow_log= opt_log_slow_admin_statements;
     if (end_active_trans(thd))
       goto error;
-    else
-      res = mysql_create_index(thd, first_table, lex->key_list);
-    break;
 
+    bzero((char*) &create_info, sizeof(create_info));
+    create_info.db_type= DB_TYPE_DEFAULT;
+    create_info.default_table_charset= thd->variables.collation_database;
+
+    res= mysql_alter_table(thd, first_table->db, first_table->table_name,
+                           &create_info, first_table,
+                           &alter_info, 0, (ORDER*)0, 0);
+    break;
+  }
 #ifdef HAVE_REPLICATION
   case SQLCOM_SLAVE_START:
   {
@@ -3046,6 +3074,13 @@ end_with_restore_list:
   case SQLCOM_ALTER_TABLE:
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
     {
+      /*
+        Use a stack copy of create_info, as it is changed in
+        mysql_alter_table, which is not allowed in case we're executing
+        a prepared statement or a stored procedure.
+      */
+      HA_CREATE_INFO create_info(lex->create_info);
+      Alter_info alter_info(lex->alter_info, thd->mem_root);
       ulong priv=0;
       if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
       {
@@ -3061,7 +3096,7 @@ end_with_restore_list:
                        is_schema_db(select_lex->db))||
 	  check_merge_table_access(thd, first_table->db,
 				   (TABLE_LIST *)
-				   lex->create_info.merge_list.first))
+				   create_info.merge_list.first))
 	goto error;				/* purecov: inspected */
       if (grant_option)
       {
@@ -3086,7 +3121,7 @@ end_with_restore_list:
       if (lex->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= NULL;
       /* ALTER TABLE ends previous transaction */
       if (end_active_trans(thd))
 	goto error;
@@ -3101,12 +3136,12 @@ end_with_restore_list:
 
         thd->enable_slow_log= opt_log_slow_admin_statements;
 	res= mysql_alter_table(thd, select_lex->db, lex->name,
-			       &lex->create_info,
-			       first_table, lex->create_list,
-			       lex->key_list,
+			       &create_info,
+                               first_table,
+                               &alter_info,
 			       select_lex->order_list.elements,
                                (ORDER *) select_lex->order_list.first,
-			       lex->ignore, &lex->alter_info, 1);
+                               lex->ignore);
       }
       break;
     }
@@ -3257,7 +3292,7 @@ end_with_restore_list:
       goto error; /* purecov: inspected */
     thd->enable_slow_log= opt_log_slow_admin_statements;
     res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
-      mysql_recreate_table(thd, first_table, 1) :
+      mysql_recreate_table(thd, first_table) :
       mysql_optimize_table(thd, first_table, &lex->check_opt);
     /* ! we write after unlocking the table */
     if (!res && !lex->no_write_to_binlog)
@@ -3567,15 +3602,6 @@ end_with_restore_list:
 			lex->drop_temporary);
   }
   break;
-  case SQLCOM_DROP_INDEX:
-    DBUG_ASSERT(first_table == all_tables && first_table != 0);
-    if (check_one_table_access(thd, INDEX_ACL, all_tables))
-      goto error;				/* purecov: inspected */
-    if (end_active_trans(thd))
-      goto error;
-    else
-      res = mysql_drop_index(thd, first_table, &lex->alter_info);
-    break;
   case SQLCOM_SHOW_PROCESSLIST:
     if (!thd->security_ctx->priv_user[0] &&
         check_global_access(thd,PROCESS_ACL))
@@ -5964,15 +5990,17 @@ bool add_field_to_list(THD *thd, char *f
   if (type_modifier & PRI_KEY_FLAG)
   {
     lex->col_list.push_back(new key_part_spec(field_name,0));
-    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
-				    0, lex->col_list));
+    lex->alter_info.key_list.push_back(new Key(Key::PRIMARY, NullS,
+                                               HA_KEY_ALG_UNDEF, 0,
+                                               lex->col_list));
     lex->col_list.empty();
   }
   if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
   {
     lex->col_list.push_back(new key_part_spec(field_name,0));
-    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
-				    lex->col_list));
+    lex->alter_info.key_list.push_back(new Key(Key::UNIQUE, NullS,
+                                               HA_KEY_ALG_UNDEF, 0,
+                                               lex->col_list));
     lex->col_list.empty();
   }
 
@@ -6035,7 +6063,7 @@ bool add_field_to_list(THD *thd, char *f
                       interval_list, cs, uint_geom_type))
     DBUG_RETURN(1);
 
-  lex->create_list.push_back(new_field);
+  lex->alter_info.create_list.push_back(new_field);
   lex->last_field=new_field;
   DBUG_RETURN(0);
 }
@@ -7057,53 +7085,6 @@ Item * all_any_subquery_creator(Item *le
     return it->upper_item= new Item_func_not_all(it);	/* ALL */
 
   return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
-}
-
-
-/*
-  CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
-  the proper arguments.  This isn't very fast but it should work for most
-  cases.
-
-  In the future ALTER TABLE will notice that only added indexes
-  and create these one by one for the existing table without having to do
-  a full rebuild.
-
-  One should normally create all indexes with CREATE TABLE or ALTER TABLE.
-*/
-
-bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
-{
-  List<create_field> fields;
-  ALTER_INFO alter_info;
-  alter_info.flags= ALTER_ADD_INDEX;
-  HA_CREATE_INFO create_info;
-  DBUG_ENTER("mysql_create_index");
-  bzero((char*) &create_info,sizeof(create_info));
-  create_info.db_type=DB_TYPE_DEFAULT;
-  create_info.default_table_charset= thd->variables.collation_database;
-  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
-				&create_info, table_list,
-				fields, keys, 0, (ORDER*)0,
-                                0, &alter_info, 1));
-}
-
-
-bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
-{
-  List<create_field> fields;
-  List<Key> keys;
-  HA_CREATE_INFO create_info;
-  DBUG_ENTER("mysql_drop_index");
-  bzero((char*) &create_info,sizeof(create_info));
-  create_info.db_type=DB_TYPE_DEFAULT;
-  create_info.default_table_charset= thd->variables.collation_database;
-  alter_info->clear();
-  alter_info->flags= ALTER_DROP_INDEX;
-  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
-				&create_info, table_list,
-				fields, keys, 0, (ORDER*)0,
-                                0, alter_info, 1));
 }
 
 

--- 1.324/sql/sql_table.cc	2006-10-31 21:46:09 +03:00
+++ 1.325/sql/sql_table.cc	2006-10-31 21:46:09 +03:00
@@ -644,8 +644,7 @@ int prepare_create_field(create_field *s
     mysql_prepare_table()
     thd			Thread object
     create_info		Create information (like MAX_ROWS)
-    fields		List of fields to create
-    keys		List of keys to create
+    alter_info          List of columns and indexes to create
 
   DESCRIPTION
     Prepares the table and key structures for table creation.
@@ -659,8 +658,8 @@ int prepare_create_field(create_field *s
 */
 
 static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
-                               List<create_field> *fields,
-                               List<Key> *keys, bool tmp_table,
+                               Alter_info *alter_info,
+                               bool tmp_table,
                                uint *db_options,
                                handler *file, KEY **key_info_buffer,
                                uint *key_count, int select_field_count)
@@ -674,11 +673,12 @@ static int mysql_prepare_table(THD *thd,
   int		timestamps= 0, timestamps_with_niladic= 0;
   int		field_no,dup_no;
   int		select_field_pos,auto_increment=0;
-  List_iterator<create_field> it(*fields),it2(*fields);
+  List_iterator<create_field> it(alter_info->create_list);
+  List_iterator<create_field> it2(alter_info->create_list);
   uint total_uneven_bit_length= 0;
   DBUG_ENTER("mysql_prepare_table");
 
-  select_field_pos= fields->elements - select_field_count;
+  select_field_pos= alter_info->create_list.elements - select_field_count;
   null_fields=blob_columns=0;
   create_info->varchar= 0;
   max_key_length= file->max_key_length();
@@ -1003,7 +1003,8 @@ static int mysql_prepare_table(THD *thd,
 
   /* Create keys */
 
-  List_iterator<Key> key_iterator(*keys), key_iterator2(*keys);
+  List_iterator<Key> key_iterator(alter_info->key_list);
+  List_iterator<Key> key_iterator2(alter_info->key_list);
   uint key_parts=0, fk_key_count=0;
   bool primary_key=0,unique_key=0;
   Key *key, *key2;
@@ -1566,8 +1567,7 @@ void sp_prepare_create_field(THD *thd, c
     db			Database
     table_name		Table name
     create_info		Create information (like MAX_ROWS)
-    fields		List of fields to create
-    keys		List of keys to create
+    alter_info [in/out] List of columns and indexes to create
     internal_tmp_table  Set to 1 if this is an internal temporary table
 			(From ALTER TABLE)
 
@@ -1586,8 +1586,8 @@ void sp_prepare_create_field(THD *thd, c
 
 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 internal_tmp_table,
+                        Alter_info *alter_info,
+                        bool internal_tmp_table,
                         uint select_field_count)
 {
   char		path[FN_REFLEN];
@@ -1599,7 +1599,7 @@ bool mysql_create_table(THD *thd,const c
   DBUG_ENTER("mysql_create_table");
 
   /* Check for duplicate fields and check type of table to create */
-  if (!fields.elements)
+  if (!alter_info->create_list.elements)
   {
     my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
                MYF(0));
@@ -1643,8 +1643,8 @@ bool mysql_create_table(THD *thd,const c
     create_info->default_table_charset= db_info.default_table_charset;
   }
 
-  if (mysql_prepare_table(thd, create_info, &fields,
-			  &keys, internal_tmp_table, &db_options, file,
+  if (mysql_prepare_table(thd, create_info, alter_info, internal_tmp_table,
+                          &db_options, file,
 			  &key_info_buffer, &key_count,
 			  select_field_count))
     DBUG_RETURN(TRUE);
@@ -1736,7 +1736,7 @@ bool mysql_create_table(THD *thd,const c
   create_info->table_options=db_options;
 
   if (rea_create_table(thd, path, db, table_name,
-                       create_info, fields, key_count,
+                       create_info, alter_info->create_list, key_count,
 		       key_info_buffer))
     goto end;
   if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
@@ -2323,9 +2323,12 @@ static bool mysql_admin_table(THD* thd, 
           (table->table->file->ha_check_for_upgrade(check_opt) ==
            HA_ADMIN_NEEDS_ALTER))
       {
+        my_bool nsok= thd->net.no_send_ok;
         close_thread_tables(thd);
         tmp_disable_binlog(thd); // binlogging is done by caller if wanted
-        result_code= mysql_recreate_table(thd, table, 0);
+        thd->net.no_send_ok= TRUE;
+        result_code= mysql_recreate_table(thd, table);
+        thd->net.no_send_ok= nsok;
         reenable_binlog(thd);
         goto send_result;
       }
@@ -2404,6 +2407,7 @@ send_result_message:
 
     case HA_ADMIN_TRY_ALTER:
     {
+      my_bool nsok= thd->net.no_send_ok;
       /*
         This is currently used only by InnoDB. ha_innobase::optimize() answers
         "try with alter", so here we close the table, do an ALTER TABLE,
@@ -2414,7 +2418,9 @@ send_result_message:
                  *save_next_global= table->next_global;
       table->next_local= table->next_global= 0;
       tmp_disable_binlog(thd); // binlogging is done by caller if wanted
-      result_code= mysql_recreate_table(thd, table, 0);
+      thd->net.no_send_ok= TRUE;
+      result_code= mysql_recreate_table(thd, table);
+      thd->net.no_send_ok= nsok;
       reenable_binlog(thd);
       close_thread_tables(thd);
       if (!result_code) // recreation went ok
@@ -2941,9 +2947,8 @@ err:
 bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
                        HA_CREATE_INFO *create_info,
                        TABLE_LIST *table_list,
-                       List<create_field> &fields, List<Key> &keys,
-                       uint order_num, ORDER *order, bool ignore,
-                       ALTER_INFO *alter_info, bool do_send_ok)
+                       Alter_info *alter_info,
+                       uint order_num, ORDER *order, bool ignore)
 {
   TABLE *table,*new_table=0;
   int error;
@@ -3163,8 +3168,7 @@ view_err:
 	Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
 	mysql_bin_log.write(&qinfo);
       }
-      if (do_send_ok)
-        send_ok(thd);
+      send_ok(thd);
     }
     else if (error > 0)
     {
@@ -3190,10 +3194,9 @@ view_err:
 
   restore_record(table, s->default_values);     // Empty record for DEFAULT
   List_iterator<Alter_drop> drop_it(alter_info->drop_list);
-  List_iterator<create_field> def_it(fields);
+  List_iterator<create_field> def_it(alter_info->create_list);
   List_iterator<Alter_column> alter_it(alter_info->alter_list);
-  List<create_field> create_list;		// Add new fields here
-  List<Key> key_list;				// Add new keys here
+  Alter_info new_info;                   // Add new columns and indexes here
   create_field *def;
 
   /*
@@ -3241,13 +3244,13 @@ view_err:
       def->field=field;
       if (!def->after)
       {
-	create_list.push_back(def);
+	new_info.create_list.push_back(def);
 	def_it.remove();
       }
     }
     else
     {						// Use old field value
-      create_list.push_back(def=new create_field(field,field));
+      new_info.create_list.push_back(def=new create_field(field,field));
       alter_it.rewind();			// Change default if ALTER
       Alter_column *alter;
       while ((alter=alter_it++))
@@ -3271,7 +3274,7 @@ view_err:
     }
   }
   def_it.rewind();
-  List_iterator<create_field> find_it(create_list);
+  List_iterator<create_field> find_it(new_info.create_list);
   while ((def=def_it++))			// Add new columns
   {
     if (def->change && ! def->field)
@@ -3280,9 +3283,9 @@ view_err:
       DBUG_RETURN(TRUE);
     }
     if (!def->after)
-      create_list.push_back(def);
+      new_info.create_list.push_back(def);
     else if (def->after == first_keyword)
-      create_list.push_front(def);
+      new_info.create_list.push_front(def);
     else
     {
       create_field *find;
@@ -3306,7 +3309,7 @@ view_err:
              alter_info->alter_list.head()->name, table_name);
     DBUG_RETURN(TRUE);
   }
-  if (!create_list.elements)
+  if (!new_info.create_list.elements)
   {
     my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
                MYF(0));
@@ -3318,8 +3321,8 @@ view_err:
     for which some fields exists.
   */
 
-  List_iterator<Key> key_it(keys);
-  List_iterator<create_field> field_it(create_list);
+  List_iterator<Key> key_it(alter_info->key_list);
+  List_iterator<create_field> field_it(new_info.create_list);
   List<key_part_spec> key_parts;
 
   KEY *key_info=table->key_info;
@@ -3391,24 +3394,27 @@ view_err:
 					    key_part_length));
     }
     if (key_parts.elements)
-      key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL :
-				 (key_info->flags & HA_NOSAME ?
-				 (!my_strcasecmp(system_charset_info,
-						 key_name, primary_key_name) ?
-				  Key::PRIMARY	: Key::UNIQUE) :
-				  (key_info->flags & HA_FULLTEXT ?
-				   Key::FULLTEXT : Key::MULTIPLE)),
-				 key_name,
-				 key_info->algorithm,
-                                 test(key_info->flags & HA_GENERATED_KEY),
-				 key_parts));
+    {
+      Key *key= new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL :
+                        (key_info->flags & HA_NOSAME ?
+                         (!my_strcasecmp(system_charset_info,
+                                         key_name, primary_key_name) ?
+                          Key::PRIMARY	: Key::UNIQUE) :
+                         (key_info->flags & HA_FULLTEXT ?
+                          Key::FULLTEXT : Key::MULTIPLE)),
+                        key_name,
+                        key_info->algorithm,
+                        test(key_info->flags & HA_GENERATED_KEY),
+                        key_parts);
+      new_info.key_list.push_back(key);
+    }
   }
   {
     Key *key;
     while ((key=key_it++))			// Add new keys
     {
       if (key->type != Key::FOREIGN_KEY)
-	key_list.push_back(key);
+        new_info.key_list.push_back(key);
       if (key->name &&
 	  !my_strcasecmp(system_charset_info,key->name,primary_key_name))
       {
@@ -3543,7 +3549,7 @@ view_err:
   {
     tmp_disable_binlog(thd);
     error= mysql_create_table(thd, new_db, tmp_name,
-                              create_info,create_list,key_list,1,0);
+                              create_info, &new_info, 1, 0);
     reenable_binlog(thd);
     if (error)
       DBUG_RETURN(error);
@@ -3584,8 +3590,9 @@ view_err:
   {
     new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
     new_table->next_number_field=new_table->found_next_number_field;
-    error=copy_data_between_tables(table, new_table, create_list, ignore,
-				   order_num, order, &copied, &deleted);
+    error= copy_data_between_tables(table, new_table, new_info.create_list,
+                                    ignore, order_num, order, &copied,
+                                    &deleted);
   }
   thd->last_insert_id=next_insert_id;		// Needed for correct log
   thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -3794,8 +3801,7 @@ end_temporary:
   my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
 	      (ulong) (copied + deleted), (ulong) deleted,
 	      (ulong) thd->cuted_fields);
-  if (do_send_ok)
-    send_ok(thd,copied+deleted,0L,tmp_name);
+  send_ok(thd,copied+deleted,0L,tmp_name);
   thd->some_tables_deleted=0;
   DBUG_RETURN(FALSE);
 
@@ -3995,14 +4001,11 @@ copy_data_between_tables(TABLE *from,TAB
  RETURN
     Like mysql_alter_table().
 */
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
-                          bool do_send_ok)
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
 {
   DBUG_ENTER("mysql_recreate_table");
   LEX *lex= thd->lex;
   HA_CREATE_INFO create_info;
-  lex->create_list.empty();
-  lex->key_list.empty();
   lex->col_list.empty();
   lex->alter_info.reset();
   bzero((char*) &create_info,sizeof(create_info));
@@ -4012,9 +4015,8 @@ bool mysql_recreate_table(THD *thd, TABL
   /* Force alter table to recreate table */
   lex->alter_info.flags= ALTER_CHANGE_COLUMN;
   DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
-                                table_list, lex->create_list,
-                                lex->key_list, 0, (ORDER *) 0,
-                                0, &lex->alter_info, do_send_ok));
+                                table_list, &lex->alter_info,
+                                0, (ORDER *) 0, 0));
 }
 
 

--- 1.493/sql/sql_yacc.yy	2006-10-31 21:46:09 +03:00
+++ 1.494/sql/sql_yacc.yy	2006-10-31 21:46:09 +03:00
@@ -1171,8 +1171,7 @@ create:
 						  TL_READ_NO_INSERT:
 						  TL_READ)))
 	    YYABORT;
-	  lex->create_list.empty();
-	  lex->key_list.empty();
+          lex->alter_info.reset();
 	  lex->col_list.empty();
 	  lex->change=NullS;
 	  bzero((char*) &lex->create_info,sizeof(lex->create_info));
@@ -1190,16 +1189,17 @@ create:
 	    if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL,
 							TL_OPTION_UPDATING))
 	      YYABORT;
-	    lex->create_list.empty();
-	    lex->key_list.empty();
+            lex->alter_info.reset();
+            lex->alter_info.flags= ALTER_ADD_INDEX;
 	    lex->col_list.empty();
 	    lex->change=NullS;
 	  }
 	   '(' key_list ')'
 	  {
 	    LEX *lex=Lex;
+            Key *key= new Key($2, $4.str, $5, 0, lex->col_list);
 
-	    lex->key_list.push_back(new Key($2,$4.str, $5, 0, lex->col_list));
+            lex->alter_info.key_list.push_back(key);
 	    lex->col_list.empty();
 	  }
 	| CREATE DATABASE opt_if_not_exists ident
@@ -2734,29 +2734,30 @@ key_def:
 	key_type opt_ident key_alg '(' key_list ')'
 	  {
 	    LEX *lex=Lex;
-	    lex->key_list.push_back(new Key($1,$2, $3, 0, lex->col_list));
+            Key *key= new Key($1, $2, $3, 0, lex->col_list);
+            lex->alter_info.key_list.push_back(key);
 	    lex->col_list.empty();		/* Alloced by sql_alloc */
 	  }
 	| opt_constraint constraint_key_type opt_ident key_alg '(' key_list ')'
 	  {
 	    LEX *lex=Lex;
 	    const char *key_name= $3 ? $3:$1;
-	    lex->key_list.push_back(new Key($2, key_name, $4, 0,
-				    lex->col_list));
+            Key *key= new Key($2, key_name, $4, 0, lex->col_list);
+            lex->alter_info.key_list.push_back(key);
 	    lex->col_list.empty();		/* Alloced by sql_alloc */
 	  }
 	| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
 	  {
 	    LEX *lex=Lex;
-	    lex->key_list.push_back(new foreign_key($4 ? $4:$1, lex->col_list,
-				    $8,
-				    lex->ref_list,
-				    lex->fk_delete_opt,
-				    lex->fk_update_opt,
-				    lex->fk_match_option));
-	    lex->key_list.push_back(new Key(Key::MULTIPLE, $4 ? $4 : $1,
-					    HA_KEY_ALG_UNDEF, 1,
-					    lex->col_list));
+            Key *key= new foreign_key($4 ? $4:$1, lex->col_list,
+                                      $8, lex->ref_list,
+                                      lex->fk_delete_opt,
+                                      lex->fk_update_opt,
+                                      lex->fk_match_option);
+            lex->alter_info.key_list.push_back(key);
+            key= new Key(Key::MULTIPLE, $4 ? $4 : $1, HA_KEY_ALG_UNDEF, 1,
+                         lex->col_list);
+            lex->alter_info.key_list.push_back(key);
 	    lex->col_list.empty();		/* Alloced by sql_alloc */
 	  }
 	| constraint opt_check_constraint
@@ -3298,8 +3299,6 @@ alter:
 	  if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
 						 TL_OPTION_UPDATING))
 	    YYABORT;
-	  lex->create_list.empty();
-	  lex->key_list.empty();
 	  lex->col_list.empty();
           lex->select_lex.init_order();
 	  lex->select_lex.db=
@@ -3309,8 +3308,7 @@ alter:
 	  lex->create_info.db_type= DB_TYPE_DEFAULT;
 	  lex->create_info.default_table_charset= NULL;
 	  lex->create_info.row_type= ROW_TYPE_NOT_USED;
-	  lex->alter_info.reset();
-	  lex->alter_info.flags= 0;
+          lex->alter_info.reset();
 	}
 	alter_list
 	{}
@@ -6050,7 +6048,8 @@ drop:
 	  {
 	     LEX *lex=Lex;
 	     lex->sql_command= SQLCOM_DROP_INDEX;
-	     lex->alter_info.drop_list.empty();
+             lex->alter_info.reset();
+             lex->alter_info.flags= ALTER_DROP_INDEX;
 	     lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
                                                                 $3.str));
 	     if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,

--- 1.215/mysql-test/r/sp.result	2006-10-31 21:46:09 +03:00
+++ 1.216/mysql-test/r/sp.result	2006-10-31 21:46:09 +03:00
@@ -5626,5 +5626,22 @@ Called B
 Called B
 drop procedure proc_21462_a|
 drop procedure proc_21462_b|
+drop table if exists t3|
+drop procedure if exists proc_bug19733|
+create table t3 (s1 int)|
+create procedure proc_bug19733()
+begin
+declare v int default 0;
+while v < 100 do
+create index i on t3 (s1);
+drop index i on t3;
+set v = v + 1;
+end while;
+end|
+call proc_bug19733()|
+call proc_bug19733()|
+call proc_bug19733()|
+drop procedure proc_bug19733|
+drop table t3|
 End of 5.0 tests
 drop table t1,t2;

--- 1.204/mysql-test/t/sp.test	2006-10-31 21:46:09 +03:00
+++ 1.205/mysql-test/t/sp.test	2006-10-31 21:46:09 +03:00
@@ -6584,6 +6584,34 @@ call proc_21462_b(1)|
 drop procedure proc_21462_a|
 drop procedure proc_21462_b|
 
+
+#
+# Bug#19733 "Repeated alter, or repeated create/drop, fails"
+# Check that CREATE/DROP INDEX is re-execution friendly.
+# 
+--disable_warnings
+drop table if exists t3|
+drop procedure if exists proc_bug19733|
+--enable_warnings
+create table t3 (s1 int)|
+
+create procedure proc_bug19733()
+begin
+  declare v int default 0;
+  while v < 100 do
+    create index i on t3 (s1);
+    drop index i on t3;
+    set v = v + 1;
+  end while;
+end|
+
+call proc_bug19733()|
+call proc_bug19733()|
+call proc_bug19733()|
+
+drop procedure proc_bug19733|
+drop table t3|
+
 --echo End of 5.0 tests
 
 

--- 1.78/mysql-test/r/ps.result	2006-10-31 21:46:09 +03:00
+++ 1.79/mysql-test/r/ps.result	2006-10-31 21:46:09 +03:00
@@ -1476,4 +1476,29 @@ i
 DEALLOCATE PREPARE stmt;
 DROP TABLE t1, t2;
 DROP PROCEDURE IF EXISTS p1;
+drop table if exists t1;
+create table t1 (s1 char(20));
+prepare stmt from "alter table t1 modify s1 int";
+execute stmt;
+execute stmt;
+drop table t1;
+deallocate prepare stmt;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t1 (i INT);
+PREPARE st_19182 FROM "CREATE TABLE t2 (j INT, KEY (j)) SELECT i FROM t1";
+EXECUTE st_19182;
+DESC t2;
+Field	Type	Null	Key	Default	Extra
+j	int(11)	YES	MUL	NULL	
+i	int(11)	YES		NULL	
+DROP TABLE t2;
+EXECUTE st_19182;
+DESC t2;
+Field	Type	Null	Key	Default	Extra
+j	int(11)	YES	MUL	NULL	
+i	int(11)	YES		NULL	
+DEALLOCATE PREPARE st_19182;
+DROP TABLE t2;
+DROP TABLE t1;
 End of 5.0 tests.

--- 1.74/mysql-test/t/ps.test	2006-10-31 21:46:09 +03:00
+++ 1.75/mysql-test/t/ps.test	2006-10-31 21:46:09 +03:00
@@ -1532,5 +1532,51 @@ while ($iterations > 0)
 --enable_query_log
 --enable_result_log
 
+#
+# Bug#4968 "Stored procedure crash if cursor opened on altered table"
+# The bug is not repeatable any more after the fix for
+# Bug#15217 "Bug #15217   Using a SP cursor on a table created with PREPARE
+# fails with weird error", however ALTER TABLE is not re-execution friendly
+# and that caused a valgrind warning. Check that the warning is gone.
+#
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (s1 char(20));
+prepare stmt from "alter table t1 modify s1 int";
+execute stmt;
+execute stmt;
+drop table t1;
+deallocate prepare stmt;
+
+#
+# Bug#19182: CREATE TABLE bar (m INT) SELECT n FROM foo; doesn't work
+# from stored procedure.
+#
+# The cause of a bug was that cached LEX::create_list was modified,
+# and then together with LEX::key_list was reset.
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+--enable_warnings
+
+CREATE TABLE t1 (i INT);
+
+PREPARE st_19182 FROM "CREATE TABLE t2 (j INT, KEY (j)) SELECT i FROM t1";
+
+EXECUTE st_19182;
+DESC t2;
+
+DROP TABLE t2;
+
+# Check that on second execution we don't loose 'j' column and the key
+# on it.
+EXECUTE st_19182;
+DESC t2;
+
+DEALLOCATE PREPARE st_19182;
+DROP TABLE t2;
+DROP TABLE t1;
 
 --echo End of 5.0 tests.
Thread
bk commit into 5.0 tree (kostja:1.2298) BUG#19182konstantin31 Oct