List:Commits« Previous MessageNext Message »
From:Roy Lyseng Date:May 7 2010 12:17pm
Subject:bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3148) Bug#50089
View as plain text  
#At file:///home/rl136806/mysql/repo/mysql-next-mr-opt-backporting/ based on revid:olav@stripped

 3148 Roy Lyseng	2010-05-07
      Bug#50089: Second call of procedure with view in subselect crashes server
            
      The bug case contains a query that references a view.
      Here is the view definition:
            
      SELECT t1field AS v1_field
      FROM t1 AS A
      WHERE A.t1field IN (SELECT t1field FROM t1);
            
      When expanding the view at prepare time, this select_lex graph is created:
            
       VS1(A)
         \
          VS2(t1)
            
      This is the query that is executed:
            
      SELECT t1field FROM t1
      WHERE t1field IN (SELECT * FROM v1);
            
      At prepare time, the query is conceptually expanded to the following query:
            
      SELECT t1field FROM t1
      WHERE t1field IN (SELECT t1field AS v1_field
                        FROM t1 AS A
                        WHERE A.t1field IN (SELECT t1field FROM t1));
            
      Here is the select_lex graph after view expansion:
            
       S1(t1)
         \
          S2(A)
            \
             VS2(t1)
            
      The contents of select_lex VS1 is merged with the query graph and VS1
      is discarded after merging.
            
      At first execution, semijoin conversion is performed, and the query is
      transformed to:
            
      SELECT t1_field FROM t1 semijoin t1 AS A
                           ON t1.t1_field = A.t1_field
      WHERE A.t1_field IN (SELECT t1_field FROM t1));
            
      Now, the select_lex object S2 is optimized away and the table A is added to S1.
      Here is the select_lex graph after transformation:
            
       S1(t1)
         \
          VS2(t1)
            
      The master field of VS2 points to S1 after conversion.
      However, the return_to field of VS2 still points to VS1.
            
      First execution proceeds normally after this.
            
      At second execution, all items in the transformed query are first re-resolved. 
      When re-resolving A.t1_field, function mark_select_range_as_dependent()
      is called with VS1 as current_sel and S1 as last_select arguments.
      Now, the master unit of VS1 does not have an "item", and we segfault.
            
      Problem occurs when mark_select_range_as_dependent() is called with two
      select_lex pointers that point into different query trees, one tree being
      the main query tree, the other being the tree representing the view.
                  
      This problem is due to the fact that the function return_after_parsing() is
      used to provide pointer to the select_lex object representing the outer
      query specification of a subquery. However, the return_to field was not
      properly updated in all situations. But it was also noticed that
      outer_select() gives the same information as return_after_parsing(),
      and the data used by this function is always kept up-to-date.
                  
      The bug was thus fixed by removing return_after_parsing() and associated data,
      and replacing calls with outer_select().
            
      Notice also that queries within procedures internally create
      prepared statements, so the solution works equally well for procedures
      as well as for prepared statements.
                  
      mysql-test/r/subselect_sj.result
        Test result for Bug#50089
      mysql-test/r/subselect_sj_jcl6.result
        Test result for Bug#50089
      mysql-test/t/subselect_sj.test
        Test case for Bug#50089
      sql/item_subselect.cc
        Replaced references to return_after_parsing() with outer_select().
      sql/sql_lex.cc
        Removed function return_after_parsing() and data field return_to.
      sql/sql_lex.h
        Removed function return_after_parsing() and data field return_to.
      sql/sql_parse.cc
        Replaced reference to return_after_parsing() with outer_select().
      sql/sql_select.cc
        Replaced reference to return_after_parsing() with outer_select().
      sql/sql_yacc.yy
        Replaced reference to return_after_parsing() with outer_select().
      
      revid:marc.alff@stripped@sun.com-20100310111425-7r30qg17f5z13ptd

    modified:
      mysql-test/r/subselect_sj.result
      mysql-test/r/subselect_sj_jcl6.result
      mysql-test/t/subselect_sj.test
      sql/item_subselect.cc
      sql/sql_lex.cc
      sql/sql_lex.h
      sql/sql_parse.cc
      sql/sql_select.cc
      sql/sql_yacc.yy
=== modified file 'mysql-test/r/subselect_sj.result'
--- a/mysql-test/r/subselect_sj.result	2010-05-07 11:31:49 +0000
+++ b/mysql-test/r/subselect_sj.result	2010-05-07 12:17:07 +0000
@@ -1221,3 +1221,58 @@ id	select_type	table	type	possible_keys	
 1	PRIMARY	it2	ALL	NULL	NULL	NULL	NULL	20	Using where; End temporary
 DROP TABLE ot1, it1, it2;
 # End of BUG#38075
