summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/trigger.result13
-rw-r--r--mysql-test/t/trigger.test23
-rw-r--r--sql/item_subselect.cc8
-rw-r--r--sql/item_subselect.h7
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_delete.cc5
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_parse.cc2
-rw-r--r--sql/sql_prepare.cc11
-rw-r--r--sql/sql_update.cc6
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)