List:Commits« Previous MessageNext Message »
From:konstantin Date:December 12 2006 12:15am
Subject:bk commit into 5.1 tree (kostja:1.2390)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 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-12-12 02:15:49+03:00, kostja@stripped +17 -0
  Merge bodhi.local:/opt/local/work/mysql-5.0-4968-pull-from-4.1
  into  bodhi.local:/opt/local/work/mysql-5.1-4968
  MERGE: 1.1810.1698.194

  mysql-test/r/ps.result@stripped, 2006-12-12 01:58:56+03:00, kostja@stripped +0 -117
    Manual merge: use local.
    MERGE: 1.56.1.28

  mysql-test/r/sp.result@stripped, 2006-12-12 01:59:18+03:00, kostja@stripped +0 -17
    Manual merge: use local.
    MERGE: 1.170.1.46

  mysql-test/t/ps.test@stripped, 2006-12-12 01:57:53+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.56.1.25

  mysql-test/t/sp.test@stripped, 2006-12-12 01:57:53+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.174.1.32

  sql/mysql_priv.h@stripped, 2006-12-12 01:57:54+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.290.1.134

  sql/sql_class.cc@stripped, 2006-12-12 01:57:54+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.223.1.32

  sql/sql_class.h@stripped, 2006-12-12 02:15:45+03:00, kostja@stripped +1 -2
    Manual merge.
    MERGE: 1.230.1.83

  sql/sql_insert.cc@stripped, 2006-12-12 02:15:45+03:00, kostja@stripped +2 -5
    Manual merge.
    MERGE: 1.146.1.62

  sql/sql_lex.cc@stripped, 2006-12-12 01:57:54+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.142.1.66

  sql/sql_lex.h@stripped, 2006-12-12 02:15:45+03:00, kostja@stripped +2 -0
    Manual merge.
    MERGE: 1.175.1.58

  sql/sql_list.h@stripped, 2006-12-12 01:57:55+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.39.1.2

  sql/sql_parse.cc@stripped, 2006-12-12 02:15:45+03:00, kostja@stripped +12 -20
    Manual merge.
    MERGE: 1.426.1.167

  sql/sql_prepare.cc@stripped, 2006-12-12 01:57:55+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.142.1.45

  sql/sql_show.cc@stripped, 2006-12-12 01:57:55+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.253.1.80

  sql/sql_table.cc@stripped, 2006-12-12 02:15:45+03:00, kostja@stripped +18 -42
    Manual merge.
    MERGE: 1.239.1.89

  sql/sql_yacc.yy@stripped, 2006-12-12 02:15:45+03:00, kostja@stripped +9 -14
    Manual merge.
    MERGE: 1.371.1.128

  tests/mysql_client_test.c@stripped, 2006-12-12 02:15:46+03:00, kostja@stripped +1 -1
    Manual merge.
    MERGE: 1.167.1.51

# 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.1-4968/RESYNC

--- 1.460/sql/mysql_priv.h	2006-12-12 02:15:57 +03:00
+++ 1.461/sql/mysql_priv.h	2006-12-12 02:15:57 +03:00
@@ -922,27 +922,22 @@ 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 use_copy_create_info);
 
 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);
 bool mysql_rename_table(handlerton *base, const char *old_db,
                         const char * old_name, const char *new_db,
                         const char * new_name, uint flags);
-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,
@@ -1050,7 +1045,8 @@ int get_quote_char_for_identifier(THD *t
 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.301/sql/sql_class.cc	2006-12-12 02:15:57 +03:00
+++ 1.302/sql/sql_class.cc	2006-12-12 02:15:57 +03:00
@@ -985,6 +985,13 @@ void select_result::cleanup()
   /* do nothing */
 }
 
+bool select_result::check_simple_select() const
+{
+  my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
+  return TRUE;
+}
+
+
 static String default_line_term("\n",default_charset_info);
 static String default_escaped("\\",default_charset_info);
 static String default_field_term("\t",default_charset_info);
@@ -1653,6 +1660,13 @@ int select_dumpvar::prepare(List<Item> &
     }
   }
   return 0;
