diff options
-rw-r--r-- | mysql-test/r/trigger.result | 13 | ||||
-rw-r--r-- | mysql-test/t/trigger.test | 23 | ||||
-rw-r--r-- | sql/item_subselect.cc | 8 | ||||
-rw-r--r-- | sql/item_subselect.h | 7 | ||||
-rw-r--r-- | sql/sql_class.h | 7 | ||||
-rw-r--r-- | sql/sql_delete.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.h | 1 | ||||
-rw-r--r-- | sql/sql_parse.cc | 2 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 11 | ||||
-rw-r--r-- | sql/sql_update.cc | 6 |
10 files changed, 70 insertions, 13 deletions
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 284e4c1556b..ee0a6f6b744 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -651,3 +651,16 @@ insert into t1 values (0); ERROR 0A000: FLUSH is not allowed in stored function or trigger drop procedure p1; drop table t1; +create table t1 (id int, data int, username varchar(16)); +insert into t1 (id, data) values (1, 0); +create trigger t1_whoupdated before update on t1 for each row +begin +declare user varchar(32); +declare i int; +select user() into user; +set NEW.username = user; +select count(*) from ((select 1) union (select 2)) as d1 into i; +end| +update t1 set data = 1; +update t1 set data = 2; +drop table t1; diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 789405696c2..49ec42568ad 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -662,3 +662,26 @@ create procedure p1() flush privileges; insert into t1 values (0); drop procedure p1; drop table t1; + +# Test for bug #11973 "SELECT .. INTO var_name; in trigger cause +# crash on update" +create table t1 (id int, data int, username varchar(16)); +insert into t1 (id, data) values (1, 0); +delimiter |; +create trigger t1_whoupdated before update on t1 for each row +begin + declare user varchar(32); + declare i int; + select user() into user; + set NEW.username = user; + select count(*) from ((select 1) union (select 2)) as d1 into i; +end| +delimiter ;| +update t1 set data = 1; + +connect (addconroot, localhost, root,,); +connection addconroot; +update t1 set data = 2; + +connection default; +drop table t1; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 53e377339b3..accc6d420be 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1276,6 +1276,14 @@ void Item_allany_subselect::print(String *str) } +void subselect_engine::set_thd(THD *thd_arg) +{ + thd= thd_arg; + if (result) + result->set_thd(thd_arg); +} + + subselect_single_select_engine:: subselect_single_select_engine(st_select_lex *select, select_subselect *result, diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0b5736169fa..46623f76170 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -299,8 +299,11 @@ public: virtual ~subselect_engine() {}; // to satisfy compiler virtual void cleanup()= 0; - // set_thd should be called before prepare() - void set_thd(THD *thd_arg) { thd= thd_arg; } + /* + Also sets "thd" for subselect_engine::result. + Should be called before prepare(). + */ + void set_thd(THD *thd_arg); THD * get_thd() { return thd; } virtual int prepare()= 0; virtual void fix_length_and_dec(Item_cache** row)= 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index 3900b25626f..5d3361d6c51 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1565,6 +1565,7 @@ public: statement/stored procedure. */ virtual void cleanup(); + void set_thd(THD *thd_arg) { thd= thd_arg; } }; @@ -1920,14 +1921,13 @@ class multi_delete :public select_result_interceptor { TABLE_LIST *delete_tables, *table_being_deleted; Unique **tempfiles; - THD *thd; ha_rows deleted, found; uint num_of_tables; int error; bool do_delete, transactional_tables, normal_tables, delete_while_scanning; public: - multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables); + multi_delete(TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_data(List<Item> &items); @@ -1943,7 +1943,6 @@ class multi_update :public select_result_interceptor TABLE_LIST *all_tables; /* query/update command tables */ TABLE_LIST *leaves; /* list of leves of join table tree */ TABLE_LIST *update_tables, *table_being_updated; - THD *thd; TABLE **tmp_tables, *main_table, *table_to_update; TMP_TABLE_PARAM *tmp_table_param; ha_rows updated, found; @@ -1955,7 +1954,7 @@ class multi_update :public select_result_interceptor bool do_update, trans_safe, transactional_tables, ignore; public: - multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list, + multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list, List<Item> *fields, List<Item> *values, enum_duplicates handle_duplicates, bool ignore); ~multi_update(); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d83937098e2..b6183bf5acb 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -407,9 +407,8 @@ bool mysql_multi_delete_prepare(THD *thd) } -multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, - uint num_of_tables_arg) - : delete_tables(dt), thd(thd_arg), deleted(0), found(0), +multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg) + : delete_tables(dt), deleted(0), found(0), num_of_tables(num_of_tables_arg), error(0), do_delete(0), transactional_tables(0), normal_tables(0) { diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4bba0c432c7..e8c65ba5100 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -458,6 +458,7 @@ public: inline bool is_prepared() { return prepared; } bool change_result(select_subselect *result, select_subselect *old_result); void set_limit(st_select_lex *values); + void set_thd(THD *thd_arg) { thd= thd_arg; } friend void lex_start(THD *thd, uchar *buf, uint length); friend int subselect_union_engine::exec(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a0930307205..77b2cdad62b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3318,7 +3318,7 @@ end_with_restore_list: if ((res= mysql_multi_delete_prepare(thd))) goto error; - if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables, + if (!thd->is_fatal_error && (result= new multi_delete(aux_tables, lex->table_count))) { res= mysql_select(thd, &select_lex->ref_pointer_array, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9d60218b285..8c3a61d39de 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1855,6 +1855,13 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) SELECT_LEX *sl= lex->all_selects_list; DBUG_ENTER("reinit_stmt_before_use"); + /* + We have to update "thd" pointer in LEX, all its units and in LEX::result, + since statements which belong to trigger body are associated with TABLE + object and because of this can be used in different threads. + */ + lex->thd= thd; + if (lex->empty_field_list_on_rset) { lex->empty_field_list_on_rset= 0; @@ -1893,6 +1900,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) unit->types.empty(); /* for derived tables & PS (which can't be reset by Item_subquery) */ unit->reinit_exec_mechanism(); + unit->set_thd(thd); } } @@ -1931,7 +1939,10 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) lex->select_lex.leaf_tables= lex->leaf_tables_insert; if (lex->result) + { lex->result->cleanup(); + lex->result->set_thd(thd); + } DBUG_VOID_RETURN; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 6deff6b0040..aa39140f9b1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -821,7 +821,7 @@ bool mysql_multi_update(THD *thd, if (mysql_multi_update_prepare(thd)) DBUG_RETURN(TRUE); - if (!(result= new multi_update(thd, table_list, + if (!(result= new multi_update(table_list, thd->lex->select_lex.leaf_tables, fields, values, handle_duplicates, ignore))) @@ -847,13 +847,13 @@ bool mysql_multi_update(THD *thd, } -multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, +multi_update::multi_update(TABLE_LIST *table_list, TABLE_LIST *leaves_list, List<Item> *field_list, List<Item> *value_list, enum enum_duplicates handle_duplicates_arg, bool ignore_arg) :all_tables(table_list), leaves(leaves_list), update_tables(0), - thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list), + tmp_tables(0), updated(0), found(0), fields(field_list), values(value_list), table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0), transactional_tables(1), ignore(ignore_arg) |