summaryrefslogtreecommitdiff
path: root/mysql-test/t/subselect4.test
diff options
context:
space:
mode:
authorunknown <timour@askmonty.org>2011-04-28 17:15:05 +0300
committerunknown <timour@askmonty.org>2011-04-28 17:15:05 +0300
commit0f4236659c2af3720d57255e224b3a8bb4f1d697 (patch)
tree1dfb7d1a272788e17bda823cacfb4061cc03f659 /mysql-test/t/subselect4.test
parent9d20163536dcb5a66411e33cf9f9d3e68c76fe6e (diff)
downloadmariadb-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.test43
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;