+}
+
+
+bool select_dumpvar::check_simple_select() const
+{
+  my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0));
+  return TRUE;
 }
 
 

--- 1.330/sql/sql_class.h	2006-12-12 02:15:57 +03:00
+++ 1.331/sql/sql_class.h	2006-12-12 02:15:57 +03:00
@@ -1703,7 +1703,14 @@ public:
   virtual bool initialize_tables (JOIN *join=0) { return 0; }
   virtual void send_error(uint errcode,const char *err);
   virtual bool send_eof()=0;
-  virtual bool simple_select() { return 0; }
+  /**
+    Check if this query returns a result set and therefore is allowed in
+    cursors and set an error message if it is not the case.
+
+    @retval FALSE     success
+    @retval TRUE      error, an error message is set
+  */
+  virtual bool check_simple_select() const;
   virtual void abort() {}
   /*
     Cleanup instance of this class for next execution of a prepared
@@ -1741,7 +1748,7 @@ public:
   bool send_fields(List<Item> &list, uint flags);
   bool send_data(List<Item> &items);
   bool send_eof();
-  bool simple_select() { return 1; }
+  virtual bool check_simple_select() const { return FALSE; }
   void abort();
 };
 
@@ -1813,20 +1820,20 @@ 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;
+  Alter_info *alter_info;
   Field **field;
 public:
-  select_create (TABLE_LIST *table,
-		 HA_CREATE_INFO *create_info_par,
-		 List<create_field> &fields_par,
-		 List<Key> &keys_par,
-		 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_create(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),
+    create_info(create_info_arg),
+    alter_info(alter_info_arg)
+  {}
   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 
   void binlog_show_create_table(TABLE **tables, uint count);
@@ -2188,6 +2195,7 @@ public:
   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
   bool send_data(List<Item> &items);
   bool send_eof();
+  virtual bool check_simple_select() const;
   void cleanup();
 };
 

--- 1.234/sql/sql_insert.cc	2006-12-12 02:15:57 +03:00
+++ 1.235/sql/sql_insert.cc	2006-12-12 02:15:57 +03:00
@@ -2795,11 +2795,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
@@ -2822,8 +2822,7 @@ 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,
+                                      Alter_info *alter_info,
                                       List<Item> *items,
                                       MYSQL_LOCK **lock,
                                       TABLEOP_HOOKS *hooks)
@@ -2868,7 +2867,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
@@ -2889,7 +2888,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,
+                            create_info, alter_info, 0,
                             select_field_count, 0))
     {
       /*
@@ -2988,7 +2987,7 @@ select_create::prepare(List<Item> &value
 #endif
 
   if (!(table= create_table_from_items(thd, create_info, create_table,
-                                       extra_fields, keys, &values,
+                                       alter_info, &values,
                                        &thd->extra_lock, hook_ptr)))
     DBUG_RETURN(-1);				// abort() deletes table
 

--- 1.210/sql/sql_lex.cc	2006-12-12 02:15:57 +03:00
+++ 1.211/sql/sql_lex.cc	2006-12-12 02:15:57 +03:00
@@ -1071,6 +1071,17 @@ int MYSQLlex(void *arg, void *yythd)
 }
 
 
+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)
+{}
+
+
 /*
   Skip comment in the end of statement.
 

--- 1.249/sql/sql_lex.h	2006-12-12 02:15:57 +03:00
+++ 1.250/sql/sql_lex.h	2006-12-12 02:15:57 +03:00
@@ -729,26 +729,62 @@ typedef class st_select_lex SELECT_LEX;
 #define ALTER_REMOVE_PARTITIONING (1L << 25)
 #define ALTER_FOREIGN_KEY         (1L << 26)
 
-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;
   List<char>                  partition_names;
   uint                        no_parts;
 
-  st_alter_info(){clear();}
-  void clear()
+  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();
+    partition_names.empty();
+    no_parts= 0;
+    flags= 0;
     keys_onoff= LEAVE_AS_IS;
     tablespace_op= NO_TABLESPACE_OP;
-    no_parts= 0;
-    partition_names.empty();
   }
-  void reset(){drop_list.empty();alter_list.empty();clear();}
-} ALTER_INFO;
+  /**
+    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.
+    The constructed copy still shares key Key, Alter_drop, create_field
+    and Alter_column elements of the lists - these structures are not
+    modified and thus are not copied.
+
+    @note You need to use check thd->is_fatal_error for out
+    of memory condition after calling this function.
+  */
+  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
 {
@@ -948,8 +984,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;
@@ -1052,7 +1086,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.41/sql/sql_list.h	2006-12-12 02:15:57 +03:00
+++ 1.42/sql/sql_list.h	2006-12-12 02:15:57 +03:00
@@ -62,21 +62,24 @@ public:
   pointer.
 */
 
-class list_node :public Sql_alloc
+
+/**
+  list_node - a node of a single-linked list.
+  @note We never call a destructor for instances of this class.
+*/
+
+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 +95,57 @@ public:
 
   inline void empty() { elements=0; first= &end_of_list; last=&first;}
   inline base_list() { empty(); }
+  /**
+    This is a shallow copy constructor that implicitly passes the ownership
+    from the source list to the new instance. The old instance is not
+    updated, so both objects end up sharing the same nodes. If one of
+    the instances then adds or removes a node, the other becomes out of
+    sync ('last' pointer), while still operational. Some old code uses and
+    relies on this behaviour. This logic is quite tricky: please do not use
+    it in any new code.
+  */
   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)
