Commit 095e2527 authored by unknown's avatar unknown

Merge bk-internal.mysql.com:/home/bk/mysql-5.0

into  bodhi.local:/opt/local/work/mysql-5.0-runtime

parents 7118b2c3 2ba119c6
...@@ -1055,6 +1055,73 @@ EXECUTE stmt USING @a; ...@@ -1055,6 +1055,73 @@ EXECUTE stmt USING @a;
0 0 0 0
DEALLOCATE PREPARE stmt; DEALLOCATE PREPARE stmt;
DROP TABLE t1; DROP TABLE t1;
DROP TABLE IF EXISTS t1, t2;
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;
Field Type Null Key Default Extra
j int(11) YES MUL NULL
i int(11) YES MUL 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 MUL NULL
DEALLOCATE PREPARE st_19182;
DROP TABLE t2, t1;
drop database if exists mysqltest;
drop table if exists t1, t2;
create database mysqltest character set utf8;
prepare stmt1 from "create table mysqltest.t1 (c char(10))";
prepare stmt2 from "create table mysqltest.t2 select 'test'";
execute stmt1;
execute stmt2;
show create table mysqltest.t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c` char(10) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
show create table mysqltest.t2;
Table Create Table
t2 CREATE TABLE `t2` (
`test` varchar(4) character set latin1 NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=utf8
drop table mysqltest.t1;
drop table mysqltest.t2;
alter database mysqltest character set latin1;
execute stmt1;
execute stmt2;
show create table mysqltest.t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c` char(10) character set utf8 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table mysqltest.t2;
Table Create Table
t2 CREATE TABLE `t2` (
`test` varchar(4) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop database mysqltest;
deallocate prepare stmt1;
deallocate prepare stmt2;
execute stmt;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c` char(10) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
execute stmt;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c` char(10) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
deallocate prepare stmt;
End of 4.1 tests. End of 4.1 tests.
create table t1 (a varchar(20)); create table t1 (a varchar(20));
insert into t1 values ('foo'); insert into t1 values ('foo');
...@@ -1536,4 +1603,54 @@ a ...@@ -1536,4 +1603,54 @@ a
2 2
DEALLOCATE PREPARE stmt; DEALLOCATE PREPARE stmt;
DROP TABLE t1,t2; DROP TABLE t1,t2;
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;
create table t1 (i int primary key auto_increment) comment='comment for table t1';
create table t2 (i int, j int, k int);
prepare stmt from "alter table t1 auto_increment=100";
execute stmt;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) NOT NULL auto_increment,
PRIMARY KEY (`i`)
) ENGINE=MyISAM AUTO_INCREMENT=100 DEFAULT CHARSET=latin1 COMMENT='comment for table t1'
flush tables;
select * from t2;
i j k
execute stmt;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) NOT NULL auto_increment,
PRIMARY KEY (`i`)
) ENGINE=MyISAM AUTO_INCREMENT=100 DEFAULT CHARSET=latin1 COMMENT='comment for table t1'
deallocate prepare stmt;
drop table t1, t2;
End of 5.0 tests. End of 5.0 tests.
...@@ -5626,6 +5626,23 @@ Called B ...@@ -5626,6 +5626,23 @@ Called B
Called B Called B
drop procedure proc_21462_a| drop procedure proc_21462_a|
drop procedure proc_21462_b| 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 End of 5.0 tests
DROP TABLE IF EXISTS bug23760| DROP TABLE IF EXISTS bug23760|
DROP TABLE IF EXISTS bug23760_log| DROP TABLE IF EXISTS bug23760_log|
......
...@@ -1106,10 +1106,80 @@ EXECUTE stmt USING @a; ...@@ -1106,10 +1106,80 @@ EXECUTE stmt USING @a;
DEALLOCATE PREPARE stmt; DEALLOCATE PREPARE stmt;
DROP TABLE t1; 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 ################################ ############################# 5.0 tests start ################################
# #
...@@ -1585,5 +1655,76 @@ EXECUTE stmt USING @arg; ...@@ -1585,5 +1655,76 @@ EXECUTE stmt USING @arg;
DEALLOCATE PREPARE stmt; DEALLOCATE PREPARE stmt;
DROP TABLE t1,t2; DROP TABLE t1,t2;
#
# 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. --echo End of 5.0 tests.
...@@ -6587,6 +6587,34 @@ call proc_21462_b(1)| ...@@ -6587,6 +6587,34 @@ call proc_21462_b(1)|
drop procedure proc_21462_a| drop procedure proc_21462_a|
drop procedure proc_21462_b| 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 End of 5.0 tests
......
...@@ -773,17 +773,15 @@ int prepare_create_field(create_field *sql_field, ...@@ -773,17 +773,15 @@ int prepare_create_field(create_field *sql_field,
uint table_flags); uint table_flags);
bool mysql_create_table(THD *thd,const char *db, const char *table_name, bool mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
List<create_field> &fields, List<Key> &keys, Alter_info *alter_info,
bool tmp_table, uint select_field_count); bool tmp_table, uint select_field_count);
bool mysql_alter_table(THD *thd, char *new_db, char *new_name, bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
TABLE_LIST *table_list, TABLE_LIST *table_list,
List<create_field> &fields, Alter_info *alter_info,
List<Key> &keys, uint order_num, ORDER *order, bool ignore);
uint order_num, ORDER *order, bool ignore, bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
ALTER_INFO *alter_info, bool do_send_ok);
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
bool mysql_create_like_table(THD *thd, TABLE_LIST *table, bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
Table_ident *src_table); Table_ident *src_table);
...@@ -792,9 +790,6 @@ bool mysql_rename_table(enum db_type base, ...@@ -792,9 +790,6 @@ bool mysql_rename_table(enum db_type base,
const char * old_name, const char * old_name,
const char *new_db, const char *new_db,
const char * new_name); 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, bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
Item **conds, uint order_num, ORDER *order); Item **conds, uint order_num, ORDER *order);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
...@@ -896,7 +891,8 @@ int get_quote_char_for_identifier(THD *thd, const char *name, uint length); ...@@ -896,7 +891,8 @@ int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild); 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); 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(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); void mysqld_list_processes(THD *thd,const char *user,bool verbose);
int mysqld_show_status(THD *thd); int mysqld_show_status(THD *thd);
......
...@@ -1839,21 +1839,22 @@ class select_insert :public select_result_interceptor { ...@@ -1839,21 +1839,22 @@ class select_insert :public select_result_interceptor {
class select_create: public select_insert { class select_create: public select_insert {
ORDER *group; ORDER *group;
TABLE_LIST *create_table; 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; MYSQL_LOCK *lock;
Field **field; Field **field;
public: public:
select_create (TABLE_LIST *table, select_create(TABLE_LIST *table,
HA_CREATE_INFO *create_info_par, HA_CREATE_INFO *create_info_arg,
List<create_field> &fields_par, Alter_info *alter_info_arg,
List<Key> &keys_par, List<Item> &select_fields,
List<Item> &select_fields,enum_duplicates duplic, bool ignore) enum_duplicates duplic, bool ignore)
:select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore), create_table(table), :select_insert(NULL, NULL, &select_fields, 0, 0, duplic, ignore),
extra_fields(&fields_par),keys(&keys_par), create_info(create_info_par), create_table(table),
create_info(create_info_arg),
alter_info(alter_info_arg),
lock(0) lock(0)
{} {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
void store_values(List<Item> &values); void store_values(List<Item> &values);
void send_error(uint errcode,const char *err); void send_error(uint errcode,const char *err);
......
...@@ -2616,11 +2616,11 @@ bool select_insert::send_eof() ...@@ -2616,11 +2616,11 @@ bool select_insert::send_eof()
temporary table flag) temporary table flag)
create_table in Pointer to TABLE_LIST object providing database create_table in Pointer to TABLE_LIST object providing database
and name for table to be created or to be open and name for table to be created or to be open
extra_fields in/out Initial list of fields for table to be created alter_info in/out Initial list of columns and indexes for the table
keys in List of keys for table to be created to be created
items in List of items which should be used to produce rest items in List of items which should be used to produce rest
of fields for the table (corresponding fields will 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 lock out Pointer to the MYSQL_LOCK object for table created
(open) will be returned in this parameter. Since (open) will be returned in this parameter. Since
this table is not included in THD::lock caller is this table is not included in THD::lock caller is
...@@ -2642,8 +2642,8 @@ bool select_insert::send_eof() ...@@ -2642,8 +2642,8 @@ bool select_insert::send_eof()
static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
TABLE_LIST *create_table, TABLE_LIST *create_table,
List<create_field> *extra_fields, Alter_info *alter_info,
List<Key> *keys, List<Item> *items, List<Item> *items,
MYSQL_LOCK **lock) MYSQL_LOCK **lock)
{ {
TABLE tmp_table; // Used during 'create_field()' TABLE tmp_table; // Used during 'create_field()'
...@@ -2682,7 +2682,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, ...@@ -2682,7 +2682,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(0); DBUG_RETURN(0);
if (item->maybe_null) if (item->maybe_null)
cr_field->flags &= ~NOT_NULL_FLAG; cr_field->flags &= ~NOT_NULL_FLAG;
extra_fields->push_back(cr_field); alter_info->create_list.push_back(cr_field);
} }
/* /*
create and lock table create and lock table
...@@ -2703,8 +2703,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, ...@@ -2703,8 +2703,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
{ {
tmp_disable_binlog(thd); tmp_disable_binlog(thd);
if (!mysql_create_table(thd, create_table->db, create_table->table_name, 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))
select_field_count))
{ {
/* /*
If we are here in prelocked mode we either create temporary table If we are here in prelocked mode we either create temporary table
...@@ -2760,7 +2759,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -2760,7 +2759,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
unit= u; unit= u;
table= create_table_from_items(thd, create_info, create_table, table= create_table_from_items(thd, create_info, create_table,
extra_fields, keys, &values, &lock); alter_info, &values, &lock);
if (!table) if (!table)
DBUG_RETURN(-1); // abort() deletes table DBUG_RETURN(-1); // abort() deletes table
......
...@@ -1054,6 +1054,17 @@ int MYSQLlex(void *arg, void *yythd) ...@@ -1054,6 +1054,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. Skip comment in the end of statement.
......
...@@ -686,18 +686,58 @@ typedef class st_select_lex SELECT_LEX; ...@@ -686,18 +686,58 @@ typedef class st_select_lex SELECT_LEX;
#define ALTER_CONVERT 1024 #define ALTER_CONVERT 1024
#define ALTER_FORCE 2048 #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_drop> drop_list;
List<Alter_column> alter_list; List<Alter_column> alter_list;
List<Key> key_list;
List<create_field> create_list;
uint flags; uint flags;
enum enum_enable_or_disable keys_onoff; enum enum_enable_or_disable keys_onoff;
enum tablespace_op_type tablespace_op; enum tablespace_op_type tablespace_op;
st_alter_info(){clear();} Alter_info() :
void clear(){keys_onoff= LEAVE_AS_IS;tablespace_op= NO_TABLESPACE_OP;} flags(0),
void reset(){drop_list.empty();alter_list.empty();clear();} keys_onoff(LEAVE_AS_IS),
} ALTER_INFO; 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.
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 struct st_sp_chistics
{ {
...@@ -883,8 +923,6 @@ typedef struct st_lex : public Query_tables_list ...@@ -883,8 +923,6 @@ typedef struct st_lex : public Query_tables_list
List<String> interval_list; List<String> interval_list;
List<LEX_USER> users_list; List<LEX_USER> users_list;
List<LEX_COLUMN> columns; List<LEX_COLUMN> columns;
List<Key> key_list;
List<create_field> create_list;
List<Item> *insert_list,field_list,value_list,update_list; List<Item> *insert_list,field_list,value_list,update_list;
List<List_item> many_values; List<List_item> many_values;
List<set_var_base> var_list; List<set_var_base> var_list;
...@@ -977,7 +1015,7 @@ typedef struct st_lex : public Query_tables_list ...@@ -977,7 +1015,7 @@ typedef struct st_lex : public Query_tables_list
bool safe_to_cache_query; bool safe_to_cache_query;
bool subqueries, ignore; bool subqueries, ignore;
st_parsing_options parsing_options; st_parsing_options parsing_options;
ALTER_INFO alter_info; Alter_info alter_info;
/* Prepared statements SQL syntax:*/ /* Prepared statements SQL syntax:*/
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */ LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
/* /*
......
...@@ -61,21 +61,24 @@ public: ...@@ -61,21 +61,24 @@ public:
pointer. 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; list_node *next;
void *info; void *info;
list_node(void *info_par,list_node *next_par) list_node(void *info_par,list_node *next_par)
:next(next_par),info(info_par) :next(next_par),info(info_par)
{} {}
list_node() /* For end_of_list */ list_node() /* For end_of_list */
{ {
info=0; info= 0;
next= this; next= this;
} }
friend class base_list;
friend class base_list_iterator;
}; };
...@@ -91,12 +94,57 @@ public: ...@@ -91,12 +94,57 @@ public:
inline void empty() { elements=0; first= &end_of_list; last=&first;} inline void empty() { elements=0; first= &end_of_list; last=&first;}
inline base_list() { empty(); } 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() inline base_list(const base_list &tmp) :Sql_alloc()
{ {
elements= tmp.elements; elements= tmp.elements;
first= tmp.first; first= tmp.first;
last= elements ? tmp.last : &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 base_list(bool error) { }
inline bool push_back(void *info) inline bool push_back(void *info)
{ {
...@@ -347,6 +395,8 @@ template <class T> class List :public base_list ...@@ -347,6 +395,8 @@ template <class T> class List :public base_list
public: public:
inline List() :base_list() {} inline List() :base_list() {}
inline List(const List<T> &tmp) :base_list(tmp) {} 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) { return base_list::push_back(a); }
inline bool push_back(T *a, MEM_ROOT *mem_root) inline bool push_back(T *a, MEM_ROOT *mem_root)
{ return base_list::push_back(a, mem_root); } { return base_list::push_back(a, mem_root); }
......
...@@ -2894,17 +2894,34 @@ mysql_execute_command(THD *thd) ...@@ -2894,17 +2894,34 @@ mysql_execute_command(THD *thd)
// Skip first table, which is the table we are creating // Skip first table, which is the table we are creating
TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local); TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
TABLE_LIST *select_tables= lex->query_tables; 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))) if ((res= create_table_precheck(thd, select_tables, create_table)))
goto end_with_restore_list; goto end_with_restore_list;
#ifndef HAVE_READLINK #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 #else
/* Fix names if symlinked tables */ /* 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) || 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)) create_table->table_name))
goto end_with_restore_list; goto end_with_restore_list;
#endif #endif
...@@ -2912,14 +2929,14 @@ mysql_execute_command(THD *thd) ...@@ -2912,14 +2929,14 @@ mysql_execute_command(THD *thd)
If we are using SET CHARSET without DEFAULT, add an implicit If we are using SET CHARSET without DEFAULT, add an implicit
DEFAULT to not confuse old users. (This may change). 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_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
HA_CREATE_USED_CHARSET) HA_CREATE_USED_CHARSET)
{ {
lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET; create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET; create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
lex->create_info.default_table_charset= lex->create_info.table_charset; create_info.default_table_charset= create_info.table_charset;
lex->create_info.table_charset= 0; create_info.table_charset= 0;
} }
/* /*
The create-select command will open and read-lock the select table The create-select command will open and read-lock the select table
...@@ -2953,7 +2970,7 @@ mysql_execute_command(THD *thd) ...@@ -2953,7 +2970,7 @@ mysql_execute_command(THD *thd)
Is table which we are changing used somewhere in other parts Is table which we are changing used somewhere in other parts
of query of query
*/ */
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
{ {
TABLE_LIST *duplicate; TABLE_LIST *duplicate;
if ((duplicate= unique_table(thd, create_table, select_tables))) if ((duplicate= unique_table(thd, create_table, select_tables)))
...@@ -2964,10 +2981,10 @@ mysql_execute_command(THD *thd) ...@@ -2964,10 +2981,10 @@ mysql_execute_command(THD *thd)
} }
} }
/* If we create merge table, we have to test tables in merge, too */ /* 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; 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= tab->next_local) tab= tab->next_local)
{ {
...@@ -2980,14 +2997,16 @@ mysql_execute_command(THD *thd) ...@@ -2980,14 +2997,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, if ((result= new select_create(create_table,
&lex->create_info, &create_info,
lex->create_list, &alter_info,
lex->key_list, select_lex->item_list,
select_lex->item_list, lex->duplicates,
lex->duplicates, lex->ignore)))
lex->ignore)))
{ {
/* /*
CREATE from SELECT give its SELECT_LEX for SELECT, CREATE from SELECT give its SELECT_LEX for SELECT,
...@@ -2996,23 +3015,19 @@ mysql_execute_command(THD *thd) ...@@ -2996,23 +3015,19 @@ mysql_execute_command(THD *thd)
res= handle_select(thd, lex, result, 0); res= handle_select(thd, lex, result, 0);
delete result; delete result;
} }
/* reset for PS */
lex->create_list.empty();
lex->key_list.empty();
} }
} }
else else
{ {
/* regular create */ /* regular create */
if (lex->name) 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); (Table_ident *)lex->name);
else else
{ {
res= mysql_create_table(thd, create_table->db, res= mysql_create_table(thd, create_table->db,
create_table->table_name, &lex->create_info, create_table->table_name, &create_info,
lex->create_list, &alter_info, 0, 0);
lex->key_list, 0, 0);
} }
if (!res) if (!res)
send_ok(thd); send_ok(thd);
...@@ -3024,16 +3039,49 @@ end_with_restore_list: ...@@ -3024,16 +3039,49 @@ end_with_restore_list:
break; break;
} }
case SQLCOM_CREATE_INDEX: 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); 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 */ goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
if (end_active_trans(thd)) if (end_active_trans(thd))
goto error; goto error;
else /*
res = mysql_create_index(thd, first_table, lex->key_list); Currently CREATE INDEX or DROP INDEX cause a full table rebuild
break; 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.row_type= ROW_TYPE_NOT_USED;
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 #ifdef HAVE_REPLICATION
case SQLCOM_SLAVE_START: case SQLCOM_SLAVE_START:
{ {
...@@ -3074,6 +3122,17 @@ end_with_restore_list: ...@@ -3074,6 +3122,17 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0); DBUG_ASSERT(first_table == all_tables && first_table != 0);
{ {
ulong priv=0; ulong priv=0;
/*
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;
if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN)) if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
{ {
my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name); my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
...@@ -3088,7 +3147,7 @@ end_with_restore_list: ...@@ -3088,7 +3147,7 @@ end_with_restore_list:
is_schema_db(select_lex->db))|| is_schema_db(select_lex->db))||
check_merge_table_access(thd, first_table->db, check_merge_table_access(thd, first_table->db,
(TABLE_LIST *) (TABLE_LIST *)
lex->create_info.merge_list.first)) create_info.merge_list.first))
goto error; /* purecov: inspected */ goto error; /* purecov: inspected */
if (grant_option) if (grant_option)
{ {
...@@ -3107,13 +3166,13 @@ end_with_restore_list: ...@@ -3107,13 +3166,13 @@ end_with_restore_list:
} }
} }
/* Don't yet allow changing of symlinks with ALTER TABLE */ /* 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, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"DATA DIRECTORY option ignored"); "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, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"INDEX DIRECTORY option ignored"); "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 */ /* ALTER TABLE ends previous transaction */
if (end_active_trans(thd)) if (end_active_trans(thd))
goto error; goto error;
...@@ -3127,13 +3186,13 @@ end_with_restore_list: ...@@ -3127,13 +3186,13 @@ end_with_restore_list:
} }
thd->enable_slow_log= opt_log_slow_admin_statements; thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_alter_table(thd, select_lex->db, lex->name, res= mysql_alter_table(thd, select_lex->db, lex->name,
&lex->create_info, &create_info,
first_table, lex->create_list, first_table,
lex->key_list, &alter_info,
select_lex->order_list.elements, select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first, (ORDER *) select_lex->order_list.first,
lex->ignore, &lex->alter_info, 1); lex->ignore);
} }
break; break;
} }
...@@ -3286,7 +3345,7 @@ end_with_restore_list: ...@@ -3286,7 +3345,7 @@ end_with_restore_list:
goto error; /* purecov: inspected */ goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements; thd->enable_slow_log= opt_log_slow_admin_statements;
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ? 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); mysql_optimize_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */ /* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog) if (!res && !lex->no_write_to_binlog)
...@@ -3602,15 +3661,6 @@ end_with_restore_list: ...@@ -3602,15 +3661,6 @@ end_with_restore_list:
lex->drop_temporary); lex->drop_temporary);
} }
break; 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: case SQLCOM_SHOW_PROCESSLIST:
if (!thd->security_ctx->priv_user[0] && if (!thd->security_ctx->priv_user[0] &&
check_global_access(thd,PROCESS_ACL)) check_global_access(thd,PROCESS_ACL))
...@@ -3739,6 +3789,12 @@ end_with_restore_list: ...@@ -3739,6 +3789,12 @@ end_with_restore_list:
break; break;
case SQLCOM_CREATE_DB: 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)) if (end_active_trans(thd))
{ {
res= -1; res= -1;
...@@ -3766,10 +3822,11 @@ end_with_restore_list: ...@@ -3766,10 +3822,11 @@ end_with_restore_list:
break; break;
} }
#endif #endif
if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name))) if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
break; break;
res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name), res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
&lex->create_info, 0); &create_info, 0);
break; break;
} }
case SQLCOM_DROP_DB: case SQLCOM_DROP_DB:
...@@ -4456,7 +4513,7 @@ create_sp_error: ...@@ -4456,7 +4513,7 @@ create_sp_error:
goto error; 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; thd->net.no_send_ok= TRUE;
if (sp->m_flags & sp_head::MULTI_RESULTS) if (sp->m_flags & sp_head::MULTI_RESULTS)
{ {
...@@ -4467,7 +4524,7 @@ create_sp_error: ...@@ -4467,7 +4524,7 @@ create_sp_error:
back back
*/ */
my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str); 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; goto error;
} }
/* /*
...@@ -4483,7 +4540,7 @@ create_sp_error: ...@@ -4483,7 +4540,7 @@ create_sp_error:
if (check_routine_access(thd, EXECUTE_ACL, if (check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, TRUE, FALSE)) 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; goto error;
} }
#endif #endif
...@@ -4508,7 +4565,7 @@ create_sp_error: ...@@ -4508,7 +4565,7 @@ create_sp_error:
thd->variables.select_limit= select_limit; 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; thd->server_status&= ~bits_to_be_cleared;
if (!res) if (!res)
...@@ -5917,15 +5974,17 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5917,15 +5974,17 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
if (type_modifier & PRI_KEY_FLAG) if (type_modifier & PRI_KEY_FLAG)
{ {
lex->col_list.push_back(new key_part_spec(field_name,0)); 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, lex->alter_info.key_list.push_back(new Key(Key::PRIMARY, NullS,
0, lex->col_list)); HA_KEY_ALG_UNDEF, 0,
lex->col_list));
lex->col_list.empty(); lex->col_list.empty();
} }
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG)) if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{ {
lex->col_list.push_back(new key_part_spec(field_name,0)); 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->alter_info.key_list.push_back(new Key(Key::UNIQUE, NullS,
lex->col_list)); HA_KEY_ALG_UNDEF, 0,
lex->col_list));
lex->col_list.empty(); lex->col_list.empty();
} }
...@@ -5988,7 +6047,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5988,7 +6047,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
interval_list, cs, uint_geom_type)) interval_list, cs, uint_geom_type))
DBUG_RETURN(1); DBUG_RETURN(1);
lex->create_list.push_back(new_field); lex->alter_info.create_list.push_back(new_field);
lex->last_field=new_field; lex->last_field=new_field;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -7016,55 +7075,6 @@ Item * all_any_subquery_creator(Item *left_expr, ...@@ -7016,55 +7075,6 @@ Item * all_any_subquery_creator(Item *left_expr,
} }
/*
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;
create_info.row_type= ROW_TYPE_NOT_USED;
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;
create_info.row_type= ROW_TYPE_NOT_USED;
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));
}
/* /*
Multi update query pre-check Multi update query pre-check
......
...@@ -460,7 +460,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) ...@@ -460,7 +460,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
} }
bool mysqld_show_create_db(THD *thd, char *dbname, 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; Security_context *sctx= thd->security_ctx;
char buff[2048]; char buff[2048];
......
...@@ -645,8 +645,7 @@ int prepare_create_field(create_field *sql_field, ...@@ -645,8 +645,7 @@ int prepare_create_field(create_field *sql_field,
mysql_prepare_table() mysql_prepare_table()
thd Thread object thd Thread object
create_info Create information (like MAX_ROWS) create_info Create information (like MAX_ROWS)
fields List of fields to create alter_info List of columns and indexes to create
keys List of keys to create
DESCRIPTION DESCRIPTION
Prepares the table and key structures for table creation. Prepares the table and key structures for table creation.
...@@ -660,8 +659,8 @@ int prepare_create_field(create_field *sql_field, ...@@ -660,8 +659,8 @@ int prepare_create_field(create_field *sql_field,
*/ */
static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
List<create_field> *fields, Alter_info *alter_info,
List<Key> *keys, bool tmp_table, bool tmp_table,
uint *db_options, uint *db_options,
handler *file, KEY **key_info_buffer, handler *file, KEY **key_info_buffer,
uint *key_count, int select_field_count) uint *key_count, int select_field_count)
...@@ -675,11 +674,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, ...@@ -675,11 +674,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
int timestamps= 0, timestamps_with_niladic= 0; int timestamps= 0, timestamps_with_niladic= 0;
int field_no,dup_no; int field_no,dup_no;
int select_field_pos,auto_increment=0; 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; uint total_uneven_bit_length= 0;
DBUG_ENTER("mysql_prepare_table"); 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; null_fields=blob_columns=0;
create_info->varchar= 0; create_info->varchar= 0;
max_key_length= file->max_key_length(); max_key_length= file->max_key_length();
...@@ -1004,7 +1004,8 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, ...@@ -1004,7 +1004,8 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
/* Create keys */ /* 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; uint key_parts=0, fk_key_count=0;
bool primary_key=0,unique_key=0; bool primary_key=0,unique_key=0;
Key *key, *key2; Key *key, *key2;
...@@ -1563,14 +1564,13 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field) ...@@ -1563,14 +1564,13 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
SYNOPSIS SYNOPSIS
mysql_create_table() mysql_create_table()
thd Thread object thd Thread object
db Database db Database
table_name Table name table_name Table name
create_info Create information (like MAX_ROWS) create_info [in/out] Create information (like MAX_ROWS)
fields List of fields to create alter_info [in/out] List of columns and indexes to create
keys List of keys to create internal_tmp_table Set to 1 if this is an internal temporary table
internal_tmp_table Set to 1 if this is an internal temporary table (From ALTER TABLE)
(From ALTER TABLE)
DESCRIPTION DESCRIPTION
If one creates a temporary table, this is automatically opened If one creates a temporary table, this is automatically opened
...@@ -1580,6 +1580,11 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field) ...@@ -1580,6 +1580,11 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
select_field_count is also used for CREATE ... SELECT, select_field_count is also used for CREATE ... SELECT,
and must be zero for standard create of table. 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 RETURN VALUES
FALSE OK FALSE OK
TRUE error TRUE error
...@@ -1587,8 +1592,8 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field) ...@@ -1587,8 +1592,8 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
bool mysql_create_table(THD *thd,const char *db, const char *table_name, bool mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
List<create_field> &fields, Alter_info *alter_info,
List<Key> &keys,bool internal_tmp_table, bool internal_tmp_table,
uint select_field_count) uint select_field_count)
{ {
char path[FN_REFLEN]; char path[FN_REFLEN];
...@@ -1600,7 +1605,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, ...@@ -1600,7 +1605,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_ENTER("mysql_create_table"); DBUG_ENTER("mysql_create_table");
/* Check for duplicate fields and check type of table to create */ /* 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), my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
MYF(0)); MYF(0));
...@@ -1644,10 +1649,10 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, ...@@ -1644,10 +1649,10 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
create_info->default_table_charset= db_info.default_table_charset; create_info->default_table_charset= db_info.default_table_charset;
} }
if (mysql_prepare_table(thd, create_info, &fields, if (mysql_prepare_table(thd, create_info, alter_info, internal_tmp_table,
&keys, internal_tmp_table, &db_options, file, &db_options, file,
&key_info_buffer, &key_count, &key_info_buffer, &key_count,
select_field_count)) select_field_count))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
/* Check if table exists */ /* Check if table exists */
...@@ -1737,8 +1742,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, ...@@ -1737,8 +1742,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
create_info->table_options=db_options; create_info->table_options=db_options;
if (rea_create_table(thd, path, db, table_name, if (rea_create_table(thd, path, db, table_name,
create_info, fields, key_count, create_info, alter_info->create_list,
key_info_buffer)) key_count, key_info_buffer))
goto end; goto end;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE) if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{ {
...@@ -2323,9 +2328,12 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -2323,9 +2328,12 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
(table->table->file->ha_check_for_upgrade(check_opt) == (table->table->file->ha_check_for_upgrade(check_opt) ==
HA_ADMIN_NEEDS_ALTER)) HA_ADMIN_NEEDS_ALTER))
{ {
my_bool save_no_send_ok= thd->net.no_send_ok;
close_thread_tables(thd); close_thread_tables(thd);
tmp_disable_binlog(thd); // binlogging is done by caller if wanted 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); reenable_binlog(thd);
goto send_result; goto send_result;
} }
...@@ -2404,6 +2412,7 @@ send_result_message: ...@@ -2404,6 +2412,7 @@ send_result_message:
case HA_ADMIN_TRY_ALTER: 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 This is currently used only by InnoDB. ha_innobase::optimize() answers
"try with alter", so here we close the table, do an ALTER TABLE, "try with alter", so here we close the table, do an ALTER TABLE,
...@@ -2414,7 +2423,9 @@ send_result_message: ...@@ -2414,7 +2423,9 @@ send_result_message:
*save_next_global= table->next_global; *save_next_global= table->next_global;
table->next_local= table->next_global= 0; table->next_local= table->next_global= 0;
tmp_disable_binlog(thd); // binlogging is done by caller if wanted 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); reenable_binlog(thd);
close_thread_tables(thd); close_thread_tables(thd);
if (!result_code) // recreation went ok if (!result_code) // recreation went ok
...@@ -2984,14 +2995,20 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled, ...@@ -2984,14 +2995,20 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
/* /*
Alter 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, bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
TABLE_LIST *table_list, TABLE_LIST *table_list,
List<create_field> &fields, List<Key> &keys, Alter_info *alter_info,
uint order_num, ORDER *order, bool ignore, uint order_num, ORDER *order, bool ignore)
ALTER_INFO *alter_info, bool do_send_ok)
{ {
TABLE *table,*new_table=0; TABLE *table,*new_table=0;
int error; int error;
...@@ -3212,8 +3229,7 @@ view_err: ...@@ -3212,8 +3229,7 @@ view_err:
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo); mysql_bin_log.write(&qinfo);
} }
if (do_send_ok) send_ok(thd);
send_ok(thd);
} }
else if (error > 0) else if (error > 0)
{ {
...@@ -3240,10 +3256,9 @@ view_err: ...@@ -3240,10 +3256,9 @@ view_err:
restore_record(table, s->default_values); // Empty record for DEFAULT restore_record(table, s->default_values); // Empty record for DEFAULT
List_iterator<Alter_drop> drop_it(alter_info->drop_list); 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_iterator<Alter_column> alter_it(alter_info->alter_list);
List<create_field> create_list; // Add new fields here Alter_info new_info; // Add new columns and indexes here
List<Key> key_list; // Add new keys here
create_field *def; create_field *def;
/* /*
...@@ -3291,13 +3306,13 @@ view_err: ...@@ -3291,13 +3306,13 @@ view_err:
def->field=field; def->field=field;
if (!def->after) if (!def->after)
{ {
create_list.push_back(def); new_info.create_list.push_back(def);
def_it.remove(); def_it.remove();
} }
} }
else else
{ // Use old field value { // 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_it.rewind(); // Change default if ALTER
Alter_column *alter; Alter_column *alter;
while ((alter=alter_it++)) while ((alter=alter_it++))
...@@ -3321,7 +3336,7 @@ view_err: ...@@ -3321,7 +3336,7 @@ view_err:
} }
} }
def_it.rewind(); 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 while ((def=def_it++)) // Add new columns
{ {
if (def->change && ! def->field) if (def->change && ! def->field)
...@@ -3330,9 +3345,9 @@ view_err: ...@@ -3330,9 +3345,9 @@ view_err:
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
if (!def->after) if (!def->after)
create_list.push_back(def); new_info.create_list.push_back(def);
else if (def->after == first_keyword) else if (def->after == first_keyword)
create_list.push_front(def); new_info.create_list.push_front(def);
else else
{ {
create_field *find; create_field *find;
...@@ -3356,7 +3371,7 @@ view_err: ...@@ -3356,7 +3371,7 @@ view_err:
alter_info->alter_list.head()->name, table_name); alter_info->alter_list.head()->name, table_name);
DBUG_RETURN(TRUE); 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), my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
MYF(0)); MYF(0));
...@@ -3368,8 +3383,8 @@ view_err: ...@@ -3368,8 +3383,8 @@ view_err:
for which some fields exists. for which some fields exists.
*/ */
List_iterator<Key> key_it(keys); List_iterator<Key> key_it(alter_info->key_list);
List_iterator<create_field> field_it(create_list); List_iterator<create_field> field_it(new_info.create_list);
List<key_part_spec> key_parts; List<key_part_spec> key_parts;
KEY *key_info=table->key_info; KEY *key_info=table->key_info;
...@@ -3441,24 +3456,37 @@ view_err: ...@@ -3441,24 +3456,37 @@ view_err:
key_part_length)); key_part_length));
} }
if (key_parts.elements) if (key_parts.elements)
key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL : {
(key_info->flags & HA_NOSAME ? Key *key;
(!my_strcasecmp(system_charset_info, enum Key::Keytype key_type;
key_name, primary_key_name) ?
Key::PRIMARY : Key::UNIQUE) : if (key_info->flags & HA_SPATIAL)
(key_info->flags & HA_FULLTEXT ? key_type= Key::SPATIAL;
Key::FULLTEXT : Key::MULTIPLE)), else if (key_info->flags & HA_NOSAME)
key_name, {
key_info->algorithm, if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
test(key_info->flags & HA_GENERATED_KEY), key_type= Key::PRIMARY;
key_parts)); 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_info->algorithm,
test(key_info->flags & HA_GENERATED_KEY),
key_parts);
new_info.key_list.push_back(key);
}
} }
{ {
Key *key; Key *key;
while ((key=key_it++)) // Add new keys while ((key=key_it++)) // Add new keys
{ {
if (key->type != Key::FOREIGN_KEY) if (key->type != Key::FOREIGN_KEY)
key_list.push_back(key); new_info.key_list.push_back(key);
if (key->name && if (key->name &&
!my_strcasecmp(system_charset_info,key->name,primary_key_name)) !my_strcasecmp(system_charset_info,key->name,primary_key_name))
{ {
...@@ -3593,7 +3621,7 @@ view_err: ...@@ -3593,7 +3621,7 @@ view_err:
{ {
tmp_disable_binlog(thd); tmp_disable_binlog(thd);
error= mysql_create_table(thd, new_db, tmp_name, 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); reenable_binlog(thd);
if (error) if (error)
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -3634,9 +3662,9 @@ view_err: ...@@ -3634,9 +3662,9 @@ view_err:
{ {
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
new_table->next_number_field=new_table->found_next_number_field; new_table->next_number_field=new_table->found_next_number_field;
error=copy_data_between_tables(table, new_table, create_list, ignore, error= copy_data_between_tables(table, new_table, new_info.create_list,
order_num, order, &copied, &deleted, ignore, order_num, order,
alter_info->keys_onoff); &copied, &deleted, alter_info->keys_onoff);
} }
else if (!new_table) else if (!new_table)
{ {
...@@ -3860,8 +3888,7 @@ end_temporary: ...@@ -3860,8 +3888,7 @@ end_temporary:
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO), my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted), (ulong) deleted, (ulong) (copied + deleted), (ulong) deleted,
(ulong) thd->cuted_fields); (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; thd->some_tables_deleted=0;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
...@@ -4060,31 +4087,26 @@ copy_data_between_tables(TABLE *from,TABLE *to, ...@@ -4060,31 +4087,26 @@ copy_data_between_tables(TABLE *from,TABLE *to,
mysql_recreate_table() mysql_recreate_table()
thd Thread handler thd Thread handler
tables Tables to recreate tables Tables to recreate
do_send_ok If we should send_ok() or leave it to caller
RETURN RETURN
Like mysql_alter_table(). Like mysql_alter_table().
*/ */
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
bool do_send_ok)
{ {
DBUG_ENTER("mysql_recreate_table");
LEX *lex= thd->lex;
HA_CREATE_INFO create_info; HA_CREATE_INFO create_info;
lex->create_list.empty(); Alter_info alter_info;
lex->key_list.empty();
lex->col_list.empty(); DBUG_ENTER("mysql_recreate_table");
lex->alter_info.reset();
bzero((char*) &create_info,sizeof(create_info)); bzero((char*) &create_info, sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT; create_info.db_type=DB_TYPE_DEFAULT;
create_info.row_type=ROW_TYPE_NOT_USED; create_info.row_type=ROW_TYPE_NOT_USED;
create_info.default_table_charset=default_charset_info; create_info.default_table_charset=default_charset_info;
/* Force alter table to recreate table */ /* 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, DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
table_list, lex->create_list, table_list, &alter_info,
lex->key_list, 0, (ORDER *) 0, 0, (ORDER *) 0, 0));
0, &lex->alter_info, do_send_ok));
} }
......
...@@ -1352,8 +1352,7 @@ create: ...@@ -1352,8 +1352,7 @@ create:
TL_READ_NO_INSERT: TL_READ_NO_INSERT:
TL_READ))) TL_READ)))
YYABORT; YYABORT;
lex->create_list.empty(); lex->alter_info.reset();
lex->key_list.empty();
lex->col_list.empty(); lex->col_list.empty();
lex->change=NullS; lex->change=NullS;
bzero((char*) &lex->create_info,sizeof(lex->create_info)); bzero((char*) &lex->create_info,sizeof(lex->create_info));
...@@ -1371,16 +1370,17 @@ create: ...@@ -1371,16 +1370,17 @@ create:
if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL, if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL,
TL_OPTION_UPDATING)) TL_OPTION_UPDATING))
YYABORT; YYABORT;
lex->create_list.empty(); lex->alter_info.reset();
lex->key_list.empty(); lex->alter_info.flags= ALTER_ADD_INDEX;
lex->col_list.empty(); lex->col_list.empty();
lex->change=NullS; lex->change=NullS;
} }
'(' key_list ')' '(' key_list ')'
{ {
LEX *lex=Lex; 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(); lex->col_list.empty();
} }
| CREATE DATABASE opt_if_not_exists ident | CREATE DATABASE opt_if_not_exists ident
...@@ -2920,29 +2920,34 @@ key_def: ...@@ -2920,29 +2920,34 @@ key_def:
key_type opt_ident key_alg '(' key_list ')' key_type opt_ident key_alg '(' key_list ')'
{ {
LEX *lex=Lex; 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 */ lex->col_list.empty(); /* Alloced by sql_alloc */
} }
| opt_constraint constraint_key_type opt_ident key_alg '(' key_list ')' | opt_constraint constraint_key_type opt_ident key_alg '(' key_list ')'
{ {
LEX *lex=Lex; LEX *lex=Lex;
const char *key_name= $3 ? $3:$1; const char *key_name= $3 ? $3:$1;
lex->key_list.push_back(new Key($2, key_name, $4, 0, Key *key= new Key($2, key_name, $4, 0, lex->col_list);
lex->col_list)); lex->alter_info.key_list.push_back(key);
lex->col_list.empty(); /* Alloced by sql_alloc */ lex->col_list.empty(); /* Alloced by sql_alloc */
} }
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references | opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->key_list.push_back(new foreign_key($4 ? $4:$1, lex->col_list, const char *key_name= $4 ? $4 : $1;
$8, Key *key= new foreign_key(key_name, lex->col_list,
lex->ref_list, $8,
lex->fk_delete_opt, lex->ref_list,
lex->fk_update_opt, lex->fk_delete_opt,
lex->fk_match_option)); lex->fk_update_opt,
lex->key_list.push_back(new Key(Key::MULTIPLE, $4 ? $4 : $1, lex->fk_match_option);
HA_KEY_ALG_UNDEF, 1, lex->alter_info.key_list.push_back(key);
lex->col_list)); key= new Key(Key::MULTIPLE, key_name,
HA_KEY_ALG_UNDEF, 1,
lex->col_list);
lex->alter_info.key_list.push_back(key);
lex->col_list.empty(); /* Alloced by sql_alloc */ lex->col_list.empty(); /* Alloced by sql_alloc */
} }
| constraint opt_check_constraint | constraint opt_check_constraint
...@@ -3484,8 +3489,6 @@ alter: ...@@ -3484,8 +3489,6 @@ alter:
if (!lex->select_lex.add_table_to_list(thd, $4, NULL, if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
TL_OPTION_UPDATING)) TL_OPTION_UPDATING))
YYABORT; YYABORT;
lex->create_list.empty();
lex->key_list.empty();
lex->col_list.empty(); lex->col_list.empty();
lex->select_lex.init_order(); lex->select_lex.init_order();
lex->select_lex.db= lex->select_lex.db=
...@@ -3495,8 +3498,7 @@ alter: ...@@ -3495,8 +3498,7 @@ alter:
lex->create_info.db_type= DB_TYPE_DEFAULT; lex->create_info.db_type= DB_TYPE_DEFAULT;
lex->create_info.default_table_charset= NULL; lex->create_info.default_table_charset= NULL;
lex->create_info.row_type= ROW_TYPE_NOT_USED; lex->create_info.row_type= ROW_TYPE_NOT_USED;
lex->alter_info.reset(); lex->alter_info.reset();
lex->alter_info.flags= 0;
} }
alter_list alter_list
{} {}
...@@ -6254,7 +6256,8 @@ drop: ...@@ -6254,7 +6256,8 @@ drop:
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->sql_command= SQLCOM_DROP_INDEX; 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, lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str)); $3.str));
if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL, if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment