List:Commits« Previous MessageNext Message »
From:mhansson Date:February 21 2008 10:27am
Subject:bk commit into 6.0 tree (mhansson:1.2767) BUG#33062
View as plain text  
Below is the list of changes that have just been committed into a local
6.0 repository of martin. When martin does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2008-02-21 11:26:58+01:00, mhansson@stripped +5 -0
  Bug#33062: subquery in stored routine cause crash
  
  Subquery flattening maintained a pointer into the list structure
  representing a WHERE clause, which introduces a dependency on this
  structure not changing. This caused crashes in stored procedures.
  Fixed by doing a lookup in the list instead instead of relying on
  a pointer.

  mysql-test/r/subselect_sj2.result@stripped, 2008-02-21 11:26:54+01:00, mhansson@stripped +55 -0
    Bug#33062: Test result

  mysql-test/t/subselect_sj2.test@stripped, 2008-02-21 11:26:54+01:00, mhansson@stripped +66 -0
    Bug#33062: Test case

  sql/item_subselect.cc@stripped, 2008-02-21 11:26:55+01:00, mhansson@stripped +0 -1
    Bug#33062: Removed pointer.

  sql/item_subselect.h@stripped, 2008-02-21 11:26:55+01:00, mhansson@stripped +0 -1
    Bug#33062: Removed pointer.

  sql/sql_select.cc@stripped, 2008-02-21 11:26:55+01:00, mhansson@stripped +51 -5
    Bug#33062: Corrected comment. Added call to new function instead of 
    using ref_ptr.

diff -Nrup a/mysql-test/r/subselect_sj2.result b/mysql-test/r/subselect_sj2.result
--- a/mysql-test/r/subselect_sj2.result	2007-12-01 22:54:37 +01:00
+++ b/mysql-test/r/subselect_sj2.result	2008-02-21 11:26:54 +01:00
@@ -351,3 +351,58 @@ Canada
 China
 Czech Republic
 drop table t1, t2;
+CREATE TABLE t1(a INT);
+CREATE TABLE t2(c INT);
+CREATE PROCEDURE p1(v1 int)
+BEGIN
+SELECT 1 FROM t1 WHERE a = v1 AND a IN (SELECT c FROM t2);
+END
+//
+CREATE PROCEDURE p2(v1 int)
+BEGIN
+SELECT 1 FROM t1 WHERE a IN (SELECT c FROM t2);
+END
+//
+CREATE PROCEDURE p3(v1 int)
+BEGIN
+SELECT 1 
+FROM 
+t1 t01,t1 t02,t1 t03,t1 t04,t1 t05,t1 t06,t1 t07,t1 t08,
+t1 t09,t1 t10,t1 t11,t1 t12,t1 t13,t1 t14,t1 t15,t1 t16,
+t1 t17,t1 t18,t1 t19,t1 t20,t1 t21,t1 t22,t1 t23,t1 t24,
+t1 t25,t1 t26,t1 t27,t1 t28,t1 t29,t1 t30,t1 t31,t1 t32,
+t1 t33,t1 t34,t1 t35,t1 t36,t1 t37,t1 t38,t1 t39,t1 t40,
+t1 t41,t1 t42,t1 t43,t1 t44,t1 t45,t1 t46,t1 t47,t1 t48,
+t1 t49,t1 t50,t1 t51,t1 t52,t1 t53,t1 t54,t1 t55,t1 t56,
+t1 t57,t1 t58,t1 t59,t1 t60
+WHERE t01.a IN (SELECT c FROM t2);
+END
+//
+CREATE PROCEDURE p4(v1 int)
+BEGIN
+SELECT 1 
+FROM 
+t1 t01,t1 t02,t1 t03,t1 t04,t1 t05,t1 t06,t1 t07,t1 t08,
+t1 t09,t1 t10,t1 t11,t1 t12,t1 t13,t1 t14,t1 t15,t1 t16,
+t1 t17,t1 t18,t1 t19,t1 t20,t1 t21,t1 t22,t1 t23,t1 t24,
+t1 t25,t1 t26,t1 t27,t1 t28,t1 t29,t1 t30,t1 t31,t1 t32,
+t1 t33,t1 t34,t1 t35,t1 t36,t1 t37,t1 t38,t1 t39,t1 t40,
+t1 t41,t1 t42,t1 t43,t1 t44,t1 t45,t1 t46,t1 t47,t1 t48,
+t1 t49,t1 t50,t1 t51,t1 t52,t1 t53,t1 t54,t1 t55,t1 t56,
+t1 t57,t1 t58,t1 t59,t1 t60
+WHERE t01.a = v1 AND t01.a IN (SELECT c FROM t2);
+END
+//
+CALL p1(1);
+1
+CALL p2(1);
+1
+CALL p3(1);
+1
+CALL p4(1);
+1
+DROP TABLE t1, t2;
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+DROP PROCEDURE p4;
diff -Nrup a/mysql-test/t/subselect_sj2.test b/mysql-test/t/subselect_sj2.test
--- a/mysql-test/t/subselect_sj2.test	2007-09-26 13:49:29 +02:00
+++ b/mysql-test/t/subselect_sj2.test	2008-02-21 11:26:54 +01:00
@@ -480,3 +480,69 @@ SELECT Name FROM t1 
     SELECT t2.CountryCode FROM t2 WHERE Population > 5000000);
 
 drop table t1, t2;