+  {
+    if (rhs.elements)
+    {
+      /*
+        It's okay to allocate an array of nodes at once: we never
+        call a destructor for list_node objects anyway.
+      */
+      first= (list_node*) alloc_root(mem_root,
+                                     sizeof(list_node) * rhs.elements);
+      if (first)
+      {
+        elements= rhs.elements;
+        list_node *dst= first;
+        list_node *src= rhs.first;
+        for (; dst < first + elements - 1; dst++, src= src->next)
+        {
+          dst->info= src->info;
+          dst->next= dst + 1;
+        }
+        /* Copy the last node */
+        dst->info= src->info;
+        dst->next= &end_of_list;
+        /* Setup 'last' member */
+        last= &dst->next;
+        return;
+      }
+    }
+    elements= 0;
+    first= &end_of_list;
+    last= &first;
+  }
   inline base_list(bool error) { }
   inline bool push_back(void *info)
   {
@@ -348,6 +396,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.600/sql/sql_parse.cc	2006-12-12 02:15:57 +03:00
+++ 1.601/sql/sql_parse.cc	2006-12-12 02:15:57 +03:00
@@ -2948,17 +2948,34 @@ mysql_execute_command(THD *thd)
     // 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;
+    /*
+      Code below (especially in mysql_create_table() and select_create
+      methods) may modify HA_CREATE_INFO structure in LEX, so we have to
+      use a copy of this structure to make execution prepared statement-
+      safe. A shallow copy is enough as this code won't modify any memory
+      referenced from this structure.
+    */
+    HA_CREATE_INFO create_info(lex->create_info);
+    Alter_info alter_info(lex->alter_info, thd->mem_root);
+
+    if (thd->is_fatal_error)
+    {
+      /* out of memory when creating a copy of alter_info */
+      res= 1;
+      goto end_with_restore_list;
+    }
 
     if ((res= create_table_precheck(thd, select_tables, create_table)))
       goto end_with_restore_list;
 
+
 #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= NULL;
 #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
@@ -2966,14 +2983,14 @@ mysql_execute_command(THD *thd)
       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
@@ -3018,7 +3035,7 @@ mysql_execute_command(THD *thd)
           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)))
