List:Commits« Previous MessageNext Message »
From:Tor Didriksen Date:June 10 2011 9:53am
Subject:bzr commit into mysql-trunk branch (tor.didriksen:3185) Bug#11766429
View as plain text  
#At file:///export/home/didrik/repo/trunk-bug11766429-prep-having/ based on revid:alexander.nozdrin@stripped

 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
=== 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<Item> List_item;
+typedef Mem_root_array<ORDER*, true> 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>  table_list;
-  SQL_I_List<ORDER>       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<ORDER>       group_list;
+  Group_list_ptrs        *group_list_ptrs;
+
   List<Item>          item_list;  /* list of fields & expressions */
   List<String>        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 */


Attachment: [text/bzr-bundle] bzr/tor.didriksen@oracle.com-20110610095257-ulh6hd2evlxkkx6d.bundle
Thread
bzr commit into mysql-trunk branch (tor.didriksen:3185) Bug#11766429Tor Didriksen10 Jun