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-11-01 15:56:12+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#6895 "Prepared Statements: ALTER TABLE DROP COLUMN does nothing"
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-11-01 15:56:06+03:00, kostja@stripped +46 -0
Update test results (Bug#19182, Bug#4968, Bug#6895)
mysql-test/r/sp.result@stripped, 2006-11-01 15:56:06+03:00, kostja@stripped +17 -0
Update test results (Bug#19733)
mysql-test/t/ps.test@stripped, 2006-11-01 15:56:06+03:00, kostja@stripped +67 -0
Add a test case for Bug#19182, Bug#4968, Bug#6895
mysql-test/t/sp.test@stripped, 2006-11-01 15:56:06+03:00, kostja@stripped +28 -0
Add a test case for Bug#19733
sql/mysql_priv.h@stripped, 2006-11-01 15:56:06+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-11-01 15:56:07+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-11-01 15:56:07+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-11-01 15:56:07+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-11-01 15:56:07+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-11-01 15:56:07+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-11-01 15:56:07+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-11-01 15:56:07+03:00, kostja@stripped +65 -63
Adjust mysql_alter_table, mysql_recreate_table, mysql_create_table,
mysql_prepare_table to new signatures.
sql/sql_yacc.yy@stripped, 2006-11-01 15:56:08+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-11-01 15:56:23 +03:00
+++ 1.418/sql/mysql_priv.h 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.307/sql/sql_class.h 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.207/sql/sql_insert.cc 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.204/sql/sql_lex.cc 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.231/sql/sql_lex.h 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.41/sql/sql_list.h 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.587/sql/sql_parse.cc 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.325/sql/sql_table.cc 2006-11-01 15:56:23 +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,26 +4001,22 @@ 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));
+ Alter_info alter_info;
+
+ DBUG_ENTER("mysql_recreate_table");
+
+ bzero((char*) &create_info, sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
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_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, &alter_info,
+ 0, (ORDER *) 0, 0));
}
--- 1.493/sql/sql_yacc.yy 2006-11-01 15:56:23 +03:00
+++ 1.494/sql/sql_yacc.yy 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.216/mysql-test/r/sp.result 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.205/mysql-test/t/sp.test 2006-11-01 15:56:23 +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-11-01 15:56:23 +03:00
+++ 1.79/mysql-test/r/ps.result 2006-11-01 15:56:23 +03:00
@@ -1476,4 +1476,50 @@ 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;
+create table t1 (a int, b int);
+prepare s_6895 from "alter table t1 drop column b";
+execute s_6895;
+show columns from t1;
+Field Type Null Key Default Extra
+a int(11) YES NULL
+drop table t1;
+create table t1 (a int, b int);
+execute s_6895;
+show columns from t1;
+Field Type Null Key Default Extra
+a int(11) YES NULL
+drop table t1;
+create table t1 (a int, b int);
+execute s_6895;
+show columns from t1;
+Field Type Null Key Default Extra
+a int(11) YES NULL
+deallocate prepare s_6895;
+drop table t1;
+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-11-01 15:56:23 +03:00
+++ 1.75/mysql-test/t/ps.test 2006-11-01 15:56:23 +03:00
@@ -1532,5 +1532,72 @@ 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#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#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#19182 | konstantin | 1 Nov |