@@ -3029,10 +3046,10 @@ mysql_execute_command(THD *thd)
           }
         }
         /* 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)
           {
@@ -3045,14 +3062,16 @@ mysql_execute_command(THD *thd)
             }
           }
         }
-
+        /*
+          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(create_table,
-				       &lex->create_info,
-				       lex->create_list,
-				       lex->key_list,
-				       select_lex->item_list,
-				       lex->duplicates,
-				       lex->ignore)))
+                                       &create_info,
+                                       &alter_info,
+                                       select_lex->item_list,
+                                       lex->duplicates,
+                                       lex->ignore)))
         {
           /*
             CREATE from SELECT give its SELECT_LEX for SELECT,
@@ -3061,9 +3080,6 @@ 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
@@ -3073,14 +3089,13 @@ mysql_execute_command(THD *thd)
         thd->options|= OPTION_KEEP_LOG;
       /* regular create */
       if (lex->like_name)
-        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
-                                     lex->like_name); 
+        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,
-				lex->create_list,
-				lex->key_list, 0, 0, 1);
+                                create_table->table_name, &create_info,
+                                &alter_info, 0, 0);
       }
       if (!res)
 	send_ok(thd);
@@ -3092,15 +3107,48 @@ end_with_restore_list:
     break;
   }
   case SQLCOM_CREATE_INDEX:
+    /* Fall through */
+  case SQLCOM_DROP_INDEX:
+  /*
+    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.
+  */
+  {
+    Alter_info alter_info(lex->alter_info, thd->mem_root);
+    HA_CREATE_INFO create_info;
+
+    if (thd->is_fatal_error) /* out of memory creating a copy of alter_info*/
+      goto error;
+
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
-    if (check_one_table_access(thd, INDEX_ACL, all_tables))
+    if (check_one_table_access(thd, INDEX_ACL, first_table))
       goto error; /* purecov: inspected */
-    thd->enable_slow_log= opt_log_slow_admin_statements;
     if (end_active_trans(thd))
       goto error;
-    res= mysql_create_index(thd, first_table, lex->key_list);
-    break;
+    /*
+      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;
 
+    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:
   {
@@ -3142,6 +3190,18 @@ end_with_restore_list:
     {
       ulong priv=0;
       ulong priv_needed= ALTER_ACL;
+      /*
+        Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
+        so we have to use a copy of this structure to make execution
+        prepared statement- safe. A shallow copy is enough as no memory
+        referenced from this structure will be modified.
+      */
+      HA_CREATE_INFO create_info(lex->create_info);
+      Alter_info alter_info(lex->alter_info, thd->mem_root);
+
+      if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
+        goto error;
+
       /* We also require DROP priv for ALTER TABLE ... DROP PARTITION */
       if (lex->alter_info.flags & ALTER_DROP_PARTITION)
         priv_needed|= DROP_ACL;
@@ -3155,7 +3215,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)
       {
@@ -3174,13 +3234,13 @@ end_with_restore_list:
 	}
       }
       /* 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= NULL;
       /* ALTER TABLE ends previous transaction */
       if (end_active_trans(thd))
 	goto error;
@@ -3194,12 +3254,12 @@ end_with_restore_list:
 
       thd->enable_slow_log= opt_log_slow_admin_statements;
       res= mysql_alter_table(thd, select_lex->db, lex->name.str,
-                             &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;
     }
   case SQLCOM_RENAME_TABLE:
@@ -3343,7 +3403,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)
@@ -3661,14 +3721,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;
-    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))
@@ -3803,6 +3855,12 @@ end_with_restore_list:
     break;
   case SQLCOM_CREATE_DB:
   {
+    /*
+      As mysql_create_db() may modify HA_CREATE_INFO structure passed to
+      it, we need to use a copy of LEX::create_info to make execution
+      prepared statement- safe.
+    */
+    HA_CREATE_INFO create_info(lex->create_info);
     if (end_active_trans(thd))
     {
       res= -1;
@@ -3831,11 +3889,12 @@ end_with_restore_list:
       break;
     }
 #endif
+
     if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
                      is_schema_db(lex->name.str)))
       break;
-    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
-                              lex->name.str), &lex->create_info, 0);
+    res= mysql_create_db(thd, (lower_case_table_names == 2 ? alias :
+                               lex->name.str), &create_info, 0);
     break;
   }
   case SQLCOM_DROP_DB:
@@ -4639,7 +4698,7 @@ end_with_restore_list:
             goto error;
         }
 