+# 
+# BUG#50089: Second call of procedure with view in subselect crashes server
+# 
+CREATE TABLE t1(t1field INTEGER, PRIMARY KEY(t1field));
+CREATE VIEW v1 AS 
+SELECT t1field AS v1field
+FROM t1 A 
+WHERE A.t1field IN (SELECT t1field FROM t1);
+INSERT INTO t1 VALUES(1),(2);
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+t1field
+1
+2
+EXPLAIN
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	index	PRIMARY	PRIMARY	4	NULL	2	Using where; Using index
+1	PRIMARY	A	eq_ref	PRIMARY	PRIMARY	4	test.t1.t1field	1	Using index
+4	DEPENDENT SUBQUERY	t1	unique_subquery	PRIMARY	PRIMARY	4	func	1	Using index
+CREATE PROCEDURE p1() 
+BEGIN 
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+END|
+CALL p1;
+t1field
+1
+2
+CALL p1;
+t1field
+1
+2
+PREPARE stmt FROM
+"
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+";
+EXECUTE stmt;
+t1field
+1
+2
+EXECUTE stmt;
+t1field
+1
+2
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
+# End of BUG#50089

=== modified file 'mysql-test/r/subselect_sj_jcl6.result'
--- a/mysql-test/r/subselect_sj_jcl6.result	2010-05-07 11:31:49 +0000
+++ b/mysql-test/r/subselect_sj_jcl6.result	2010-05-07 12:17:07 +0000
@@ -1225,6 +1225,61 @@ id	select_type	table	type	possible_keys	
 1	PRIMARY	it2	ALL	NULL	NULL	NULL	NULL	20	Using where; End temporary; Using join buffer
 DROP TABLE ot1, it1, it2;
 # End of BUG#38075
+# 
+# BUG#50089: Second call of procedure with view in subselect crashes server
+# 
+CREATE TABLE t1(t1field INTEGER, PRIMARY KEY(t1field));
+CREATE VIEW v1 AS 
+SELECT t1field AS v1field
+FROM t1 A 
+WHERE A.t1field IN (SELECT t1field FROM t1);
+INSERT INTO t1 VALUES(1),(2);
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+t1field
+1
+2
+EXPLAIN
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	index	PRIMARY	PRIMARY	4	NULL	2	Using where; Using index
+1	PRIMARY	A	eq_ref	PRIMARY	PRIMARY	4	test.t1.t1field	1	Using index
+4	DEPENDENT SUBQUERY	t1	unique_subquery	PRIMARY	PRIMARY	4	func	1	Using index
+CREATE PROCEDURE p1() 
+BEGIN 
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+END|
+CALL p1;
+t1field
+1
+2
+CALL p1;
+t1field
+1
+2
+PREPARE stmt FROM
+"
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+";
+EXECUTE stmt;
+t1field
+1
+2
+EXECUTE stmt;
+t1field
+1
+2
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
+# End of BUG#50089
 set join_cache_level=default;
 show variables like 'join_cache_level';
 Variable_name	Value

