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#33062 | mhansson | 21 Feb |