-	my_bool nsok= thd->net.no_send_ok;
+	my_bool save_no_send_ok= thd->net.no_send_ok;
 	thd->net.no_send_ok= TRUE;
 	if (sp->m_flags & sp_head::MULTI_RESULTS)
 	{
@@ -4650,7 +4709,7 @@ end_with_restore_list:
               back
             */
 	    my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
-	    thd->net.no_send_ok= nsok;
+	    thd->net.no_send_ok= save_no_send_ok;
 	    goto error;
 	  }
           /*
@@ -4666,7 +4725,7 @@ end_with_restore_list:
 	if (check_routine_access(thd, EXECUTE_ACL,
 				 sp->m_db.str, sp->m_name.str, TRUE, FALSE))
 	{
-	  thd->net.no_send_ok= nsok;
+	  thd->net.no_send_ok= save_no_send_ok;
 	  goto error;
 	}
 #endif
@@ -4693,7 +4752,7 @@ end_with_restore_list:
 
 	thd->variables.select_limit= select_limit;
 
-	thd->net.no_send_ok= nsok;
+	thd->net.no_send_ok= save_no_send_ok;
         thd->server_status&= ~bits_to_be_cleared;
 
 	if (!res)
@@ -6184,17 +6243,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,
-                                    &default_key_create_info,
-				    0, lex->col_list));
+    lex->alter_info.key_list.push_back(new Key(Key::PRIMARY, NullS,
+                                               &default_key_create_info,
+                                               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,
-                                    &default_key_create_info, 0,
-				    lex->col_list));
+    lex->alter_info.key_list.push_back(new Key(Key::UNIQUE, NullS,
+                                               &default_key_create_info, 0,
+                                               lex->col_list));
     lex->col_list.empty();
   }
 
@@ -6254,7 +6313,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);
 }
@@ -7274,53 +7333,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= 0;
-  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= 0;
-  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.376/sql/sql_show.cc	2006-12-12 02:15:57 +03:00
+++ 1.377/sql/sql_show.cc	2006-12-12 02:15:57 +03:00
@@ -693,7 +693,7 @@ mysqld_show_create(THD *thd, TABLE_LIST 
 }
 
 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.375/sql/sql_table.cc	2006-12-12 02:15:57 +03:00
+++ 1.376/sql/sql_table.cc	2006-12-12 02:15:57 +03:00
@@ -2161,8 +2161,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
       tmp_table                 If a temporary table is to be created.
       db_options          INOUT Table options (like HA_OPTION_PACK_RECORD).
       file                      The handler for the new table.
@@ -2182,8 +2181,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)
@@ -2197,11 +2196,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();
@@ -2526,7 +2526,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;
@@ -3162,18 +3163,14 @@ static HA_CREATE_INFO *copy_create_info(
 
   SYNOPSIS
     mysql_create_table_internal()
-    thd			Thread object
-    db			Database
-    table_name		Table name
-    lex_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.
+    thd			 Thread object
+    db			 Database
+    table_name		 Table name
+    create_info [in/out] Create information (like MAX_ROWS)
+    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)
+    select_field_count
 
   DESCRIPTION
     If one creates a temporary table, this is automatically opened
@@ -3183,6 +3180,11 @@ static HA_CREATE_INFO *copy_create_info(
     select_field_count is also used for CREATE ... SELECT,
     and must be zero for standard create of table.
 
+    Note that structures passed as 'create_info' and 'alter_info' parameters
+    may be modified by this function. It is responsibility of the caller to
+    make a copy of create_info in order to provide correct execution in
+    prepared statements/stored routines.
+
   RETURN VALUES
     FALSE OK
     TRUE  error
@@ -3190,36 +3192,25 @@ static HA_CREATE_INFO *copy_create_info(
 
 bool mysql_create_table_internal(THD *thd,
                                 const char *db, const char *table_name,
-                                HA_CREATE_INFO *lex_create_info,
-                                List<create_field> &fields,
-                                List<Key> &keys,bool internal_tmp_table,
-                                uint select_field_count,
-                                bool use_copy_create_info)
+                                HA_CREATE_INFO *create_info,
+                                Alter_info *alter_info,
+                                bool internal_tmp_table,
+                                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)
+  if (!alter_info->create_list.elements)
   {
     my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
                MYF(0));
@@ -3398,10 +3389,10 @@ bool mysql_create_table_internal(THD *th
 
   set_table_default_charset(thd, create_info, (char*) db);
 
-  if (mysql_prepare_table(thd, create_info, &fields,
-			  &keys, internal_tmp_table, &db_options, file,
-			  &key_info_buffer, &key_count,
-			  select_field_count))
+  if (mysql_prepare_table(thd, create_info, alter_info, internal_tmp_table,
+                          &db_options, file,
+                          &key_info_buffer, &key_count,
+                          select_field_count))
     goto err;
 
       /* Check if table exists */
