diff options
author | unknown <timour@askmonty.org> | 2011-04-28 17:15:05 +0300 |
---|---|---|
committer | unknown <timour@askmonty.org> | 2011-04-28 17:15:05 +0300 |
commit | 0f4236659c2af3720d57255e224b3a8bb4f1d697 (patch) | |
tree | 1dfb7d1a272788e17bda823cacfb4061cc03f659 /mysql-test/t/subselect4.test | |
parent | 9d20163536dcb5a66411e33cf9f9d3e68c76fe6e (diff) | |
download | mariadb-git-0f4236659c2af3720d57255e224b3a8bb4f1d697.tar.gz |
Fix LP BUG#718593
Analysis:
Build_equal_items_for_cond() rewrites the WHERE clause in such a way,
that it may merge the list join->cond_equal->current_level with the
list of child Items in an AND condition of the WHERE clause.
The place where this is done is:
static COND *build_equal_items_for_cond(THD *thd, COND *cond,
COND_EQUAL *inherited)
{
...
if (and_level)
{
args->concat(&eq_list);
args->concat((List<Item> *)&cond_equal.current_level);
}
...
}
As a result, later transformations on the WHERE clause may change the
structure of the list join->cond_equal->current_level without knowing this.
Specifically in this bug, Item_in_subselect::inject_in_to_exists_cond
creates a new AND of the old WHERE clause and the IN->EXISTS conditions.
It then calls fix_fields() for the new AND. Among other things, fix_fields
flattens all nested ANDs into one by merging the AND argument lists.
When there is a cond_equal for the JOIN, its list of Item_equal objects
is attached to the end of the original AND. When a lower-level AND is
merged into the top-level one, the argument list of the lower-level AND
is concatenated to the list of multiple equalities in the upper-level AND.
As a result, when substitute_for_best_equal_field processes the
multiple equalities, it turns out that the multiple equality list contains
the Items from the lower-level AND which were concatenated to the end of
the join->cond_equal->current_level list. This results in a crash because
this list must not contain any other Items except for the previously found
Item_equal ones.
Solution:
When performing IN->EXIST predicate injection, and the where clause is an
AND, detach the list of Item_equal objects before calling fix_fields on
the injected where clause.
After fix_fields is done, reattach back the multiple equalities list to
the end of the argument list of the new AND.
Diffstat (limited to 'mysql-test/t/subselect4.test')
-rw-r--r-- | mysql-test/t/subselect4.test | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index 051375c43ef..4b262a070cc 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -1327,3 +1327,46 @@ SELECT * FROM t2 WHERE (f1b) IN (SELECT f1a FROM t1 GROUP BY f1a, f2a); set @@optimizer_switch=@save_optimizer_switch; drop table t0,t1,t2; + +--echo # +--echo # LP BUG#718593 Crash in substitute_for_best_equal_field -> eliminate_item_equal -> +--echo # Item_field::find_item_equal -> Item_equal::contains +--echo # + +set @save_optimizer_switch=@@optimizer_switch; +SET @@optimizer_switch = 'semijoin=off'; + +CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ; +INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d'); + +CREATE TABLE t2 ( f12 int(11), f13 int(11)) ; +insert into t2 values (1,2), (3,4); + +EXPLAIN +SELECT * FROM t2 +WHERE ( f12 ) IN ( + SELECT alias2.f3 + FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11 + WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10 +); +SELECT * FROM t2 +WHERE ( f12 ) IN ( + SELECT alias2.f3 + FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11 + WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10 +); + +EXPLAIN +SELECT * FROM t2 +WHERE ( f12 ) IN ( + SELECT alias2.f3 + FROM t1 AS alias1, t1 AS alias2 + WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10)); +SELECT * FROM t2 +WHERE ( f12 ) IN ( + SELECT alias2.f3 + FROM t1 AS alias1, t1 AS alias2 + WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10)); + +set @@optimizer_switch=@save_optimizer_switch; +drop table t1, t2; |