=== modified file 'mysql-test/t/subselect_sj.test'
--- a/mysql-test/t/subselect_sj.test	2010-05-07 11:31:49 +0000
+++ b/mysql-test/t/subselect_sj.test	2010-05-07 12:17:07 +0000
@@ -900,3 +900,53 @@ WHERE int_nokey IN (SELECT it2.int_key
 DROP TABLE ot1, it1, it2;
 
 --echo # End of BUG#38075
+
+--echo # 
+--echo # BUG#50089: Second call of procedure with view in subselect crashes server
+--echo # 
+
+CREATE TABLE t1(t1field INTEGER, PRIMARY KEY(t1field));
+
+CREATE VIEW v1 AS 
+  SELECT t1field AS v1field
+  FROM t1 A 
+  WHERE A.t1field IN (SELECT t1field FROM t1);
+
+INSERT INTO t1 VALUES(1),(2);
+
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+
+EXPLAIN
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+
+delimiter |;
+CREATE PROCEDURE p1() 
+  BEGIN 
+    SELECT t1field
+    FROM t1
+    WHERE t1field IN (SELECT v1field FROM v1);
+  END|
+delimiter ;|
+
+CALL p1;
+CALL p1;
+
+PREPARE stmt FROM
+"
+SELECT t1field
+FROM t1
+WHERE t1field IN (SELECT v1field FROM v1);
+";
+
+EXECUTE stmt;
+EXECUTE stmt;
+
+DROP PROCEDURE p1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+--echo # End of BUG#50089

=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc	2010-05-02 19:14:50 +0000
+++ b/sql/item_subselect.cc	2010-05-07 12:17:07 +0000
@@ -1104,9 +1104,9 @@ Item_in_subselect::single_value_transfor
     SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
     substitution= optimizer;
 
-    SELECT_LEX *current= thd->lex->current_select, *up;
+    SELECT_LEX *current= thd->lex->current_select;
 
-    thd->lex->current_select= up= current->return_after_parsing();
+    thd->lex->current_select= current->outer_select();
     //optimizer never use Item **ref => we can pass 0 as parameter
     if (!optimizer || optimizer->fix_left(thd, 0))
     {
@@ -1391,8 +1391,8 @@ Item_in_subselect::row_value_transformer
     SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
     substitution= optimizer;
 
-    SELECT_LEX *current= thd->lex->current_select, *up;
-    thd->lex->current_select= up= current->return_after_parsing();
+    SELECT_LEX *current= thd->lex->current_select;
+    thd->lex->current_select= current->outer_select();
     //optimizer never use Item **ref => we can pass 0 as parameter
     if (!optimizer || optimizer->fix_left(thd, 0))
     {
@@ -1722,7 +1722,7 @@ Item_in_subselect::select_in_like_transf
       goto err;
   }
 
-  thd->lex->current_select= up= current->return_after_parsing();
+  thd->lex->current_select= current->outer_select();
   result= (!left_expr->fixed &&
            left_expr->fix_fields(thd, optimizer->arguments()));
   /* fix_fields can change reference to left_expr, we need reassign it */

=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc	2010-04-16 09:07:23 +0000
+++ b/sql/sql_lex.cc	2010-05-07 12:17:07 +0000
@@ -327,8 +327,7 @@ void lex_start(THD *thd)
   lex->view_list.empty();
   lex->prepared_stmt_params.empty();
   lex->auxiliary_table_list.empty();
-  lex->unit.next= lex->unit.master=
-    lex->unit.link_next= lex->unit.return_to= 0;
+  lex->unit.next= lex->unit.master= lex->unit.link_next= 0;
   lex->unit.prev= lex->unit.link_prev= 0;
   lex->unit.slave= lex->unit.global_parameters= lex->current_select=
     lex->all_selects_list= &lex->select_lex;

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2010-04-16 09:07:23 +0000
+++ b/sql/sql_lex.h	2010-05-07 12:17:07 +0000
@@ -399,7 +399,6 @@ public:
 
   virtual st_select_lex_unit* master_unit()= 0;
   virtual st_select_lex* outer_select()= 0;
-  virtual st_select_lex* return_after_parsing()= 0;
 
   virtual bool set_braces(bool value);
   virtual bool inc_in_sum_expr();
@@ -478,8 +477,6 @@ public:
     global parameters for union
   */
   st_select_lex *global_parameters;
-  //node on wich we should return current_select pointer after parsing subquery
-  st_select_lex *return_to;
   /* LIMIT clause runtime counters */
   ha_rows select_limit_cnt, offset_limit_cnt;
   /* not NULL if unit used in subselect, point to subselect item */
@@ -507,7 +504,6 @@ public:
   {
     return my_reinterpret_cast(st_select_lex_unit*)(next);
   }
-  st_select_lex* return_after_parsing() { return return_to; }
   void exclude_level();
   void exclude_tree();
 
@@ -702,11 +698,6 @@ public:
   {
     return &link_next;
   }
-  st_select_lex* return_after_parsing()
-  {
-    return master_unit()->return_after_parsing();
-  }
-
   void mark_as_dependent(st_select_lex *last);
 
   bool set_braces(bool value);

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-04-16 09:07:23 +0000
+++ b/sql/sql_parse.cc	2010-05-07 12:17:07 +0000
@@ -5559,7 +5559,6 @@ mysql_new_select(LEX *lex, bool move_dow
     unit->include_down(lex->current_select);
     unit->link_next= 0;
     unit->link_prev= 0;
-    unit->return_to= lex->current_select;
     select_lex->include_down(unit);
     /*
       By default we assume that it is usual subselect and we have outer name

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2010-05-07 11:31:49 +0000
+++ b/sql/sql_select.cc	2010-05-07 12:17:07 +0000
@@ -619,7 +619,7 @@ JOIN::prepare(Item ***rref_pointer_array
       }
 
       SELECT_LEX *current= thd->lex->current_select;
-      thd->lex->current_select= current->return_after_parsing();
+      thd->lex->current_select= current->outer_select();
       char const *save_where= thd->where;
       thd->where= "IN/ALL/ANY subquery";
         

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2010-04-16 09:07:23 +0000
+++ b/sql/sql_yacc.yy	2010-05-07 12:17:07 +0000
@@ -13723,7 +13723,7 @@ subselect_end:
 
             lex->pop_context();
             SELECT_LEX *child= lex->current_select;
-            lex->current_select = lex->current_select->return_after_parsing();
+            lex->current_select = lex->current_select->outer_select();
             lex->nest_level--;
             lex->current_select->n_child_sum_items += child->n_sum_items;
             /*


Attachment: [text/bzr-bundle] bzr/roy.lyseng@sun.com-20100507121707-4rodtuem07qn03mi.bundle
Thread
bzr commit into mysql-next-mr-bugfixing branch (roy.lyseng:3148) Bug#50089Roy Lyseng7 May