@@ -3505,7 +3496,8 @@ bool mysql_create_table_internal(THD *th
   create_info->table_options=db_options;
 
   path[path_length - reg_ext_length]= '\0'; // Remove .frm extension
-  if (rea_create_table(thd, path, db, table_name, create_info, fields,
+  if (rea_create_table(thd, path, db, table_name,
+                       create_info, alter_info->create_list,
                        key_count, key_info_buffer, file))
     goto unlock_and_end;
 
@@ -4226,10 +4218,13 @@ static bool mysql_admin_table(THD* thd, 
           (table->table->file->ha_check_for_upgrade(check_opt) ==
            HA_ADMIN_NEEDS_ALTER))
       {
+        my_bool save_no_send_ok= thd->net.no_send_ok;
         ha_autocommit_or_rollback(thd, 1);
         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= save_no_send_ok;
         reenable_binlog(thd);
         goto send_result;
       }
@@ -4308,6 +4303,7 @@ send_result_message:
 
     case HA_ADMIN_TRY_ALTER:
     {
+      my_bool save_no_send_ok= 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,
@@ -4319,7 +4315,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= save_no_send_ok;
       reenable_binlog(thd);
       ha_autocommit_or_rollback(thd, 0);
       close_thread_tables(thd);
@@ -5196,14 +5194,20 @@ static uint compare_tables(TABLE *table,
 
 /*
   Alter table
+
+
+  NOTE
+    The structures passed as 'create_info' and 'alter_info' parameters may
+    be modified by this function. It is responsibility of the caller to make
+    a copy of create_info in order to provide correct execution in prepared
+    statements/stored routines.
 */
 
 bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
                        HA_CREATE_INFO *lex_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;
@@ -5499,8 +5503,7 @@ view_err:
     if (!error)
     {
       write_bin_log(thd, TRUE, thd->query, thd->query_length);
-      if (do_send_ok)
-        send_ok(thd);
+      send_ok(thd);
     }
     else if (error > 0)
     {
@@ -5529,10 +5532,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;
 
   /*
@@ -5580,7 +5582,7 @@ view_err:
       def->field=field;
       if (!def->after)
       {
-	create_list.push_back(def);
+	new_info.create_list.push_back(def);
 	def_it.remove();
       }
     }
@@ -5590,7 +5592,7 @@ view_err:
         This field was not dropped and not changed, add it to the list
         for the new table.
       */
-      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++))
@@ -5614,7 +5616,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)
@@ -5623,9 +5625,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;
@@ -5649,7 +5651,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));
@@ -5661,8 +5663,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;
@@ -5736,6 +5738,9 @@ view_err:
     if (key_parts.elements)
     {
       KEY_CREATE_INFO key_create_info;
+      Key *key;
+      enum Key::Keytype key_type;
+
       bzero((char*) &key_create_info, sizeof(key_create_info));
 
       key_create_info.algorithm= key_info->algorithm;
@@ -5744,17 +5749,25 @@ view_err:
       if (key_info->flags & HA_USES_PARSER)
         key_create_info.parser_name= *key_info->parser_name;
 
-      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_create_info,
-                                 test(key_info->flags & HA_GENERATED_KEY),
-				 key_parts));
+      if (key_info->flags & HA_SPATIAL)
+        key_type= Key::SPATIAL;
+      else if (key_info->flags & HA_NOSAME)
+      {
+        if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
+          key_type= Key::PRIMARY;
+        else
+          key_type= Key::UNIQUE;
+      }
+      else if (key_info->flags & HA_FULLTEXT)
+        key_type= Key::FULLTEXT;
+      else
+        key_type= Key::MULTIPLE;
+
+      key= new Key(key_type, key_name,
+                   &key_create_info,
+                   test(key_info->flags & HA_GENERATED_KEY),
+                   key_parts);
+      new_info.key_list.push_back(key);
     }
   }
   {
@@ -5762,7 +5775,7 @@ view_err:
     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))
       {
@@ -6070,7 +6083,7 @@ view_err:
   */
   tmp_disable_binlog(thd);
   error= mysql_create_table(thd, new_db, tmp_name,
-                            create_info,create_list,key_list,1,0,0);
+                            create_info, &new_info, 1, 0);
   reenable_binlog(thd);
   if (error)
     DBUG_RETURN(error);