+
+#
+# Bug#33062: subquery in stored routine cause crash
+#
+
+CREATE TABLE t1(a INT);
+CREATE TABLE t2(c INT);
+
+DELIMITER //;
+
+CREATE PROCEDURE p1(v1 int)
+BEGIN
+  SELECT 1 FROM t1 WHERE a = v1 AND a IN (SELECT c FROM t2);
+END
+//
+
+CREATE PROCEDURE p2(v1 int)
+BEGIN
+  SELECT 1 FROM t1 WHERE a IN (SELECT c FROM t2);
+END
+//
+
+CREATE PROCEDURE p3(v1 int)
+BEGIN
+  SELECT 1 
+  FROM 
+    t1 t01,t1 t02,t1 t03,t1 t04,t1 t05,t1 t06,t1 t07,t1 t08,
+    t1 t09,t1 t10,t1 t11,t1 t12,t1 t13,t1 t14,t1 t15,t1 t16,
+    t1 t17,t1 t18,t1 t19,t1 t20,t1 t21,t1 t22,t1 t23,t1 t24,
+    t1 t25,t1 t26,t1 t27,t1 t28,t1 t29,t1 t30,t1 t31,t1 t32,
+    t1 t33,t1 t34,t1 t35,t1 t36,t1 t37,t1 t38,t1 t39,t1 t40,
+    t1 t41,t1 t42,t1 t43,t1 t44,t1 t45,t1 t46,t1 t47,t1 t48,
+    t1 t49,t1 t50,t1 t51,t1 t52,t1 t53,t1 t54,t1 t55,t1 t56,
+    t1 t57,t1 t58,t1 t59,t1 t60
+  WHERE t01.a IN (SELECT c FROM t2);
+END
+//
+
+CREATE PROCEDURE p4(v1 int)
+BEGIN
+  SELECT 1 
+  FROM 
+    t1 t01,t1 t02,t1 t03,t1 t04,t1 t05,t1 t06,t1 t07,t1 t08,
+    t1 t09,t1 t10,t1 t11,t1 t12,t1 t13,t1 t14,t1 t15,t1 t16,
+    t1 t17,t1 t18,t1 t19,t1 t20,t1 t21,t1 t22,t1 t23,t1 t24,
+    t1 t25,t1 t26,t1 t27,t1 t28,t1 t29,t1 t30,t1 t31,t1 t32,
+    t1 t33,t1 t34,t1 t35,t1 t36,t1 t37,t1 t38,t1 t39,t1 t40,
+    t1 t41,t1 t42,t1 t43,t1 t44,t1 t45,t1 t46,t1 t47,t1 t48,
+    t1 t49,t1 t50,t1 t51,t1 t52,t1 t53,t1 t54,t1 t55,t1 t56,
+    t1 t57,t1 t58,t1 t59,t1 t60
+  WHERE t01.a = v1 AND t01.a IN (SELECT c FROM t2);
+END
+//
+
+DELIMITER ;//
+
+CALL p1(1);
+CALL p2(1);
+CALL p3(1);
+CALL p4(1);
+
+DROP TABLE t1, t2;
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+DROP PROCEDURE p4;
diff -Nrup a/sql/item_subselect.cc b/sql/item_subselect.cc
--- a/sql/item_subselect.cc	2007-11-23 12:41:55 +01:00
+++ b/sql/item_subselect.cc	2008-02-21 11:26:55 +01:00
@@ -1709,7 +1709,6 @@ void Item_in_subselect::print(String *st
 bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
 {
   bool result = 0;
-  ref_ptr= ref;
 
   if (exec_method == SEMI_JOIN)
     return !( (*ref)= new Item_int(1));
diff -Nrup a/sql/item_subselect.h b/sql/item_subselect.h
--- a/sql/item_subselect.h	2007-10-30 15:25:47 +01:00
+++ b/sql/item_subselect.h	2008-02-21 11:26:55 +01:00
@@ -295,7 +295,6 @@ public:
      - (TABLE_LIST*)1 if the predicate is in the WHERE.
   */
   TABLE_LIST *expr_join_nest;
-  Item **ref_ptr;
 
   /* The method chosen to execute the IN predicate.  */
   enum enum_exec_method {
diff -Nrup a/sql/sql_select.cc b/sql/sql_select.cc
--- a/sql/sql_select.cc	2007-12-13 13:56:21 +01:00
+++ b/sql/sql_select.cc	2008-02-21 11:26:55 +01:00
@@ -229,6 +229,8 @@ void select_describe(JOIN *join, bool ne
 static Item *remove_additional_cond(Item* conds);
 static void add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab);
 static bool test_if_ref(Item_field *left_item,Item *right_item);
+static bool replace_where_subcondition(JOIN *join, Item *old_cond, 
+                                       Item *new_cond, bool fix_fields);
 
 /*
   This is used to mark equalities that were made from i-th IN-equality.
@@ -3333,14 +3335,15 @@ bool JOIN::flatten_subqueries()
   */
   sj_subselects.sort(subq_sj_candidate_cmp);
   // #tables-in-parent-query + #tables-in-subquery < MAX_TABLES
-  /* Replace all subqueries to be flattened for Item_int(1) */
+  /* Replace all subqueries to be flattened with Item_int(1) */
   arena= thd->activate_stmt_arena_if_needed(&backup);
   for (in_subq= sj_subselects.front(); 
        in_subq != in_subq_end && 
        tables + ((*in_subq)->sj_convert_priority % MAX_TABLES) < MAX_TABLES;
        in_subq++)
   {
-    *((*in_subq)->ref_ptr)= new Item_int(1);
+    if (replace_where_subcondition(this, *in_subq, new Item_int(1), FALSE))
+      DBUG_RETURN(TRUE);
   }
  
   for (in_subq= sj_subselects.front(); 
@@ -3365,11 +3368,12 @@ bool JOIN::flatten_subqueries()
     if (res == Item_subselect::RES_ERROR)
       DBUG_RETURN(TRUE);
 
-    *((*in_subq)->ref_ptr)= (*in_subq)->substitution;
     (*in_subq)->changed= 1;
     (*in_subq)->fixed= 1;
-    if (!(*in_subq)->substitution->fixed &&
-      (*in_subq)->substitution->fix_fields(thd, (*in_subq)->ref_ptr))
+
+    Item *substitute= (*in_subq)->substitution;
+    bool do_fix_fields= !(*in_subq)->substitution->fixed;
+    if (replace_where_subcondition(this, *in_subq, substitute, do_fix_fields))
       DBUG_RETURN(TRUE);
 
     //if ((*in_subq)->fix_fields(thd, (*in_subq)->ref_ptr))
@@ -14830,6 +14834,48 @@ static bool test_if_ref(Item_field *left
   return 0;					// keep test
 }
 
+/**
+   @brief Replaces an expression destructively inside the expression tree of
+   the WHERE clase.
+
+   @note Because of current requirements for semijoin flattening, we do not
+   need to recurse here, hence this function will only examine the top-level
+   AND conditions. (see JOIN::prepare, comment above the line 
+   'if (do_materialize)'
+   
+   @param join The top-level query.
+   @param old_cond The expression to be replaced.
+   @param new_cond The expression to be substituted.
+   @param do_fix_fields If true, Item::fix_fields(THD*, Item**) is called for
+   the new expression.
+   @return <code>true</code> if there was an error, <code>false</code> if
+   successful.
+*/
+static bool replace_where_subcondition(JOIN *join, Item *old_cond, 
+                                       Item *new_cond, bool do_fix_fields)
+{
+  if (join->conds == old_cond) {
+    join->conds= new_cond;
+    if (do_fix_fields)
+      new_cond->fix_fields(join->thd, &join->conds);
+    return FALSE;
+  }
+  
+  if (join->conds->type() == Item::COND_ITEM) {
+    List_iterator<Item> li(*((Item_cond*)join->conds)->argument_list());
+    Item *item;
+    while ((item= li++))
+      if (item == old_cond) 
+      {
+        li.replace(new_cond);
+        if (do_fix_fields)
+          new_cond->fix_fields(join->thd, li.ref());
+        return FALSE;
+      }
+  }
+
+  return TRUE;
+}
 
 /*
   Extract a condition that can be checked after reading given table
Thread
bk commit into 6.0 tree (mhansson:1.2767) BUG#33062mhansson21 Feb