From: Tor Didriksen Date: June 10 2011 9:53am Subject: bzr push into mysql-trunk branch (tor.didriksen:3184 to 3185) Bug#11766429 List-Archive: http://lists.mysql.com/commits/139049 X-Bug: 11766429 Message-Id: <20110610095333.6F7B52AA@atum07.norway.sun.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3185 Tor Didriksen 2011-06-10 Bug#11766429 - 59533: RE-EXECUTE OF PREPARED STATEMENT CRASHES IN ITEM_REF::FIX_FIELDS WITH The second element of the GROUP BY list was const, and removed by remove_const. Solution: re-establish the list before second execution. @ sql/sql_lex.cc Add group_list_ptrs to remember the group_by list next pointers. @ sql/sql_lex.h Add group_list_ptrs to remember the group_by list next pointers. @ sql/sql_prepare.cc Re-establish group_list in reinit_stmt_before_use() modified: mysql-test/r/group_by.result mysql-test/t/group_by.test sql/sql_lex.cc sql/sql_lex.h sql/sql_prepare.cc 3184 Alexander Nozdrin 2011-06-10 [merge] Auto-merge from mysql-trunk. modified: mysql-test/r/type_datetime.result mysql-test/t/type_datetime.test sql/sql_select.cc === modified file 'mysql-test/r/group_by.result' --- a/mysql-test/r/group_by.result 2011-05-26 05:50:01 +0000 +++ b/mysql-test/r/group_by.result 2011-06-10 09:52:57 +0000 @@ -1967,3 +1967,23 @@ field1 field2 DROP TABLE t1; DROP TABLE where_subselect; # End of Bug #58782 +# +# Bug #11766429 +# RE-EXECUTE OF PREPARED STATEMENT CRASHES IN ITEM_REF::FIX_FIELDS WITH +# +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (0); +CREATE TABLE t2(b INT, KEY(b)); +INSERT INTO t2 VALUES (0),(0); +PREPARE stmt FROM ' +SELECT 1 FROM t2 +LEFT JOIN t1 ON NULL +GROUP BY t2.b, t1.a +HAVING a <> 2'; +EXECUTE stmt; +1 +EXECUTE stmt; +1 +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2; +# End of Bug #11766429 === modified file 'mysql-test/t/group_by.test' --- a/mysql-test/t/group_by.test 2011-02-18 10:59:18 +0000 +++ b/mysql-test/t/group_by.test 2011-06-10 09:52:57 +0000 @@ -1359,3 +1359,26 @@ DROP TABLE t1; DROP TABLE where_subselect; --echo # End of Bug #58782 + +--echo # +--echo # Bug #11766429 +--echo # RE-EXECUTE OF PREPARED STATEMENT CRASHES IN ITEM_REF::FIX_FIELDS WITH +--echo # + +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (0); +CREATE TABLE t2(b INT, KEY(b)); +INSERT INTO t2 VALUES (0),(0); + +PREPARE stmt FROM ' +SELECT 1 FROM t2 +LEFT JOIN t1 ON NULL +GROUP BY t2.b, t1.a +HAVING a <> 2'; +EXECUTE stmt; +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2; + +--echo # End of Bug #11766429 === modified file 'sql/sql_lex.cc' --- a/sql/sql_lex.cc 2011-05-26 15:20:09 +0000 +++ b/sql/sql_lex.cc 2011-06-10 09:52:57 +0000 @@ -380,6 +380,8 @@ void lex_start(THD *thd) lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; lex->select_lex.init_order(); lex->select_lex.group_list.empty(); + if (lex->select_lex.group_list_ptrs) + lex->select_lex.group_list_ptrs->clear(); lex->describe= DESCRIBE_NONE; lex->subqueries= FALSE; lex->context_analysis_only= 0; @@ -1776,6 +1778,8 @@ void st_select_lex::init_select() st_select_lex_node::init_select(); sj_nests.empty(); group_list.empty(); + if (group_list_ptrs) + group_list_ptrs->clear(); type= db= 0; having= 0; table_join_options= 0; @@ -3059,6 +3063,8 @@ static void fix_prepare_info_in_table_li The passed WHERE and HAVING are to be saved for the future executions. This function saves it, and returns a copy which can be thrashed during this execution of the statement. By saving/thrashing here we mean only + We also save the chain of ORDER::next in group_list, in case + the list is modified by remove_const(). AND/OR trees. The function also calls fix_prepare_info_in_table_list that saves all ON expressions. @@ -3070,6 +3076,19 @@ void st_select_lex::fix_prepare_informat if (!thd->stmt_arena->is_conventional() && first_execution) { first_execution= 0; + if (group_list.first) + { + if (!group_list_ptrs) + { + void *mem= thd->stmt_arena->alloc(sizeof(Group_list_ptrs)); + group_list_ptrs= new (mem) Group_list_ptrs(thd->stmt_arena->mem_root); + } + group_list_ptrs->reserve(group_list.elements); + for (ORDER *order= group_list.first; order; order= order->next) + { + group_list_ptrs->push_back(order); + } + } if (*conds) { prep_where= *conds; === modified file 'sql/sql_lex.h' --- a/sql/sql_lex.h 2011-05-12 17:29:19 +0000 +++ b/sql/sql_lex.h 2011-06-10 09:52:57 +0000 @@ -24,6 +24,7 @@ #include "sql_trigger.h" #include "item.h" /* From item_subselect.h: subselect_union_engine */ #include "thr_lock.h" /* thr_lock_type, TL_UNLOCK */ +#include "mem_root_array.h" /* YACC and LEX Definitions */ @@ -185,6 +186,7 @@ enum enum_drop_mode #define TL_OPTION_ALIAS 8 typedef List List_item; +typedef Mem_root_array Group_list_ptrs; /* SERVERS CACHE CHANGES */ typedef struct st_lex_server_options @@ -628,7 +630,16 @@ public: enum olap_type olap; /* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */ SQL_I_List table_list; - SQL_I_List group_list; /* GROUP BY clause. */ + + /* + GROUP BY clause. + This list may be mutated during optimization (by remove_const()), + so for prepared statements, we keep a copy of the ORDER.next pointers in + group_list_ptrs, and re-establish the original list before each execution. + */ + SQL_I_List group_list; + Group_list_ptrs *group_list_ptrs; + List item_list; /* list of fields & expressions */ List interval_list; bool is_item_list_lookup; @@ -819,7 +830,8 @@ public: bool test_limit(); friend void lex_start(THD *thd); - st_select_lex() : n_sum_items(0), n_child_sum_items(0) {} + st_select_lex() : group_list_ptrs(NULL), n_sum_items(0), n_child_sum_items(0) + {} void make_empty_select() { init_query(); === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2011-06-10 07:49:17 +0000 +++ b/sql/sql_prepare.cc 2011-06-10 09:52:57 +0000 @@ -2428,6 +2428,14 @@ void reinit_stmt_before_use(THD *thd, LE DBUG_ASSERT(sl->join == 0); ORDER *order; /* Fix GROUP list */ + if (sl->group_list_ptrs && sl->group_list_ptrs->size() > 0) + { + for (uint ix= 0; ix < sl->group_list_ptrs->size() - 1; ++ix) + { + order= sl->group_list_ptrs->at(ix); + order->next= sl->group_list_ptrs->at(ix+1); + } + } for (order= sl->group_list.first; order; order= order->next) order->item= &order->item_ptr; /* Fix ORDER list */ No bundle (reason: useless for push emails).