@@ -6110,8 +6123,9 @@ view_err:
     /* We don't want update TIMESTAMP fields during ALTER TABLE. */
     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->count_cuted_fields= CHECK_FIELD_IGNORE;
 
@@ -6503,8 +6517,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);
 
@@ -6721,31 +6734,26 @@ copy_data_between_tables(TABLE *from,TAB
     mysql_recreate_table()
     thd			Thread handler
     tables		Tables to recreate
-    do_send_ok          If we should send_ok() or leave it to caller
 
  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));
+  Alter_info alter_info;
+
+  DBUG_ENTER("mysql_recreate_table");
+
+  bzero((char*) &create_info, sizeof(create_info));
   create_info.db_type= 0;
   create_info.row_type=ROW_TYPE_NOT_USED;
   create_info.default_table_charset=default_charset_info;
   /* Force alter table to recreate table */
-  lex->alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
+  alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
   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, &alter_info,
+                                0, (ORDER *) 0, 0));
 }
 
 

--- 1.519/sql/sql_yacc.yy	2006-12-12 02:15:57 +03:00
+++ 1.520/sql/sql_yacc.yy	2006-12-12 02:15:58 +03:00
@@ -1231,8 +1231,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));
@@ -1254,8 +1253,8 @@ create:
 							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;
 	  }
@@ -1267,8 +1266,9 @@ create:
 	      yyerror(ER(ER_SYNTAX_ERROR));
 	      YYABORT;
 	    }
-	    lex->key_list.push_back(new Key($2, $4.str, &lex->key_create_info, 0,
-					   lex->col_list));
+            Key *key= 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
@@ -4065,8 +4065,9 @@ key_def:
 	      yyerror(ER(ER_SYNTAX_ERROR));
 	      YYABORT;
 	    }
-	    lex->key_list.push_back(new Key($1,$2, &lex->key_create_info, 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
@@ -4074,22 +4075,25 @@ key_def:
 	  {
 	    LEX *lex=Lex;
 	    const char *key_name= $3 ? $3 : $1;
-	    lex->key_list.push_back(new Key($2, key_name, &lex->key_create_info, 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,
-					    &default_key_create_info, 1,
-					    lex->col_list));
+            const char *key_name= $4 ? $4 : $1;
+            Key *key= new foreign_key(key_name, 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, key_name,
+                         &default_key_create_info, 1,
+                         lex->col_list);
+            lex->alter_info.key_list.push_back(key);
 	    lex->col_list.empty();		/* Alloced by sql_alloc */
 
             /* Only used for ALTER TABLE. Ignored otherwise. */
@@ -4679,8 +4683,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->like_name= 0;
@@ -4691,7 +4693,6 @@ alter:
 	  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->no_write_to_binlog= 0;
 	}
 	alter_commands
@@ -7687,7 +7688,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.206/mysql-test/t/sp.test	2006-12-12 02:15:58 +03:00
+++ 1.207/mysql-test/t/sp.test	2006-12-12 02:15:58 +03:00
@@ -6587,6 +6587,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
 
 --echo Begin of 5.1 tests

--- 1.90/mysql-test/t/ps.test	2006-12-12 02:15:58 +03:00
+++ 1.91/mysql-test/t/ps.test	2006-12-12 02:15:58 +03:00
@@ -1117,10 +1117,80 @@ EXECUTE stmt USING @a;
 DEALLOCATE PREPARE stmt;
 DROP TABLE t1;
 
+#
+# 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, t2;
+--enable_warnings
 
---echo End of 4.1 tests.
+CREATE TABLE t1 (i INT);
 
+PREPARE st_19182
+FROM "CREATE TABLE t2 (i INT, j INT, KEY (i), 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 keys
+# on 'i' and 'j' columns.
+EXECUTE st_19182;
+DESC t2;
+
+DEALLOCATE PREPARE st_19182;
+DROP TABLE t2, t1;
+
+#
+# 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
+# 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;
+
+--echo End of 4.1 tests.
 
 ############################# 5.0 tests start ################################
 #
@@ -1551,6 +1621,78 @@ execute no_index;
 execute sq;
 deallocate prepare no_index;
 deallocate prepare sq;
+
+#
+# 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#6895 "Prepared Statements: ALTER TABLE DROP COLUMN does nothing"
+#
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (a int, b int);
+prepare s_6895 from "alter table t1 drop column b";
+execute s_6895;
+show columns from t1;
+drop table t1;
+create table t1 (a int, b int);
+execute s_6895;
+show columns from t1;
+drop table t1;
+create table t1 (a int, b int);
+execute s_6895;
+show columns from t1;
+deallocate prepare s_6895;
+drop table t1;
+
+#
+# Bug #22060 "ALTER TABLE x AUTO_INCREMENT=y in SP crashes server"
+#
+# 5.0 part of the test.
+#
+
+# 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;
+# 5.1 part of the test.
+# 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;
 
 --echo End of 5.0 tests.
 

--- 1.184/sql/sql_prepare.cc	2006-12-12 02:15:58 +03:00
+++ 1.185/sql/sql_prepare.cc	2006-12-12 02:15:58 +03:00
@@ -2947,10 +2947,9 @@ bool Prepared_statement::execute(String 
     in INSERT ... SELECT and similar commands.
   */
 
-  if (open_cursor && lex->result &&
!lex->result->simple_select())
+  if (open_cursor && lex->result &&
lex->result->check_simple_select())
   {
     DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
-    my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
     return TRUE;
   }
 

--- 1.222/tests/mysql_client_test.c	2006-12-12 02:15:58 +03:00
+++ 1.223/tests/mysql_client_test.c	2006-12-12 02:15:58 +03:00
@@ -15684,6 +15684,33 @@ static void test_bug21635()
   DBUG_VOID_RETURN;
 }
 
+/*
+  Bug#24179 "select b into $var" fails with --cursor_protocol"
+  The failure is correct, check that the returned message is meaningful.
+*/
+
+static void test_bug24179()
+{
+  int rc;
+  MYSQL_STMT *stmt;
+
+  DBUG_ENTER("test_bug24179");
+  myheader("test_bug24179");
+
+  stmt= open_cursor("select 1 into @a");
+  rc= mysql_stmt_execute(stmt);
+  DIE_UNLESS(rc);
+  if (!opt_silent)
+  {
+    printf("Got error (as expected): %d %s\n",
+           mysql_stmt_errno(stmt),
+           mysql_stmt_error(stmt));
+  }
+  DIE_UNLESS(mysql_stmt_errno(stmt) == 1323);
+
+  DBUG_VOID_RETURN;
+}
+
 
 /*
   Read and parse arguments and MySQL options from my.cnf
@@ -15966,6 +15993,7 @@ static struct my_tests_st my_tests[]= {
   { "test_bug23383", test_bug23383 },
   { "test_bug21635", test_bug21635 },
   { "test_status", test_status},
+  { "test_bug24179", test_bug24179 },
   { 0, 0 }
 };
 
Thread
bk commit into 5.1 tree (kostja:1.2390)konstantin12 Dec