diff options
39 files changed, 1058 insertions, 235 deletions
diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 6ae6111a8bb..3dabd226ae6 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -311,4 +311,5 @@ #define ER_TRUNCATED_WRONG_VALUE 1292 #define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293 #define ER_INVALID_ON_UPDATE 1294 -#define ER_ERROR_MESSAGES 295 +#define ER_UNSUPPORTED_PS 1295 +#define ER_ERROR_MESSAGES 296 diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index fc5ef88f045..f0975b6fa10 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -1,4 +1,5 @@ drop table if exists t1,t2,t3; +drop database if exists mysqltest; create table t1(id1 int not null auto_increment primary key, t char(12)); create table t2(id2 int not null, t char(12)); create table t3(id3 int not null, t char(12), index(id3)); @@ -402,7 +403,7 @@ DELETE t1 FROM t1, t2 AS t3; DELETE t4 FROM t1, t1 AS t4; DELETE t3 FROM t1 AS t3, t1 AS t4; DELETE t1 FROM t1 AS t3, t2 AS t4; -ERROR 42000: Not unique table/alias: 't1' +ERROR 42S02: Unknown table 't1' in MULTI DELETE INSERT INTO t1 values (1),(2); INSERT INTO t2 values (1),(2); DELETE t1 FROM t1 AS t2, t2 AS t1 where t1.a=t2.a and t1.a=1; @@ -435,3 +436,20 @@ select * from t2; c2_id c2_p_id c2_note c2_active 1 1 A Note 1 drop table t1, t2; +create database mysqltest; +create table mysqltest.t1 (a int, b int, primary key (a)); +create table mysqltest.t2 (a int, b int, primary key (a)); +create table mysqltest.t3 (a int, b int, primary key (a)); +grant select on mysqltest.* to mysqltest_1@localhost; +grant update on mysqltest.t1 to mysqltest_1@localhost; +update t1, t2 set t1.b=1 where t1.a=t2.a; +update t1, t2 set t1.b=(select t3.b from t3 where t1.a=t3.a) where t1.a=t2.a; +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +drop database mysqltest; +create table t1 (a int, primary key (a)); +create table t2 (a int, primary key (a)); +create table t3 (a int, primary key (a)); +delete t1,t3 from t1,t2 where t1.a=t2.a and t2.a=(select t3.a from t3 where t1.a=t3.a); +ERROR 42S02: Unknown table 't3' in MULTI DELETE +drop table t1, t2, t3; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 27fd80e781b..8b6941c4a94 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -4,6 +4,7 @@ --disable_warnings drop table if exists t1,t2,t3; +drop database if exists mysqltest; --enable_warnings create table t1(id1 int not null auto_increment primary key, t char(12)); @@ -354,7 +355,7 @@ CREATE TABLE t2 ( a int ); DELETE t1 FROM t1, t2 AS t3; DELETE t4 FROM t1, t1 AS t4; DELETE t3 FROM t1 AS t3, t1 AS t4; ---error 1066 +--error 1109 DELETE t1 FROM t1 AS t3, t2 AS t4; INSERT INTO t1 values (1),(2); INSERT INTO t2 values (1),(2); @@ -369,7 +370,6 @@ DROP TABLE t1,t2; # # Test update with const tables # - create table `t1` (`p_id` int(10) unsigned NOT NULL auto_increment, `p_code` varchar(20) NOT NULL default '', `p_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`p_id`) ); create table `t2` (`c2_id` int(10) unsigned NULL auto_increment, `c2_p_id` int(10) unsigned NOT NULL default '0', `c2_note` text NOT NULL, `c2_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`c2_id`), KEY `c2_p_id` (`c2_p_id`) ); insert into t1 values (0,'A01-Comp',1); @@ -379,3 +379,36 @@ update t1 left join t2 on p_id = c2_p_id set c2_note = 'asdf-1' where p_id = 2; select * from t1; select * from t2; drop table t1, t2; + +# +# prevelege chexk for multiupdate with other tables +# + +connect (root,localhost,root,,test,$MASTER_MYPORT,master.sock); +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings +create table mysqltest.t1 (a int, b int, primary key (a)); +create table mysqltest.t2 (a int, b int, primary key (a)); +create table mysqltest.t3 (a int, b int, primary key (a)); +grant select on mysqltest.* to mysqltest_1@localhost; +grant update on mysqltest.t1 to mysqltest_1@localhost; +connect (user1,localhost,mysqltest_1,,mysqltest,$MASTER_MYPORT,master.sock); +connection user1; +update t1, t2 set t1.b=1 where t1.a=t2.a; +update t1, t2 set t1.b=(select t3.b from t3 where t1.a=t3.a) where t1.a=t2.a; +connection root; +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +drop database mysqltest; + +# +# multi delete wrong table check +# +create table t1 (a int, primary key (a)); +create table t2 (a int, primary key (a)); +create table t3 (a int, primary key (a)); +-- error 1109 +delete t1,t3 from t1,t2 where t1.a=t2.a and t2.a=(select t3.a from t3 where t1.a=t3.a); +drop table t1, t2, t3; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 24d60b51eab..d5842189f07 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -477,9 +477,11 @@ bool Item_in_optimizer::fix_left(THD *thd, struct st_table_list *tables, Item **ref) { - if (args[0]->fix_fields(thd, tables, ref) || - (!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))) + if ((!args[0]->fixed && args[0]->fix_fields(thd, tables, args))) return 1; + if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))) + return 1; + cache->setup(args[0]); cache->store(args[0]); if (cache->cols() == 1) @@ -512,12 +514,12 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, Item ** ref) { DBUG_ASSERT(fixed == 0); - if (!args[0]->fixed && fix_left(thd, tables, ref)) + if (fix_left(thd, tables, ref)) return 1; if (args[0]->maybe_null) maybe_null=1; - if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args)) + if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args+1)) return 1; Item_in_subselect * sub= (Item_in_subselect *)args[1]; if (args[0]->cols() != sub->engine->cols()) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 29db2ceda49..44e241b9d4c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -347,6 +347,13 @@ void free_items(Item *item); void cleanup_items(Item *item); class THD; void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0); +int check_one_table_access(THD *thd, ulong privilege, + TABLE_LIST *tables, bool no_errors); +bool check_merge_table_access(THD *thd, char *db, + TABLE_LIST *table_list); +int multi_update_precheck(THD *thd, TABLE_LIST *tables); +int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count); +int insert_select_precheck(THD *thd, TABLE_LIST *tables); #include "sql_class.h" #include "opt_range.h" diff --git a/sql/set_var.cc b/sql/set_var.cc index e3ed2a4cbd8..b357c0c96f2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2528,6 +2528,24 @@ int set_var::check(THD *thd) } +int set_var::light_check(THD *thd) +{ + if (var->check_type(type)) + { + my_error(type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE, + MYF(0), + var->name); + return -1; + } + if ((type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))) + return 1; + + if (value && (value->fix_fields(thd, 0, &value) || value->check_cols(1))) + return -1; + return 0; +} + + int set_var::update(THD *thd) { if (!value) @@ -2555,6 +2573,16 @@ int set_var_user::check(THD *thd) } +int set_var_user::light_check(THD *thd) +{ + /* + Item_func_set_user_var can't substitute something else on its place => + 0 can be passed as last argument (reference on item) + */ + return (user_var_item->fix_fields(thd, 0, (Item**) 0)); +} + + int set_var_user::update(THD *thd) { if (user_var_item->update()) diff --git a/sql/set_var.h b/sql/set_var.h index 1cac2953a21..699f320bbd9 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -688,6 +688,8 @@ public: virtual ~set_var_base() {} virtual int check(THD *thd)=0; /* To check privileges etc. */ virtual int update(THD *thd)=0; /* To set the value */ + /* light check for PS */ + virtual int light_check(THD *thd) { return check(thd); } }; @@ -728,6 +730,7 @@ public: } int check(THD *thd); int update(THD *thd); + int light_check(THD *thd); }; @@ -742,6 +745,7 @@ public: {} int check(THD *thd); int update(THD *thd); + int light_check(THD *thd); }; /* For SET PASSWORD */ diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 339c693bb38..f3a0c5e0eec 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -307,3 +307,4 @@ character-set=latin2 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 9c870ecb67c..195e48faf82 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -301,3 +301,4 @@ character-set=latin1 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 18f11253fb5..9d9dfb14a89 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -309,3 +309,4 @@ character-set=latin1 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 2d7f82e36ef..14a854fbafb 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -298,3 +298,4 @@ character-set=latin1 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index c96f5d1e40c..5d0f34fd4b2 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -303,3 +303,4 @@ character-set=latin7 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index bb5f48cab56..adc9f66e96b 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -298,3 +298,4 @@ character-set=latin1 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index ccc9eace98e..0b732ba48f8 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -310,3 +310,4 @@ character-set=latin1 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index ff49f887d95..f96c10b0e65 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -298,3 +298,4 @@ character-set=greek "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 63925213da2..a26790a4ef9 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -300,3 +300,4 @@ character-set=latin2 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 76e572fd71b..7c519e4e4bf 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -298,3 +298,4 @@ character-set=latin1 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index f7df183269d..f973f84d2a4 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -300,3 +300,4 @@ character-set=ujis "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index e63a5d64c2b..8b5d318ab19 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -298,3 +298,4 @@ character-set=euckr "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 2d28db39a3c..c0a7d736e1f 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -300,3 +300,4 @@ character-set=latin1 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 231bcc89822..fc9b5d2f6da 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -300,3 +300,4 @@ character-set=latin1 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 0b5269cce80..36b7d67d134 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -302,3 +302,4 @@ character-set=latin2 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 9549d8f530d..d4ffa2d5ef5 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -299,3 +299,4 @@ character-set=latin1 "Truncado errado %-.32s valor: '%-.128s'" "Incorreta definição de tabela; Pode ter somente uma coluna TIMESTAMP com CURRENT_TIMESTAMP em DEFAULT ou ON UPDATE cláusula" "Inválida cláusula ON UPDATE para campo '%-.64s'", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 3e1993d8018..4918a6e1a10 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -302,3 +302,4 @@ character-set=latin2 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 943a64ad711..dbc93306a38 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -300,3 +300,4 @@ character-set=koi8r "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 74cc1c9f2e1..df157566aea 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -292,3 +292,4 @@ character-set=cp1250 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 79fe55c1ff1..80d21f8e31f 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -306,3 +306,4 @@ character-set=latin2 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 36d8bac986e..512f06c8c50 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -300,3 +300,4 @@ character-set=latin1 "Equivocado truncado %-.32s valor: '%-.128s'" "Incorrecta definición de tabla; Solamente debe haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o ON UPDATE cláusula" "Inválido ON UPDATE cláusula para campo '%-.64s'", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 2643e726db8..22e7cb786b5 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -298,3 +298,4 @@ character-set=latin1 "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index e61e479aa66..3149d58b413 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -303,3 +303,4 @@ character-set=koi8u "Truncated wrong %-.32s value: '%-.128s'" "Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" "Invalid ON UPDATE clause for '%-.64s' field", +"This command is not supported in the prepared statement protocol yet", diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index df7d487194a..7ff2fb4643a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1635,6 +1635,66 @@ void st_select_lex::print_limit(THD *thd, String *str) } /* + unlink first table from table lists + + SYNOPSIS + unlink_first_table() + tables - global table list + global_first - save first global table passed using this parameter + local_first - save first local table passed using this parameter + + RETURN + global list without first table +*/ +TABLE_LIST *st_lex::unlink_first_table(TABLE_LIST *tables, + TABLE_LIST **global_first, + TABLE_LIST **local_first) +{ + *global_first= tables; + *local_first= (TABLE_LIST*)select_lex.table_list.first; + // exclude from global table list + tables= tables->next; + // and from local list if it is not the same + if (&select_lex != all_selects_list) + select_lex.table_list.first= (gptr)(*local_first)->next; + else + select_lex.table_list.first= (gptr)tables; + (*global_first)->next= 0; + return tables; +} + +/* + link unlinked first table back + + SYNOPSIS + link_first_table_back() + tables - global table list + global_first - save first global table + local_first - save first local table + + RETURN + global list +*/ +TABLE_LIST *st_lex::link_first_table_back(TABLE_LIST *tables, + TABLE_LIST *global_first, + TABLE_LIST *local_first) +{ + global_first->next= tables; + tables= global_first; + if (&select_lex != all_selects_list) + { + /* + we do not touch local table 'next' field => we need just + put the table in the list + */ + select_lex.table_list.first= (gptr) local_first; + } + else + select_lex.table_list.first= (gptr) tables; + return tables; +} + +/* There are st_select_lex::add_table_to_list & st_select_lex::set_lock_for_tables are in sql_parse.cc diff --git a/sql/sql_lex.h b/sql/sql_lex.h index c86c7d4a81d..d5fbbd8803e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -603,6 +603,12 @@ typedef struct st_lex un->uncacheable|= cause; } } + TABLE_LIST *unlink_first_table(TABLE_LIST *tables, + TABLE_LIST **global_first, + TABLE_LIST **local_first); + TABLE_LIST *link_first_table_back(TABLE_LIST *tables, + TABLE_LIST *global_first, + TABLE_LIST *local_first); } LEX; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2b8720abebb..147f576d03e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -51,13 +51,10 @@ extern "C" int gethostname(char *name, int namelen); static int check_for_max_user_connections(THD *thd, USER_CONN *uc); static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); -static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); static void remove_escape(char *name); static void refresh_status(void); static bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); -static int check_one_table_access(THD *thd, ulong privilege, - TABLE_LIST *tables, bool no_errors); const char *any_db="*any*"; // Special symbol for check_access @@ -2164,17 +2161,9 @@ mysql_execute_command(THD *thd) case SQLCOM_CREATE_TABLE: { /* Skip first table, which is the table we are creating */ - TABLE_LIST *create_table= tables; - TABLE_LIST *create_table_local= - (TABLE_LIST*)lex->select_lex.table_list.first; - // exclude from global table list - tables= tables->next; - // and from local list if it is not the same - if (&lex->select_lex != lex->all_selects_list) - lex->select_lex.table_list.first= (gptr)create_table_local->next; - else - lex->select_lex.table_list.first= (gptr)tables; - create_table->next= 0; + TABLE_LIST *create_table, *create_table_local; + tables= lex->unlink_first_table(tables, &create_table, + &create_table_local); ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? CREATE_TMP_ACL : CREATE_ACL); @@ -2184,10 +2173,10 @@ mysql_execute_command(THD *thd) check_merge_table_access(thd, create_table->db, (TABLE_LIST *) lex->create_info.merge_list.first)) - goto create_eror; /* purecov: inspected */ + goto create_error; /* purecov: inspected */ if (grant_option && want_priv != CREATE_TMP_ACL && check_grant(thd, want_priv, create_table,0,0)) - goto create_eror; + goto create_error; #ifndef HAVE_READLINK lex->create_info.data_file_name=lex->create_info.index_file_name=0; #else @@ -2223,10 +2212,10 @@ mysql_execute_command(THD *thd) create_table->real_name)) { net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name); - goto create_eror; + goto create_error; } if (tables && check_table_access(thd, SELECT_ACL, tables,0)) - goto create_eror; // Error message is given + goto create_error; // Error message is given select_lex->options|= SELECT_NO_UNLOCK; unit->offset_limit_cnt= select_lex->offset_limit; unit->select_limit_cnt= select_lex->select_limit+ @@ -2244,6 +2233,9 @@ mysql_execute_command(THD *thd) lex->key_list, select_lex->item_list,lex->duplicates))) res=handle_select(thd, lex, result); + //reset for PS + lex->create_list.empty(); + lex->key_list.empty(); } } else // regular create @@ -2261,35 +2253,18 @@ mysql_execute_command(THD *thd) if (!res) send_ok(thd); } + // put tables back for PS rexecuting - create_table->next= tables; - tables= create_table; - if (&lex->select_lex != lex->all_selects_list) - { - /* - we do not touch local table 'next' field => we need just - put the table in the list - */ - lex->select_lex.table_list.first= (gptr) create_table_local; - } - else - lex->select_lex.table_list.first= (gptr) tables; + tables= lex->link_first_table_back(tables, create_table, + create_table_local); break; -create_eror: +create_error: res= 1; //error reported unsent_create_error: // put tables back for PS rexecuting - create_table->next= tables; - tables= create_table; - if (&lex->select_lex != lex->all_selects_list) - { - /* - we do not touch local table 'next' field => we need just - put the table in the list - */ - lex->select_lex.table_list.first= (gptr) create_table_local; - } + tables= lex->link_first_table_back(tables, create_table, + create_table_local); break; } case SQLCOM_CREATE_INDEX: @@ -2577,39 +2552,8 @@ unsent_create_error: break; case SQLCOM_UPDATE_MULTI: { - const char *msg= 0; - TABLE_LIST *table; - - if (select_lex->item_list.elements != lex->value_list.elements) - { - send_error(thd,ER_WRONG_VALUE_COUNT); - DBUG_VOID_RETURN; - } - /* - Ensure that we have UPDATE or SELECT privilege for each table - The exact privilege is checked in mysql_multi_update() - */ - for (table= tables ; table ; table= table->next) - { - TABLE_LIST *save= table->next; - table->next= 0; - if (check_one_table_access(thd, UPDATE_ACL, table, 1) && - check_one_table_access(thd, SELECT_ACL, table, 0)) - goto error; - table->next= save; - } - - if (select_lex->order_list.elements) - msg= "ORDER BY"; - else if (select_lex->select_limit && select_lex->select_limit != - HA_POS_ERROR) - msg= "LIMIT"; - if (msg) - { - net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg); - res= 1; + if ((res= multi_update_precheck(thd, tables))) break; - } res= mysql_multi_update(thd,tables, &select_lex->item_list, &lex->value_list, @@ -2642,16 +2586,9 @@ unsent_create_error: case SQLCOM_REPLACE_SELECT: case SQLCOM_INSERT_SELECT: { - /* - Check that we have modify privileges for the first table and - select privileges for the rest - */ - { - ulong privilege= (lex->duplicates == DUP_REPLACE ? - INSERT_ACL | DELETE_ACL : INSERT_ACL); - if (check_one_table_access(thd, privilege, tables, 0)) - goto error; - } + TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first; + if ((res= insert_select_precheck(thd, tables))) + break; /* Fix lock for first table */ if (tables->lock_type == TL_WRITE_DELAYED) @@ -2672,16 +2609,18 @@ unsent_create_error: select_lex->options |= OPTION_BUFFER_RESULT; } - /* Skip first table, which is the table we are inserting in */ - lex->select_lex.table_list.first= - (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next); - lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE; if (!(res=open_and_lock_tables(thd, tables))) { if ((result=new select_insert(tables->table,&lex->field_list, lex->duplicates))) + /* Skip first table, which is the table we are inserting in */ + lex->select_lex.table_list.first= (gptr) first_local_table->next; + lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE; res=handle_select(thd,lex,result); + /* revert changes for SP */ + lex->select_lex.table_list.first= (gptr) first_local_table; + lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; if (thd->net.report_error) res= -1; } @@ -2718,51 +2657,25 @@ unsent_create_error: } case SQLCOM_DELETE_MULTI: { - TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first; + TABLE_LIST *aux_tables= + (TABLE_LIST *)thd->lex->auxilliary_table_list.first; + TABLE_LIST *delete_tables= (TABLE_LIST*)select_lex->table_list.first; + TABLE_LIST *auxi; - uint table_count=0; + uint table_count= 0; multi_delete *result; + if ((res= multi_delete_precheck(thd, tables, &table_count))) + break; - /* sql_yacc guarantees that tables and aux_tables are not zero */ - if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) || - check_table_access(thd,SELECT_ACL, tables,0) || - check_table_access(thd,DELETE_ACL, aux_tables,0)) - goto error; - if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where) - { - send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); - goto error; - } - for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) - { - table_count++; - /* All tables in aux_tables must be found in FROM PART */ - TABLE_LIST *walk; - for (walk= (TABLE_LIST*) tables; walk; walk= walk->next) - { - if (!my_strcasecmp(table_alias_charset, auxi->alias, walk->alias) && - !strcmp(walk->db, auxi->db)) - break; - } - if (!walk) - { - net_printf(thd, ER_NONUNIQ_TABLE, auxi->real_name); - goto error; - } - if (walk->derived) - { - net_printf(thd, ER_NON_UPDATABLE_TABLE, - auxi->real_name, "DELETE"); - goto error; - } - walk->lock_type= auxi->lock_type; - auxi->table_list= walk; // Remember corresponding table - } + // condition will be TRUE on SP re esexcuting + if (select_lex->item_list.elements != 0) + select_lex->item_list.empty(); if (add_item_to_list(thd, new Item_null())) { res= -1; break; } + thd->proc_info="init"; if ((res=open_and_lock_tables(thd,tables))) break; @@ -3494,9 +3407,8 @@ error: 0 - OK 1 - access denied, error is sent to client */ - -static int check_one_table_access(THD *thd, ulong privilege, - TABLE_LIST *tables, bool no_errors) +int check_one_table_access(THD *thd, ulong privilege, + TABLE_LIST *tables, bool no_errors) { if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0)) @@ -3694,8 +3606,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, return FALSE; } -static bool check_merge_table_access(THD *thd, char *db, - TABLE_LIST *table_list) +bool check_merge_table_access(THD *thd, char *db, + TABLE_LIST *table_list) { int error=0; if (table_list) @@ -4977,3 +4889,181 @@ Item * all_any_subquery_creator(Item *left_expr, return it; /* ANY/SOME */ } + + +/* + Multi update query pre-check + + SYNOPSIS + multi_update_precheck() + thd - thread handler + tables - global table list + + RETURN + 0 - OK + 1 - error (message is sent to user) + -1 - error (message is not sent to user) +*/ +int multi_update_precheck(THD *thd, TABLE_LIST *tables) +{ + DBUG_ENTER("multi_update_precheck"); + const char *msg= 0; + TABLE_LIST *table; + LEX *lex= thd->lex; + SELECT_LEX *select_lex= &lex->select_lex; + TABLE_LIST *update_list= (TABLE_LIST*)select_lex->table_list.first; + + if (select_lex->item_list.elements != lex->value_list.elements) + { + my_error(ER_WRONG_VALUE_COUNT, MYF(0)); + DBUG_RETURN(-1); + } + /* + Ensure that we have UPDATE or SELECT privilege for each table + The exact privilege is checked in mysql_multi_update() + */ + for (table= update_list; table; table= table->next) + { + TABLE_LIST *save= table->next; + table->next= 0; + if ((check_access(thd, UPDATE_ACL, table->db, + &table->grant.privilege, 0, 1) || + grant_option && check_grant(thd, UPDATE_ACL, table, 0, 1)) && + (check_access(thd, SELECT_ACL, table->db, + &table->grant.privilege, 0, 0) || + grant_option && check_grant(thd, SELECT_ACL, table, 0, 0))) + DBUG_RETURN(1); + table->next= save; + if (table->table_list) + table->table_list->checked= 1; + } + // tables of subqueries + if (&lex->select_lex != lex->all_selects_list) + { + for (table= tables; table; table= table->next) + { + if (table->checked) + { + table->checked= 0; + /* + If we check table by local TABLE_LIST copy then we should copy + grants to global table list, because it will be used for table + opening. + */ + if (table->table_list) + table->grant= table->table_list->grant; + } + else + { + TABLE_LIST *save= table->next; + table->next= 0; + if (check_access(thd, SELECT_ACL, table->db, + &table->grant.privilege, 0, 0) || + grant_option && check_grant(thd, SELECT_ACL, table, 0, 0)) + DBUG_RETURN(1); + table->next= save; + } + } + } + + if (select_lex->order_list.elements) + msg= "ORDER BY"; + else if (select_lex->select_limit && select_lex->select_limit != + HA_POS_ERROR) + msg= "LIMIT"; + if (msg) + { + my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg); + DBUG_RETURN(-1); + } + DBUG_RETURN(0); +} + +/* + Multi delete query pre-check + + SYNOPSIS + multi_delete_precheck() + thd - thread handler + tables - global table list + table_count - pointer to table counter + + RETURN + 0 - OK + 1 - error (message is sent to user) + -1 - error (message is not sent to user) +*/ +int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) +{ + DBUG_ENTER("multi_delete_precheck"); + SELECT_LEX *select_lex= &thd->lex->select_lex; + TABLE_LIST *aux_tables= + (TABLE_LIST *)thd->lex->auxilliary_table_list.first; + TABLE_LIST *delete_tables= (TABLE_LIST *)select_lex->table_list.first; + TABLE_LIST *auxi; + + /* sql_yacc guarantees that tables and aux_tables are not zero */ + DBUG_ASSERT(aux_tables != 0); + if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) || + check_table_access(thd,SELECT_ACL, tables,0) || + check_table_access(thd,DELETE_ACL, aux_tables,0)) + DBUG_RETURN(1); + if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where) + { + my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, MYF(0)); + DBUG_RETURN(-1); + } + for (auxi= aux_tables; auxi; auxi= auxi->next) + { + (*table_count)++; + /* All tables in aux_tables must be found in FROM PART */ + TABLE_LIST *walk; + for (walk= delete_tables; walk; walk= walk->next) + { + if (!my_strcasecmp(table_alias_charset, auxi->alias, walk->alias) && + !strcmp(walk->db, auxi->db)) + break; + } + if (!walk) + { + my_error(ER_UNKNOWN_TABLE, MYF(0), auxi->real_name, "MULTI DELETE"); + DBUG_RETURN(-1); + } + if (walk->derived) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), auxi->real_name, "DELETE"); + DBUG_RETURN(-1); + } + walk->lock_type= auxi->lock_type; + auxi->table_list= walk; // Remember corresponding table + } + DBUG_RETURN(0); +} + + +/* + INSERT ... SELECT query pre-check + + SYNOPSIS + multi_delete_precheck() + thd - thread handler + tables - global table list + + RETURN + 0 - OK + 1 - error (message is sent to user) + -1 - error (message is not sent to user) +*/ +int insert_select_precheck(THD *thd, TABLE_LIST *tables) +{ + DBUG_ENTER("insert_select_precheck"); + /* + Check that we have modify privileges for the first table and + select privileges for the rest + */ + ulong privilege= (thd->lex->duplicates == DUP_REPLACE ? + INSERT_ACL | DELETE_ACL : INSERT_ACL); + if (check_one_table_access(thd, privilege, tables, 0)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index bdbdcb28d3a..b4580ca5a60 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -646,26 +646,29 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt) static int mysql_test_insert_fields(Prepared_statement *stmt, TABLE_LIST *table_list, List<Item> &fields, - List<List_item> &values_list) + List<List_item> &values_list, + List<Item> &update_fields, + List<Item> &update_values, + enum_duplicates duplic) { THD *thd= stmt->thd; + LEX *lex= stmt->lex; TABLE *table; List_iterator_fast<List_item> its(values_list); List_item *values; + TABLE_LIST *insert_table_list= + (TABLE_LIST*) lex->select_lex.table_list.first; DBUG_ENTER("mysql_test_insert_fields"); #ifndef NO_EMBEDDED_ACCESS_CHECKS - my_bool update=(stmt->lex->value_list.elements ? UPDATE_ACL : 0); - ulong privilege= (stmt->lex->duplicates == DUP_REPLACE ? - INSERT_ACL | DELETE_ACL : INSERT_ACL | update); - if (check_access(thd,privilege,table_list->db, - &table_list->grant.privilege,0,0) || - (grant_option && check_grant(thd,privilege,table_list,0,0))) - DBUG_RETURN(1); + ulong privilege= (lex->duplicates == DUP_REPLACE ? + INSERT_ACL | DELETE_ACL : INSERT_ACL); + if (check_one_table_access(thd, privilege, table_list, 0)) + DBUG_RETURN(1); #endif - /* + /* open temporary memory pool for temporary data allocated by derived tables & preparation procedure */ @@ -683,12 +686,19 @@ static int mysql_test_insert_fields(Prepared_statement *stmt, uint value_count; ulong counter= 0; - if (check_insert_fields(thd,table,fields,*values,1)) + if (check_insert_fields(thd, table, fields, *values, 1) || + setup_tables(insert_table_list) || + setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) || + (duplic == DUP_UPDATE && + (setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) || + setup_fields(thd, 0, insert_table_list, update_values, 0, 0, 0)))) + goto error; + if (find_real_table_in_list(table_list->next, + table_list->db, table_list->real_name)) { - thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(-1); + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); + goto error; } - thd->free_temporary_memory_pool_for_ps_preparing(); value_count= values->elements; its.rewind(); @@ -701,15 +711,20 @@ static int mysql_test_insert_fields(Prepared_statement *stmt, my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, ER(ER_WRONG_VALUE_COUNT_ON_ROW), MYF(0), counter); - DBUG_RETURN(-1); + goto error; } + if (setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0)) + goto error; } } - else - { - thd->free_temporary_memory_pool_for_ps_preparing(); - } + lex->unit.cleanup(); + thd->free_temporary_memory_pool_for_ps_preparing(); DBUG_RETURN(0); + +error: + lex->unit.cleanup(); + thd->free_temporary_memory_pool_for_ps_preparing(); + DBUG_RETURN(-1); } @@ -728,19 +743,26 @@ static int mysql_test_insert_fields(Prepared_statement *stmt, static int mysql_test_upd_fields(Prepared_statement *stmt, TABLE_LIST *table_list, List<Item> &fields, List<Item> &values, - COND *conds) + COND *conds, ulong privelege) { THD *thd= stmt->thd; + SELECT_LEX *select_lex= &stmt->lex->select_lex; + TABLE_LIST *upd_table_list= + (TABLE_LIST*) select_lex->table_list.first; + List<Item> all_fields; + uint order_num= select_lex->order_list.elements; + ORDER *order= (ORDER *) select_lex->order_list.first; DBUG_ENTER("mysql_test_upd_fields"); #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_access(thd,UPDATE_ACL,table_list->db, - &table_list->grant.privilege,0,0) || - (grant_option && check_grant(thd,UPDATE_ACL,table_list,0,0))) + if (check_one_table_access(thd, privelege, table_list, 0)) DBUG_RETURN(1); + // Set privilege for the WHERE clause + table_list->grant.want_privilege= (SELECT_ACL & + ~table_list->grant.privilege); #endif - /* + /* open temporary memory pool for temporary data allocated by derived tables & preparation procedure */ @@ -748,11 +770,19 @@ static int mysql_test_upd_fields(Prepared_statement *stmt, if (open_and_lock_tables(thd, table_list)) goto err; - if (setup_tables(table_list) || - setup_fields(thd, 0, table_list, fields, 1, 0, 0) || - setup_conds(thd, table_list, &conds) || thd->net.report_error) + if (setup_tables(upd_table_list) || + setup_conds(thd, upd_table_list, &conds) || + thd->lex->select_lex.setup_ref_array(thd, order_num) || + setup_fields(thd, 0, upd_table_list, fields, 1, 0, 0) || + setup_order(thd, thd->lex->select_lex.ref_pointer_array, + upd_table_list, all_fields, all_fields, order) || + thd->net.report_error) + { + stmt->lex->unit.cleanup(); goto err; + } + stmt->lex->unit.cleanup(); thd->free_temporary_memory_pool_for_ps_preparing(); /* TODO: here we should send types of placeholders to the client. */ @@ -782,16 +812,12 @@ err: static int mysql_test_select_fields(Prepared_statement *stmt, TABLE_LIST *tables, - uint wild_num, - List<Item> &fields, COND *conds, - uint og_num, ORDER *order, ORDER *group, - Item *having, ORDER *proc, - ulong select_options, - SELECT_LEX_UNIT *unit, - SELECT_LEX *select_lex) + List<Item> &fields) { THD *thd= stmt->thd; LEX *lex= stmt->lex; + SELECT_LEX_UNIT *unit= &lex->unit; + DBUG_ENTER("mysql_test_select_fields"); @@ -805,11 +831,8 @@ static int mysql_test_select_fields(Prepared_statement *stmt, else if (check_access(thd, privilege, "*any*",0,0,0)) DBUG_RETURN(1); #endif - if ((&lex->select_lex != lex->all_selects_list && - lex->unit.create_total_list(thd, lex, &tables))) - DBUG_RETURN(1); - /* + /* open temporary memory pool for temporary data allocated by derived tables & preparation procedure */ @@ -825,18 +848,11 @@ static int mysql_test_select_fields(Prepared_statement *stmt, if (send_prep_stmt(stmt, 0)) goto err; } - else + else { - select_result *result= lex->result; - if (!result && !(result= new select_send())) - { - send_error(thd, ER_OUT_OF_RESOURCES); - goto err; - } - thd->used_tables= 0; // Updated by setup_fields - if (unit->prepare(thd, result, 0)) + if (unit->prepare(thd, 0, 0)) { send_error(thd); goto err_prep; @@ -864,6 +880,277 @@ err: /* + Validate and prepare for execution DO statement expressions + + SYNOPSIS + mysql_test_do_fields() + stmt prepared statemen handler + tables list of tables queries + values list of expressions + + RETURN VALUE + 0 success + 1 error, sent to client + -1 error, not sent to client +*/ + +static int mysql_test_do_fields(Prepared_statement *stmt, + TABLE_LIST *tables, + List<Item> *values) +{ + DBUG_ENTER("mysql_test_do_fields"); + THD *thd= stmt->thd; + int res= 0; + if (tables && (res= check_table_access(thd, SELECT_ACL, tables, 0))) + DBUG_RETURN(res); + /* + open temporary memory pool for temporary data allocated by derived + tables & preparation procedure + */ + thd->allocate_temporary_memory_pool_for_ps_preparing(); + if (tables && (res= open_and_lock_tables(thd, tables))) + { + thd->free_temporary_memory_pool_for_ps_preparing(); + DBUG_RETURN(res); + } + res= setup_fields(thd, 0, 0, *values, 0, 0, 0); + stmt->lex->unit.cleanup(); + thd->free_temporary_memory_pool_for_ps_preparing(); + if (res) + DBUG_RETURN(-1); + DBUG_RETURN(0); +} + + +/* + Validate and prepare for execution SET statement expressions + + SYNOPSIS + mysql_test_set_fields() + stmt prepared statemen handler + tables list of tables queries + values list of expressions + + RETURN VALUE + 0 success + 1 error, sent to client + -1 error, not sent to client +*/ +static int mysql_test_set_fields(Prepared_statement *stmt, + TABLE_LIST *tables, + List<set_var_base> *var_list) +{ + DBUG_ENTER("mysql_test_set_fields"); + List_iterator_fast<set_var_base> it(*var_list); + THD *thd= stmt->thd; + set_var_base *var; + int res= 0; + + if (tables && (res= check_table_access(thd, SELECT_ACL, tables, 0))) + DBUG_RETURN(res); + /* + open temporary memory pool for temporary data allocated by derived + tables & preparation procedure + */ + thd->allocate_temporary_memory_pool_for_ps_preparing(); + if (tables && (res= open_and_lock_tables(thd, tables))) + goto error; + while ((var= it++)) + { + if (var->light_check(thd)) + { + stmt->lex->unit.cleanup(); + res= -1; + goto error; + } + } + stmt->lex->unit.cleanup(); + thd->free_temporary_memory_pool_for_ps_preparing(); + DBUG_RETURN(0); + +error: + thd->free_temporary_memory_pool_for_ps_preparing(); + DBUG_RETURN(res); +} + + +/* + Check internal SELECT of the prepared command + + SYNOPSIS + select_like_statement_test() + stmt - prepared table handler + tables - global list of tables + + RETURN + 0 success + 1 error, sent to client + -1 error, not sent to client +*/ +static int select_like_statement_test(Prepared_statement *stmt, + TABLE_LIST *tables) +{ + DBUG_ENTER("select_like_statement_test"); + THD *thd= stmt->thd; + LEX *lex= stmt->lex; + int res= 0; + /* + open temporary memory pool for temporary data allocated by derived + tables & preparation procedure + */ + thd->allocate_temporary_memory_pool_for_ps_preparing(); + if (tables && (res= open_and_lock_tables(thd, tables))) + goto end; + + thd->used_tables= 0; // Updated by setup_fields + + if (lex->unit.prepare(thd, 0, 0)) + { + res= thd->net.report_error ? -1 : 1; + } +end: + lex->unit.cleanup(); + thd->free_temporary_memory_pool_for_ps_preparing(); + DBUG_RETURN(res); +} + + +/* + Validate and prepare for execution CRETE TABLE statement + + SYNOPSIS + mysql_test_create_table() + stmt prepared statemen handler + tables list of tables queries + + RETURN VALUE + 0 success + 1 error, sent to client + -1 error, not sent to client +*/ +static int mysql_test_create_table(Prepared_statement *stmt, + TABLE_LIST *tables) +{ + DBUG_ENTER("mysql_test_create_table"); + THD *thd= stmt->thd; + LEX *lex= stmt->lex; + int res= 0; + + ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? + CREATE_TMP_ACL : CREATE_ACL); + if (check_one_table_access(thd, want_priv, tables, 0) || + check_merge_table_access(thd, tables->db, + (TABLE_LIST *) + lex->create_info.merge_list.first)) + DBUG_RETURN(1); + + /* Skip first table, which is the table we are creating */ + TABLE_LIST *create_table, *create_table_local; + tables= lex->unlink_first_table(tables, &create_table, + &create_table_local); + + if (grant_option && want_priv != CREATE_TMP_ACL && + check_grant(thd, want_priv, create_table,0,0)) + { + res= 1; + goto end; + } + + if (tables) + res= select_like_statement_test(stmt, tables); + +end: + // put tables back for PS rexecuting + tables= lex->link_first_table_back(tables, create_table, + create_table_local); + DBUG_RETURN(res); +} + +/* + Validate and prepare for execution multy update statement + + SYNOPSIS + mysql_test_multiupdate() + stmt prepared statemen handler + tables list of tables queries + + RETURN VALUE + 0 success + 1 error, sent to client + -1 error, not sent to client +*/ +static int mysql_test_multiupdate(Prepared_statement *stmt, + TABLE_LIST *tables) +{ + int res; + if ((res= multi_update_precheck(stmt->thd, tables))) + return res; + return select_like_statement_test(stmt, tables); +} + + +/* + Validate and prepare for execution multy delete statement + + SYNOPSIS + mysql_test_multidelete() + stmt prepared statemen handler + tables list of tables queries + + RETURN VALUE + 0 success + 1 error, sent to client + -1 error, not sent to client +*/ +static int mysql_test_multidelete(Prepared_statement *stmt, + TABLE_LIST *tables) +{ + int res; + stmt->thd->lex->current_select= &stmt->thd->lex->select_lex; + if (add_item_to_list(stmt->thd, new Item_null())) + return -1; + + uint fake_counter= 0; + if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter))) + return res; + return select_like_statement_test(stmt, tables); +} + + +/* + Validate and prepare for execution INSERT ... SELECT statement + + SYNOPSIS + mysql_test_insert_select() + stmt prepared statemen handler + tables list of tables queries + + RETURN VALUE + 0 success + 1 error, sent to client + -1 error, not sent to client +*/ +static int mysql_test_insert_select(Prepared_statement *stmt, + TABLE_LIST *tables) +{ + int res; + LEX *lex= stmt->lex; + if ((res= insert_select_precheck(stmt->thd, tables))) + return res; + TABLE_LIST *first_local_table= + (TABLE_LIST *)lex->select_lex.table_list.first; + /* Skip first table, which is the table we are inserting in */ + lex->select_lex.table_list.first= (gptr) first_local_table->next; + lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE; + res= select_like_statement_test(stmt, tables); + /* revert changes*/ + lex->select_lex.table_list.first= (gptr) first_local_table; + lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; + return res; +} + + +/* Send the prepare query results back to client SYNOPSIS send_prepare_results() @@ -872,25 +1159,33 @@ err: 0 success 1 error, sent to client */ - static int send_prepare_results(Prepared_statement *stmt) { + DBUG_ENTER("send_prepare_results"); THD *thd= stmt->thd; LEX *lex= stmt->lex; SELECT_LEX *select_lex= &lex->select_lex; TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first; enum enum_sql_command sql_command= lex->sql_command; int res; - - DBUG_ENTER("send_prepare_results"); DBUG_PRINT("enter",("command: %d, param_count: %ld", sql_command, stmt->param_count)); + + if (&lex->select_lex != lex->all_selects_list && + lex->unit.create_total_list(thd, lex, &tables)) + DBUG_RETURN(1); + switch (sql_command) { + case SQLCOM_REPLACE: case SQLCOM_INSERT: - if ((res= mysql_test_insert_fields(stmt, tables, lex->field_list, - lex->many_values))) + if ((res= + mysql_test_insert_fields(stmt, tables, lex->field_list, + lex->many_values, + select_lex->item_list, lex->value_list, + (lex->value_list.elements ? + DUP_UPDATE : lex->duplicates)))) goto error; break; @@ -898,32 +1193,75 @@ static int send_prepare_results(Prepared_statement *stmt) /* XXX: fallthrough */ case SQLCOM_DELETE: if ((res= mysql_test_upd_fields(stmt, tables, select_lex->item_list, - lex->value_list, select_lex->where))) + lex->value_list, select_lex->where, + ((sql_command == SQLCOM_DELETE)? + DELETE_ACL : UPDATE_ACL)))) goto error; break; case SQLCOM_SELECT: - if ((res= mysql_test_select_fields(stmt, tables, select_lex->with_wild, - select_lex->item_list, - select_lex->where, - select_lex->order_list.elements + - select_lex->group_list.elements, - (ORDER*) select_lex->order_list.first, - (ORDER*) select_lex->group_list.first, - select_lex->having, - (ORDER*)lex->proc_list.first, - select_lex->options | thd->options, - &(lex->unit), select_lex))) + if ((res= mysql_test_select_fields(stmt, tables, select_lex->item_list))) goto error; /* Statement and field info has already been sent */ DBUG_RETURN(0); + case SQLCOM_CREATE_TABLE: + if ((res= mysql_test_create_table(stmt, tables))) + goto error; + break; + + case SQLCOM_DO: + if ((res= mysql_test_do_fields(stmt, tables, lex->insert_list))) + goto error; + break; + + case SQLCOM_SET_OPTION: + if ((res= mysql_test_set_fields(stmt, tables, &lex->var_list))) + goto error; + break; + + case SQLCOM_DELETE_MULTI: + if ((res= mysql_test_multidelete(stmt, tables))) + goto error; + break; + + case SQLCOM_UPDATE_MULTI: + if ((res= mysql_test_multiupdate(stmt, tables))) + goto error; + break; + + case SQLCOM_INSERT_SELECT: + if ((res= mysql_test_insert_select(stmt, tables))) + goto error; + break; + + case SQLCOM_SHOW_DATABASES: + case SQLCOM_SHOW_PROCESSLIST: + case SQLCOM_SHOW_STORAGE_ENGINES: + case SQLCOM_SHOW_PRIVILEGES: + case SQLCOM_SHOW_COLUMN_TYPES: + case SQLCOM_SHOW_STATUS: + case SQLCOM_SHOW_VARIABLES: + case SQLCOM_SHOW_LOGS: + case SQLCOM_SHOW_TABLES: + case SQLCOM_SHOW_OPEN_TABLES: + case SQLCOM_SHOW_CHARSETS: + case SQLCOM_SHOW_COLLATIONS: + case SQLCOM_SHOW_FIELDS: + case SQLCOM_SHOW_KEYS: + case SQLCOM_SHOW_CREATE_DB: + case SQLCOM_SHOW_GRANTS: + case SQLCOM_DROP_TABLE: + case SQLCOM_RENAME_TABLE: + break; + default: - /* - Rest fall through to default category, no parsing - for non-DML statements + /* + All other is not supported yet */ - break; + res= -1; + my_error(ER_UNSUPPORTED_PS, MYF(0)); + goto error; } DBUG_RETURN(send_prep_stmt(stmt, 0)); @@ -1176,6 +1514,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) */ thd->protocol= &thd->protocol_prep; // Switch to binary protocol mysql_execute_command(thd); + thd->lex->unit.cleanup(); thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 598b53fe7dd..03b6d9b6bbb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -434,7 +434,7 @@ JOIN::prepare(Item ***rref_pointer_array, goto err; } #endif - if (!procedure && result->prepare(fields_list, unit_arg)) + if (!procedure && result && result->prepare(fields_list, unit_arg)) goto err; /* purecov: inspected */ if (select_lex->olap == ROLLUP_TYPE && rollup_init()) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 7265a99d6e5..468bdab9119 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -460,13 +460,24 @@ int st_select_lex_unit::cleanup() table= 0; // Safety } JOIN *join; - for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select()) + SELECT_LEX *sl= first_select_in_union(); + for (; sl; sl= sl->next_select()) { if ((join= sl->join)) { error|= sl->join->cleanup(); delete join; } + else + { + // it can be DO/SET with subqueries + for (SELECT_LEX_UNIT *lex_unit= sl->first_inner_unit(); + lex_unit != 0; + lex_unit= lex_unit->next_unit()) + { + error|= lex_unit->cleanup(); + } + } } if (fake_select_lex && (join= fake_select_lex->join)) { diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 1a9906be0cc..c7c87a488fd 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -99,7 +99,7 @@ int mysql_update(THD *thd, setup_conds(thd,update_table_list,&conds) || thd->lex->select_lex.setup_ref_array(thd, order_num) || setup_order(thd, thd->lex->select_lex.ref_pointer_array, - &tables, all_fields, all_fields, order) || + update_table_list, all_fields, all_fields, order) || setup_ftfuncs(&thd->lex->select_lex)) DBUG_RETURN(-1); /* purecov: inspected */ @@ -427,6 +427,9 @@ int mysql_multi_update(THD *thd, int res; multi_update *result; TABLE_LIST *tl; + TABLE_LIST *update_list= + (TABLE_LIST*)thd->lex->select_lex.table_list.first; + table_map item_tables= 0, derived_tables= 0; DBUG_ENTER("mysql_multi_update"); @@ -439,7 +442,7 @@ int mysql_multi_update(THD *thd, Ensure that we have update privilege for all tables and columns in the SET part */ - for (tl= table_list ; tl ; tl=tl->next) + for (tl= update_list; tl; tl= tl->next) { TABLE *table= tl->table; /* @@ -456,14 +459,14 @@ int mysql_multi_update(THD *thd, { // Assign table map values to check updatability of derived tables uint tablenr=0; - for (TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first; + for (TABLE_LIST *table_list= update_list; table_list; table_list= table_list->next, tablenr++) { table_list->table->map= (table_map) 1 << tablenr; } } - if (setup_fields(thd, 0, table_list, *fields, 1, 0, 0)) + if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0)) DBUG_RETURN(-1); if (thd->lex->derived_tables) { @@ -479,7 +482,7 @@ int mysql_multi_update(THD *thd, /* Count tables and setup timestamp handling */ - for (tl= select_lex->get_table_list() ; tl ; tl= tl->next) + for (tl= update_list; tl; tl= tl->next) { TABLE *table= tl->table; @@ -496,7 +499,7 @@ int mysql_multi_update(THD *thd, if (thd->lex->derived_tables && (item_tables & derived_tables)) { // find derived table which cause error - for (tl= select_lex->get_table_list() ; tl ; tl= tl->next) + for (tl= update_list; tl; tl= tl->next) { if (tl->derived && (item_tables & tl->table->map)) { diff --git a/sql/table.h b/sql/table.h index 0bae880a89f..bbf22ae6725 100644 --- a/sql/table.h +++ b/sql/table.h @@ -193,6 +193,7 @@ typedef struct st_table_list bool updating; /* for replicate-do/ignore table */ bool force_index; /* Prefer index over table scan */ bool ignore_leaves; /* Preload only non-leaf nodes */ + bool checked; /* used in multi-upd privelege check */ bool non_cachable_table; /* stop PS caching */ } TABLE_LIST; diff --git a/tests/client_test.c b/tests/client_test.c index eaa9c6d7acd..795dbd26769 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -925,14 +925,6 @@ static void test_prepare_simple() rc = mysql_query(mysql,"CREATE TABLE test_prepare_simple(id int, name varchar(50))"); myquery(rc); - /* alter table */ - strmov(query,"ALTER TABLE test_prepare_simple ADD new char(20)"); - stmt = mysql_simple_prepare(mysql, query); - mystmt_init(stmt); - - verify_param_count(stmt,0); - mysql_stmt_close(stmt); - /* insert */ strmov(query,"INSERT INTO test_prepare_simple VALUES(?,?)"); stmt = mysql_simple_prepare(mysql, query); @@ -1541,22 +1533,25 @@ static void test_select_version() } /******************************************************** -* to test simple select * +* to test simple show * *********************************************************/ -static void test_select_simple() +static void test_select_show_table() { MYSQL_STMT *stmt; - int rc; + int rc, i; - myheader("test_select_simple"); + myheader("test_select_show_table"); stmt = mysql_simple_prepare(mysql, "SHOW TABLES FROM mysql"); mystmt_init(stmt); verify_param_count(stmt,0); - rc = mysql_execute(stmt); - mystmt(stmt, rc); + for (i= 1; i < 3; i++) + { + rc = mysql_execute(stmt); + mystmt(stmt, rc); + } my_process_stmt_result(stmt); mysql_stmt_close(stmt); @@ -4048,7 +4043,7 @@ static void test_stmt_close() rc = mysql_query(lmysql,"CREATE TABLE test_stmt_close(id int)"); myquery(rc); - strmov(query,"ALTER TABLE test_stmt_close ADD name varchar(20)"); + strmov(query,"DO \"nothing\""); stmt1= mysql_simple_prepare(lmysql, query); mystmt_init(stmt1); @@ -6452,14 +6447,10 @@ static void test_prepare_grant() myquery_r(rc); stmt= mysql_simple_prepare(mysql,"DELETE FROM test_grant"); - mystmt_init(stmt); - - rc = mysql_execute(stmt); - myquery_r(rc); + mystmt_init_r(stmt); assert(4 == my_stmt_result("SELECT * FROM test_grant")); - mysql_stmt_close(stmt); mysql_close(lmysql); mysql= org_mysql; @@ -8214,6 +8205,7 @@ static void test_subqueries() MYSQL_STMT *stmt; int rc, i; const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s, (a-1,b-1) in (select a,b from t2) as in_row_s FROM t1, (select a x, b y from t2) tt WHERE x=a"; + /* const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s FROM t1, (select a x, b y from t2) tt WHERE x=a"; */ myheader("test_subquery"); @@ -8594,13 +8586,22 @@ static void test_selecttmp() static void test_create_drop() { - MYSQL_STMT *stmt_create, *stmt_drop; + MYSQL_STMT *stmt_create, *stmt_drop, *stmt_select, *stmt_create_select; char *query; int rc, i; myheader("test_table_manipulation"); rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2"); myquery(rc); + + rc= mysql_query(mysql,"create table t2 (a int);"); + myquery(rc); + + rc= mysql_query(mysql,"create table t1 (a int);"); + myquery(rc); + + rc= mysql_query(mysql, "insert into t2 values (3), (2), (1);"); + myquery(rc); query= (char*)"create table t1 (a int)"; stmt_create= mysql_prepare(mysql, query, strlen(query)); @@ -8610,18 +8611,51 @@ static void test_create_drop() stmt_drop= mysql_prepare(mysql, query, strlen(query)); mystmt_init(stmt_drop); + query= (char*)"select a in (select a from t2) from t1"; + stmt_select= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_select); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); + + query= (char*)"create table t1 select a from t2"; + stmt_create_select= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_create_select); + for (i= 0; i < 3; i++) { rc= mysql_execute(stmt_create); mystmt(stmt_create, rc); fprintf(stdout, "created %i\n", i); + + rc= mysql_execute(stmt_select); + mystmt(stmt_select, rc); + assert(0 == my_process_stmt_result(stmt_select)); + rc= mysql_execute(stmt_drop); mystmt(stmt_drop, rc); - fprintf(stdout, "droped %i\n", i); + fprintf(stdout, "droped %i\n", i); + + rc= mysql_execute(stmt_create_select); + mystmt(stmt_create, rc); + fprintf(stdout, "created select %i\n", i); + + rc= mysql_execute(stmt_select); + mystmt(stmt_select, rc); + assert(3 == my_process_stmt_result(stmt_select)); + + rc= mysql_execute(stmt_drop); + mystmt(stmt_drop, rc); + fprintf(stdout, "droped %i\n", i); } mysql_stmt_close(stmt_create); mysql_stmt_close(stmt_drop); + mysql_stmt_close(stmt_select); + mysql_stmt_close(stmt_create_select); + + rc= mysql_query(mysql, "DROP TABLE t2"); + myquery(rc); } @@ -8669,6 +8703,166 @@ static void test_rename() myquery(rc); } + +static void test_do_set() +{ + MYSQL_STMT *stmt_do, *stmt_set; + char *query; + int rc, i; + myheader("test_do_set"); + + rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql,"create table t1 (a int)"); + myquery(rc); + + query= (char*)"do @var:=(1 in (select * from t1))"; + stmt_do= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_do); + + query= (char*)"set @var=(1 in (select * from t1))"; + stmt_set= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_set); + + for (i= 0; i < 3; i++) + { + rc= mysql_execute(stmt_do); + mystmt(stmt_do, rc); + fprintf(stdout, "do %i\n", i); + rc= mysql_execute(stmt_set); + mystmt(stmt_set, rc); + fprintf(stdout, "set %i\n", i); + } + + mysql_stmt_close(stmt_do); + mysql_stmt_close(stmt_set); +} + +static void test_multi() +{ + MYSQL_STMT *stmt_delete, *stmt_update, *stmt_select1, *stmt_select2; + char *query; + MYSQL_BIND bind[1]; + int rc, i; + long param= 1, length= 1; + myheader("test_multi"); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (char *)¶m; + bind[0].buffer_length= 0; + bind[0].is_null= 0; + bind[0].length= &length; + + rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2"); + myquery(rc); + + rc= mysql_query(mysql,"create table t1 (a int, b int)"); + myquery(rc); + + rc= mysql_query(mysql,"create table t2 (a int, b int)"); + myquery(rc); + + rc= mysql_query(mysql,"insert into t1 values (3,3), (2,2), (1,1)"); + myquery(rc); + + rc= mysql_query(mysql,"insert into t2 values (3,3), (2,2), (1,1)"); + myquery(rc); + + query= (char*)"delete t1,t2 from t1,t2 where t1.a=t2.a and t1.b=10"; + stmt_delete= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_delete); + + query= (char*)"update t1,t2 set t1.b=10,t2.b=10 where t1.a=t2.a and t1.b=?"; + stmt_update= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_update); + + query= (char*)"select * from t1"; + stmt_select1= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_select1); + + query= (char*)"select * from t2"; + stmt_select2= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_select2); + + for(i= 0; i < 3; i++) + { + rc= mysql_bind_param(stmt_update, bind); + mystmt(stmt_update,rc); + + rc= mysql_execute(stmt_update); + mystmt(stmt_update, rc); + fprintf(stdout, "update %ld\n", param); + + rc= mysql_execute(stmt_delete); + mystmt(stmt_delete, rc); + fprintf(stdout, "delete %ld\n", param); + + rc= mysql_execute(stmt_select1); + mystmt(stmt_select1, rc); + assert((uint)(3-param) == my_process_stmt_result(stmt_select1)); + + rc= mysql_execute(stmt_select2); + mystmt(stmt_select2, rc); + assert((uint)(3-param) == my_process_stmt_result(stmt_select2)); + + param++; + } + + mysql_stmt_close(stmt_delete); + mysql_stmt_close(stmt_update); + mysql_stmt_close(stmt_select1); + mysql_stmt_close(stmt_select2); + rc= mysql_query(mysql,"drop table t1,t2"); + myquery(rc); +} + + +static void test_insert_select() +{ + MYSQL_STMT *stmt_insert, *stmt_select; + char *query; + int rc, i; + myheader("test_insert_select"); + + rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2"); + myquery(rc); + + rc= mysql_query(mysql,"create table t1 (a int)"); + myquery(rc); + + rc= mysql_query(mysql,"create table t2 (a int)"); + myquery(rc); + + rc= mysql_query(mysql,"insert into t2 values (1)"); + myquery(rc); + + query= (char*)"insert into t1 select a from t2"; + stmt_insert= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_insert); + + query= (char*)"select * from t1"; + stmt_select= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt_select); + + for(i= 0; i < 3; i++) + { + rc= mysql_execute(stmt_insert); + mystmt(stmt_insert, rc); + fprintf(stdout, "insert %u\n", i); + + rc= mysql_execute(stmt_select); + mystmt(stmt_select, rc); + assert((i+1) == my_process_stmt_result(stmt_select)); + } + + mysql_stmt_close(stmt_insert); + mysql_stmt_close(stmt_select); + rc= mysql_query(mysql,"drop table t1,t2"); + myquery(rc); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -8831,7 +9025,7 @@ int main(int argc, char **argv) test_select_prepare(); /* prepare select - protocol_prep debug */ test_select(); /* simple select test */ test_select_version(); /* select with variables */ - test_select_simple(); /* simple select prepare */ + test_select_show_table();/* simple show prepare */ #if NOT_USED /* Enable this tests from 4.1.1 when mysql_param_result() is @@ -8932,6 +9126,9 @@ int main(int argc, char **argv) test_selecttmp(); /* temporary table used in select execution */ test_create_drop(); /* some table manipulation BUG#2811 */ test_rename(); /* rename test */ + test_do_set(); /* DO & SET commands test BUG#3393 */ + test_multi(); /* test of multi delete & update */ + test_insert_select(); /* test INSERT ... SELECT */ end_time= time((time_t *)0); total_time+= difftime(end_time, start_time); |