3870 Guilhem Bichot 2012-02-09 [merge]
merge from trunk
modified:
mysql-test/r/events_restart.result
mysql-test/t/events_restart.test
sql/events.cc
=== modified file 'mysql-test/include/icp_tests.inc'
--- a/mysql-test/include/icp_tests.inc 2012-02-01 09:59:13 +0000
+++ b/mysql-test/include/icp_tests.inc 2012-02-08 15:25:17 +0000
@@ -862,6 +862,15 @@ CREATE TABLE t2 (
INSERT INTO t2 VALUES (1,7,'f');
+# Bug was specific of IN->EXISTS:
+set @old_opt_switch=@@optimizer_switch;
+--disable_query_log
+if (`select locate('materialization', @@optimizer_switch) > 0`)
+{
+ set optimizer_switch='materialization=off';
+}
+--enable_query_log
+
let query=
SELECT t1.i1
FROM t1
@@ -877,6 +886,7 @@ WHERE t1.i1 NOT IN
eval EXPLAIN $query;
eval $query;
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1,t2;
--echo #
@@ -909,6 +919,15 @@ CREATE TABLE t3 (
INSERT INTO t3 VALUES (NULL,'w'), (1,NULL), (2,'d');
+# Bug was specific of IN->EXISTS:
+set @old_opt_switch=@@optimizer_switch;
+--disable_query_log
+if (`select locate('materialization', @@optimizer_switch) > 0`)
+{
+ set optimizer_switch='materialization=off';
+}
+--enable_query_log
+
let query=
SELECT i1
FROM t3
@@ -923,6 +942,7 @@ WHERE c1 IN
eval EXPLAIN $query;
eval $query;
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
--echo #
=== modified file 'mysql-test/include/join_cache.inc'
--- a/mysql-test/include/join_cache.inc 2012-01-26 15:42:39 +0000
+++ b/mysql-test/include/join_cache.inc 2012-02-08 15:25:17 +0000
@@ -1713,6 +1713,15 @@ CREATE TABLE t3 (
INSERT INTO t3 VALUES (NULL), (NULL);
+# Bug was specific of IN->EXISTS:
+set @old_opt_switch=@@optimizer_switch;
+--disable_query_log
+if (`select locate('materialization', @@optimizer_switch) > 0`)
+{
+ set optimizer_switch='materialization=off';
+}
+--enable_query_log
+
--echo
let query_in=
@@ -1752,6 +1761,7 @@ eval $query_in_toplevel;
--echo
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
set @@join_buffer_size=default;
=== modified file 'mysql-test/include/subquery.inc'
--- a/mysql-test/include/subquery.inc 2012-02-07 14:50:31 +0000
+++ b/mysql-test/include/subquery.inc 2012-02-08 15:25:17 +0000
@@ -3223,7 +3223,7 @@ INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
---echo # should have eq_ref for t1
+--echo # should have eq_ref for t1, unless subquery materialization is used
--replace_column 1 x 2 x 5 x 6 x 7 x 8 x 9 x 10 x
EXPLAIN
SELECT * FROM t2 outr
@@ -5804,3 +5804,21 @@ eval EXPLAIN SELECT * FROM ( $subq ) AS
eval SELECT * FROM ( $subq ) AS alias3;
DROP TABLE t1,t2;
+
+--echo #
+--echo # Test that indexsubquery_engine only does one lookup if
+--echo # the technique is unique_subquery: does not try to read the
+--echo # next row if the first row failed the subquery's WHERE
+--echo # condition (here: b=3).
+--echo #
+
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+let $query=select * from t1 where a in (select a from t2 where b=3);
+eval explain $query;
+flush status;
+eval $query;
+show status like "handler_read%";
+drop table t1,t2;
=== modified file 'mysql-test/include/subquery_mat.inc'
--- a/mysql-test/include/subquery_mat.inc 2012-01-20 09:07:08 +0000
+++ b/mysql-test/include/subquery_mat.inc 2012-02-08 15:25:17 +0000
@@ -910,7 +910,6 @@ DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
-
--echo #
--echo # Bug#13419028 - SUBQUERY MATERIALIZATION NOT USED IN CREATE
--echo # SELECT
@@ -1022,4 +1021,326 @@ DROP TABLE t1, t2;
--echo # End of test for bug#13607423.
+--echo
+--echo Test of WL#6094 "Allow subquery materialization in NOT IN if all
+--echo columns are not nullable"
+--echo
+
+# We want to test WL#6094 only, not WL#6095, so we use 2 columns.
+
+create table t1(a int not null);
+create table t2(a int not null);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+
+--echo Test in SELECT list
+
+--echo
+let $query=select a, (a,a) in (select a,a from t2) from t1;
+
+--echo cols not nullable => subq materialization
+eval explain extended $query;
+eval $query;
+
+--echo
+let $query=select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+--echo cols not nullable => subq materialization
+eval explain extended $query;
+eval $query;
+
+--echo
+let $query=select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+
+--echo t2.a is not nullable, but in the query it may appear as NULL
+--echo as it's in an outer join. So, no materialization.
+eval explain extended $query;
+eval $query;
+
+--echo
+alter table t2 modify a int;
+let $query=select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+--echo two nullable inner cols => no subq materialization
+eval explain extended $query;
+eval $query;
+alter table t2 modify a int not null;
+
+--echo
+--echo Test in WHERE
+--echo
+let $query=select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) in (select a,a from t2 as t3);
+--echo top-level => subq materialization. With one exception: if
+--echo semijoin is enabled in @@optimizer_switch, semijoin is chosen,
+--echo then rejected (due to outer join), and in that case, the
+--echo fallback is IN->EXISTS, subq-materialization is not tried...
+eval explain extended $query;
+eval $query;
+
+--echo
+let $query=select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) not in (select a,a from t2 as t3);
+--echo cols not nullable => subq materialization
+eval explain extended $query;
+eval $query;
+
+drop table t1,t2;
+
+--echo
+--echo Test of WL6095 "Allow subquery materialization in NOT IN if
+--echo single-column subquery"
+--echo
+
+# We want to test WL#6095 only, not WL#6094, so we use nullable columns.
+
+create table t1(a int null);
+create table t2(a int null);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+
+--echo
+let $query=select a, a in (select a from t2) from t1;
+
+--echo one col => subq materialization
+eval explain extended $query;
+eval $query;
+
+--echo
+let $query=select t1.a, t2.a, t2.a in (select * from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+
+--echo t2.a is not nullable, but in the query it may appear as NULL
+--echo as it's in an outer join. But there is only one inner column so
+--echo materialization is possible
+eval explain extended $query;
+eval $query;
+
+--echo
+let $query=select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+
+--echo _two_ outer columns, nullable => no materialization
+eval explain extended $query;
+eval $query;
+
+drop table t1,t2;
+
+--echo
+--echo Test in HAVING
+
+create table t1(a int, b int);
+create table t2(a int);
+insert into t1 values(1,1),(1,2),(1,3),(2,1),(2,2),(2,3);
+insert into t2 values(10),(20);
+
+let $query=select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+
+--echo no NULLs.
+
+eval explain extended $query;
+eval $query;
+
+--echo one outer NULL
+insert into t1 values(null,null);
+
+eval explain extended $query;
+eval $query;
+
+--echo one outer NULL and one inner NULL
+insert into t2 values(null);
+
+eval explain extended $query;
+eval $query;
+
+--echo one inner NULL
+delete from t1 where a is null;
+
+eval explain extended $query;
+eval $query;
+
+drop table t1,t2;
+
+--echo
+--echo Verify that an inner NULL is looked up only once (result is
+--echo cached).
+
+create table t1(a int);
+create table t2(a int);
+insert into t1 values(1),(2),(3),(4),(5),(6);
+insert into t1 select * from t1; # t1 has 12 rows
+insert into t2 values(10),(20),(NULL);
+
+let $query=select a, (a in (select * from t2)) from t1;
+
+eval explain extended $query;
+flush status;
+eval $query;
+--echo There will be one look-up in the temporary table for each row
+--echo of t1 (12), plus one additional look-up to check whether table
+--echo contains a NULL value.
+show status like "handler_read_key";
+
+drop table t1,t2;
+
+--echo #
+--echo # Bug#13495157 - SUBQUERY MATERIALIZATION NOT USED FOR CERTAIN
+--echo # STATEMENTS
+--echo #
+
+CREATE TABLE t1(a INT);
+INSERT INTO t1 VALUES(1),(2),(3);
+CREATE TABLE t2(a INT);
+INSERT INTO t2 VALUES(1),(2),(4);
+
+--echo # subquery materialization used for SELECT:
+EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+
+--echo # Also used for INSERT SELECT:
+# a) all different tables:
+CREATE TABLE t3 SELECT * FROM t1;
+EXPLAIN INSERT INTO t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+INSERT INTO t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+--sorted_result
+SELECT * FROM t3;
+
+# b) insert into subquery's selected table
+EXPLAIN INSERT INTO t2 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+INSERT INTO t2 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+--sorted_result
+SELECT * FROM t2;
+
+# c) insert into subquery's and query's selected table
+EXPLAIN INSERT INTO t2 SELECT * FROM t2 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+INSERT INTO t2 SELECT * FROM t2 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+--sorted_result
+SELECT * FROM t2;
+
+--echo # Not used for single-table UPDATE, DELETE:
+# a) all different tables
+EXPLAIN SELECT * FROM t2 WHERE a IN (SELECT * FROM t1);
+EXPLAIN UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t1);
+UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t1);
+--sorted_result
+SELECT * FROM t2;
+EXPLAIN DELETE FROM t2 WHERE a IN (SELECT * FROM t1);
+DELETE FROM t2 WHERE a IN (SELECT * FROM t1);
+--sorted_result
+SELECT * FROM t2;
+
+# b) update/delete in subquery's selected table: forbidden
+--error ER_UPDATE_TABLE_USED
+EXPLAIN UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t2);
+--error ER_UPDATE_TABLE_USED
+EXPLAIN DELETE FROM t2 WHERE a IN (SELECT * FROM t2);
+
+# Put some content so that future queries have rows to modify:
+UPDATE t2 SET a=3 WHERE a=0;
+
+--echo # Used for multi-table UPDATE, DELETE:
+
+# a) all different tables
+EXPLAIN SELECT * FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+EXPLAIN UPDATE t2,t3 SET t2.a=t2.a-2 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+UPDATE t2,t3 SET t2.a=t2.a-2 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+--sorted_result
+SELECT * FROM t2;
+EXPLAIN DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+--sorted_result
+SELECT * FROM t2;
+
+# b) update/delete in subquery's selected table: forbidden
+--error ER_UPDATE_TABLE_USED
+EXPLAIN UPDATE t2,t3 SET t2.a=10 WHERE t2.a IN (SELECT * FROM t2 WHERE a <> 2);
+--error ER_UPDATE_TABLE_USED
+EXPLAIN DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t2 WHERE a <> 2);
+
+DROP TABLE t1,t2,t3;
+
+--echo #
+--echo # Test that subquery materialization only does one lookup: does
+--echo # not try to read the next row if the first row failed the
+--echo # subquery's WHERE. We use a case where index lookup is not
+--echo # enough to satisfy IN(), because index has length two when the
+--echo # outer value has length three, and thus the post-filtering
+--echo # WHERE added by subselect_hash_sj_engine::setup() makes the
+--echo # decision.
+--echo #
+create table t1 (a varchar(3));
+create table t2 (a varchar(2));
+insert into t1 values('aaa'), ('aaa');
+insert into t2 values('aa'), ('aa');
+let $query=select * from t1 where a in (select a from t2);
+eval explain $query;
+flush status;
+eval $query;
+show status like "handler_read%";
+drop table t1,t2;
+
+--echo #
+--echo # Bug#13655791 DIFFERENT RESULT WITH WL6094 ON QUERY WITH XOR
+--echo # IN WHERE CLAUSE + MYISAM
+--echo #
+
+CREATE TABLE t1 (
+ pk int NOT NULL,
+ col_varchar_nokey varchar(1) DEFAULT NULL,
+ PRIMARY KEY (pk)
+);
+
+INSERT INTO t1 VALUES (10,'x');
+
+CREATE TABLE t2 (
+ pk int NOT NULL,
+ col_varchar_nokey varchar(1) DEFAULT NULL,
+ PRIMARY KEY (pk)
+);
+
+INSERT INTO t2 VALUES (1,'v'), (5,'x'), (11,'z'), (12,'c'), (15,'y');
+
+CREATE TABLE t3 (
+ pk int NOT NULL,
+ col_int_key int DEFAULT NULL,
+ PRIMARY KEY (pk),
+ KEY col_int_key (col_int_key)
+);
+
+INSERT INTO t3 VALUES (10,8);
+
+CREATE TABLE t4 (
+ pk int NOT NULL,
+ col_varchar_nokey varchar(1) DEFAULT NULL,
+ PRIMARY KEY (pk)
+);
+
+INSERT INTO t4 VALUES (1,'x');
+
+let $query=
+SELECT OUTR.pk, OUTR.col_varchar_nokey, OUTR2.col_varchar_nokey
+FROM t2 AS OUTR2
+ JOIN t4 AS OUTR
+ ON (OUTR2.col_varchar_nokey > OUTR.col_varchar_nokey)
+WHERE
+ OUTR.col_varchar_nokey IN (
+ SELECT INNR.col_varchar_nokey
+ FROM t3 AS INNR2
+ LEFT JOIN t1 AS INNR
+ ON (INNR2.col_int_key >= INNR.pk)
+ )
+ XOR OUTR.pk < 6
+;
+
+eval EXPLAIN $query;
+FLUSH STATUS;
+eval $query;
+SHOW STATUS LIKE "HANDLER_READ%";
+
+DROP TABLE t1,t2,t3,t4;
+
--echo # End of 5.6 tests
=== modified file 'mysql-test/r/innodb_icp.result'
--- a/mysql-test/r/innodb_icp.result 2012-02-01 09:59:13 +0000
+++ b/mysql-test/r/innodb_icp.result 2012-02-08 15:25:17 +0000
@@ -794,6 +794,7 @@ PRIMARY KEY (pk),
KEY col_int_key (i1)
);
INSERT INTO t2 VALUES (1,7,'f');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT t1.i1
FROM t1
WHERE t1.i1 NOT IN
@@ -821,6 +822,7 @@ OR SUBQUERY_t2.c1 = 'a'
i1
NULL
133
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1,t2;
#
# Bug#11876420 "MISSING ROW IN RESULT WITH SUBQUERY + IN + XOR +
@@ -845,6 +847,7 @@ c1 VARCHAR(1),
KEY col_varchar_key (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL,'w'), (1,NULL), (2,'d');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT i1
FROM t3
WHERE c1 IN
@@ -870,6 +873,7 @@ XOR i1;
i1
1
2
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
#
# Bug#12355958 "FAILING ASSERTION: TRX->LOCK.N_ACTIVE_THRS == 1"
=== modified file 'mysql-test/r/innodb_icp_all.result'
--- a/mysql-test/r/innodb_icp_all.result 2012-02-01 09:59:13 +0000
+++ b/mysql-test/r/innodb_icp_all.result 2012-02-08 15:25:17 +0000
@@ -794,6 +794,7 @@ PRIMARY KEY (pk),
KEY col_int_key (i1)
);
INSERT INTO t2 VALUES (1,7,'f');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT t1.i1
FROM t1
WHERE t1.i1 NOT IN
@@ -821,6 +822,7 @@ OR SUBQUERY_t2.c1 = 'a'
i1
NULL
133
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1,t2;
#
# Bug#11876420 "MISSING ROW IN RESULT WITH SUBQUERY + IN + XOR +
@@ -845,6 +847,7 @@ c1 VARCHAR(1),
KEY col_varchar_key (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL,'w'), (1,NULL), (2,'d');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT i1
FROM t3
WHERE c1 IN
@@ -870,6 +873,7 @@ XOR i1;
i1
1
2
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
#
# Bug#12355958 "FAILING ASSERTION: TRX->LOCK.N_ACTIVE_THRS == 1"
=== modified file 'mysql-test/r/innodb_icp_none.result'
--- a/mysql-test/r/innodb_icp_none.result 2012-02-01 09:59:13 +0000
+++ b/mysql-test/r/innodb_icp_none.result 2012-02-08 15:25:17 +0000
@@ -793,6 +793,7 @@ PRIMARY KEY (pk),
KEY col_int_key (i1)
);
INSERT INTO t2 VALUES (1,7,'f');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT t1.i1
FROM t1
WHERE t1.i1 NOT IN
@@ -820,6 +821,7 @@ OR SUBQUERY_t2.c1 = 'a'
i1
NULL
133
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1,t2;
#
# Bug#11876420 "MISSING ROW IN RESULT WITH SUBQUERY + IN + XOR +
@@ -844,6 +846,7 @@ c1 VARCHAR(1),
KEY col_varchar_key (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL,'w'), (1,NULL), (2,'d');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT i1
FROM t3
WHERE c1 IN
@@ -869,6 +872,7 @@ XOR i1;
i1
1
2
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
#
# Bug#12355958 "FAILING ASSERTION: TRX->LOCK.N_ACTIVE_THRS == 1"
=== modified file 'mysql-test/r/join_cache_bka.result'
--- a/mysql-test/r/join_cache_bka.result 2012-01-30 13:13:15 +0000
+++ b/mysql-test/r/join_cache_bka.result 2012-02-08 15:25:17 +0000
@@ -2380,6 +2380,7 @@ c1 INTEGER,
KEY k1 (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL), (NULL);
+set @old_opt_switch=@@optimizer_switch;
explain SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
@@ -2411,9 +2412,9 @@ id select_type table type possible_keys
explain SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start materialize; Scan
-1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where; End materialize; Using join buffer (Block Nested Loop)
-1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index
+1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start temporary
+1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where; Using join buffer (Block Nested Loop)
+1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index; End temporary
SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
XOR TRUE;
@@ -2433,6 +2434,7 @@ SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
c1
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
set @@join_buffer_size=default;
=== modified file 'mysql-test/r/join_cache_bka_nixbnl.result'
--- a/mysql-test/r/join_cache_bka_nixbnl.result 2012-01-30 13:13:15 +0000
+++ b/mysql-test/r/join_cache_bka_nixbnl.result 2012-02-08 15:25:17 +0000
@@ -2380,6 +2380,7 @@ c1 INTEGER,
KEY k1 (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL), (NULL);
+set @old_opt_switch=@@optimizer_switch;
explain SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
@@ -2411,9 +2412,9 @@ id select_type table type possible_keys
explain SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start materialize; Scan
-1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where; End materialize
-1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index
+1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start temporary
+1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where
+1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index; End temporary
SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
XOR TRUE;
@@ -2433,6 +2434,7 @@ SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
c1
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
set @@join_buffer_size=default;
=== modified file 'mysql-test/r/join_cache_bkaunique.result'
--- a/mysql-test/r/join_cache_bkaunique.result 2012-01-30 13:13:15 +0000
+++ b/mysql-test/r/join_cache_bkaunique.result 2012-02-08 15:25:17 +0000
@@ -2381,6 +2381,7 @@ c1 INTEGER,
KEY k1 (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL), (NULL);
+set @old_opt_switch=@@optimizer_switch;
explain SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
@@ -2412,9 +2413,9 @@ id select_type table type possible_keys
explain SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start materialize; Scan
-1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where; End materialize; Using join buffer (Block Nested Loop)
-1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index
+1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start temporary
+1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where; Using join buffer (Block Nested Loop)
+1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index; End temporary
SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
XOR TRUE;
@@ -2434,6 +2435,7 @@ SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
c1
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
set @@join_buffer_size=default;
=== modified file 'mysql-test/r/join_cache_bnl.result'
--- a/mysql-test/r/join_cache_bnl.result 2012-01-30 13:13:15 +0000
+++ b/mysql-test/r/join_cache_bnl.result 2012-02-08 15:25:17 +0000
@@ -2381,6 +2381,7 @@ c1 INTEGER,
KEY k1 (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL), (NULL);
+set @old_opt_switch=@@optimizer_switch;
explain SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
@@ -2412,9 +2413,9 @@ id select_type table type possible_keys
explain SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start materialize; Scan
-1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where; End materialize; Using join buffer (Block Nested Loop)
-1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index
+1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start temporary
+1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where; Using join buffer (Block Nested Loop)
+1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index; End temporary
SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
XOR TRUE;
@@ -2434,6 +2435,7 @@ SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
c1
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
set @@join_buffer_size=default;
=== modified file 'mysql-test/r/join_cache_nojb.result'
--- a/mysql-test/r/join_cache_nojb.result 2012-02-01 09:59:13 +0000
+++ b/mysql-test/r/join_cache_nojb.result 2012-02-08 15:25:17 +0000
@@ -2381,6 +2381,7 @@ c1 INTEGER,
KEY k1 (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL), (NULL);
+set @old_opt_switch=@@optimizer_switch;
explain SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
@@ -2412,9 +2413,9 @@ id select_type table type possible_keys
explain SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start materialize; Scan
-1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where; End materialize
-1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index
+1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 1 Using index; Start temporary
+1 PRIMARY t1 ALL col_int_key NULL NULL NULL 1 Using where
+1 PRIMARY t3 ref k1 k1 5 test.t1.c2_key 1 Using index; End temporary
SELECT t3.c1 FROM t3
WHERE t3.c1 = SOME (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1)
XOR TRUE;
@@ -2434,6 +2435,7 @@ SELECT t3.c1 FROM t3
WHERE t3.c1 IN (SELECT t1.c2_key FROM t2 JOIN t1 ON t2.pk < t1.c1);
c1
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
set @@join_buffer_size=default;
=== modified file 'mysql-test/r/myisam_icp.result'
--- a/mysql-test/r/myisam_icp.result 2012-02-01 09:59:13 +0000
+++ b/mysql-test/r/myisam_icp.result 2012-02-08 15:25:17 +0000
@@ -792,6 +792,7 @@ PRIMARY KEY (pk),
KEY col_int_key (i1)
);
INSERT INTO t2 VALUES (1,7,'f');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT t1.i1
FROM t1
WHERE t1.i1 NOT IN
@@ -819,6 +820,7 @@ OR SUBQUERY_t2.c1 = 'a'
i1
NULL
133
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1,t2;
#
# Bug#11876420 "MISSING ROW IN RESULT WITH SUBQUERY + IN + XOR +
@@ -843,6 +845,7 @@ c1 VARCHAR(1),
KEY col_varchar_key (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL,'w'), (1,NULL), (2,'d');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT i1
FROM t3
WHERE c1 IN
@@ -867,6 +870,7 @@ XOR i1;
i1
1
2
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
#
# Bug#12355958 "FAILING ASSERTION: TRX->LOCK.N_ACTIVE_THRS == 1"
=== modified file 'mysql-test/r/myisam_icp_all.result'
--- a/mysql-test/r/myisam_icp_all.result 2012-02-01 09:59:13 +0000
+++ b/mysql-test/r/myisam_icp_all.result 2012-02-08 15:25:17 +0000
@@ -792,6 +792,7 @@ PRIMARY KEY (pk),
KEY col_int_key (i1)
);
INSERT INTO t2 VALUES (1,7,'f');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT t1.i1
FROM t1
WHERE t1.i1 NOT IN
@@ -819,6 +820,7 @@ OR SUBQUERY_t2.c1 = 'a'
i1
NULL
133
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1,t2;
#
# Bug#11876420 "MISSING ROW IN RESULT WITH SUBQUERY + IN + XOR +
@@ -843,6 +845,7 @@ c1 VARCHAR(1),
KEY col_varchar_key (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL,'w'), (1,NULL), (2,'d');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT i1
FROM t3
WHERE c1 IN
@@ -867,6 +870,7 @@ XOR i1;
i1
1
2
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
#
# Bug#12355958 "FAILING ASSERTION: TRX->LOCK.N_ACTIVE_THRS == 1"
=== modified file 'mysql-test/r/myisam_icp_none.result'
--- a/mysql-test/r/myisam_icp_none.result 2012-02-01 09:59:13 +0000
+++ b/mysql-test/r/myisam_icp_none.result 2012-02-08 15:25:17 +0000
@@ -791,6 +791,7 @@ PRIMARY KEY (pk),
KEY col_int_key (i1)
);
INSERT INTO t2 VALUES (1,7,'f');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT t1.i1
FROM t1
WHERE t1.i1 NOT IN
@@ -818,6 +819,7 @@ OR SUBQUERY_t2.c1 = 'a'
i1
NULL
133
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1,t2;
#
# Bug#11876420 "MISSING ROW IN RESULT WITH SUBQUERY + IN + XOR +
@@ -842,6 +844,7 @@ c1 VARCHAR(1),
KEY col_varchar_key (c1)
) ENGINE=InnoDB;
INSERT INTO t3 VALUES (NULL,'w'), (1,NULL), (2,'d');
+set @old_opt_switch=@@optimizer_switch;
EXPLAIN SELECT i1
FROM t3
WHERE c1 IN
@@ -866,6 +869,7 @@ XOR i1;
i1
1
2
+set @@optimizer_switch=@old_opt_switch;
DROP TABLE t1, t2, t3;
#
# Bug#12355958 "FAILING ASSERTION: TRX->LOCK.N_ACTIVE_THRS == 1"
=== modified file 'mysql-test/r/subquery_all.result'
--- a/mysql-test/r/subquery_all.result 2012-02-07 14:50:31 +0000
+++ b/mysql-test/r/subquery_all.result 2012-02-08 15:25:17 +0000
@@ -890,9 +890,9 @@ a t1.a in (select t2.a from t2)
explain extended SELECT t1.a, t1.a in (select t2.a from t2) FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery a a 5 func 2 100.00 Using index
+2 SUBQUERY t2 index NULL a 5 NULL 3 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in t2 on a checking NULL having <is_not_null_test>(`test`.`t2`.`a`)))) AS `t1.a in (select t2.a from t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `t1.a in (select t2.a from t2)` from `test`.`t1`
CREATE TABLE t3 (a int(11) default '0');
INSERT INTO t3 VALUES (1),(2),(3);
SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
@@ -904,10 +904,10 @@ a t1.a in (select t2.a from t2,t3 where
explain extended SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
-2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 func 2 100.00 Using where; Using index
-2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t2 index a a 5 NULL 3 100.00 Using index
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (Block Nested Loop)
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t2` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t2`.`a`) and ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`))) having <is_not_null_test>(`test`.`t2`.`a`))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` join `test`.`t3` where (`test`.`t3`.`a` = `test`.`t2`.`a`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1`
drop table t1,t2,t3;
create table t1 (a float);
select 10.5 IN (SELECT * from t1 LIMIT 1);
@@ -1368,27 +1368,27 @@ a3 1
explain extended select s1, s1 NOT IN (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key
+2 SUBQUERY t2 index NULL s1 6 NULL 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key
+2 SUBQUERY t2 index NULL s1 6 NULL 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key
+2 SUBQUERY t2 index NULL s1 6 NULL 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Using where; Full scan on NULL key
+2 SUBQUERY t2 index s1 s1 6 NULL 2 50.00 Using where; Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL where (`test`.`t2`.`s1` < 'a2') having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` where (`test`.`t2`.`s1` < 'a2') ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1`
drop table t1,t2;
create table t2 (a int, b int);
create table t3 (a int);
@@ -1641,9 +1641,9 @@ id text
explain extended select * from t1 where id not in (select id from t1 where id < 8);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 12 100.00 Using where
-2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index; Using where
+2 SUBQUERY t1 range PRIMARY PRIMARY 4 NULL 7 100.00 Using where; Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`id`,<exists>(<primary_index_lookup>(<cache>(`test`.`t1`.`id`) in t1 on PRIMARY where ((`test`.`t1`.`id` < 8) and (<cache>(`test`.`t1`.`id`) = `test`.`t1`.`id`)))))))
+Note 1003 /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`id`,`test`.`t1`.`id` in ( <materialize> (/* select#2 */ select `test`.`t1`.`id` from `test`.`t1` where (`test`.`t1`.`id` < 8) ), <primary_index_lookup>(`test`.`t1`.`id` in <temporary table> on distinct_key where ((`test`.`t1`.`id` = `materialized subselect`.`id`)))))))
explain extended select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY tt ALL NULL NULL NULL NULL 12 100.00 Using where
@@ -2829,7 +2829,7 @@ INSERT INTO t2 VALUES (1),(2),(3);
EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 3
-2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 2 Using index; Full scan on NULL key
+2 SUBQUERY t1 index NULL a 5 NULL 5 Using index
SELECT a, a IN (SELECT a FROM t1) FROM t2;
a a IN (SELECT a FROM t1)
1 1
@@ -4180,14 +4180,14 @@ CREATE TABLE t1 (pk int PRIMARY KEY, int
INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
-# should have eq_ref for t1
+# should have eq_ref for t1, unless subquery materialization is used
EXPLAIN
SELECT * FROM t2 outr
WHERE outr.int_key NOT IN (SELECT t1.pk FROM t1, t2)
ORDER BY outr.pk;
id select_type table type possible_keys key key_len ref rows Extra
x x outr ALL x x x x x x
-x x t1 eq_ref x x x x x x
+x x t1 index x x x x x x
x x t2 index x x x x x x
# should not crash on debug binaries
SELECT * FROM t2 outr
@@ -4264,9 +4264,9 @@ Z
explain extended select a in (select max(ie) from t1 where oref=4 group by grp) from t3;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00
-2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using temporary; Using filesort
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using temporary; Using filesort
Warnings:
-Note 1003 /* select#1 */ select <in_optimizer>(`test`.`t3`.`a`,<exists>(/* select#2 */ select max(`test`.`t1`.`ie`) from `test`.`t1` where (`test`.`t1`.`oref` = 4) group by `test`.`t1`.`grp` having trigcond_if(outer_field_is_not_null, (<cache>(`test`.`t3`.`a`) = <ref_null_helper>(max(`test`.`t1`.`ie`))), true))) AS `a in (select max(ie) from t1 where oref=4 group by grp)` from `test`.`t3`
+Note 1003 /* select#1 */ select <in_optimizer>(`test`.`t3`.`a`,`test`.`t3`.`a` in ( <materialize> (/* select#2 */ select max(`test`.`t1`.`ie`) from `test`.`t1` where (`test`.`t1`.`oref` = 4) group by `test`.`t1`.`grp` ), <primary_index_lookup>(`test`.`t3`.`a` in <temporary table> on distinct_key where ((`test`.`t3`.`a` = `materialized subselect`.`max(ie)`))))) AS `a in (select max(ie) from t1 where oref=4 group by grp)` from `test`.`t3`
drop table t1, t2, t3;
create table t1 (a int, oref int, key(a));
insert into t1 values
@@ -4900,9 +4900,9 @@ SELECT a FROM t1, t2 WHERE a=b AND (b NO
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 100.00 Using index
-2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`b` = `test`.`t1`.`a`) and (not(<in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t1` where ((<cache>(`test`.`t2`.`b`) = `test`.`t1`.`a`) or isnull(`test`.`t1`.`a`)) having <is_not_null_test>(`test`.`t1`.`a`))))))
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`b` = `test`.`t1`.`a`) and (not(<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))))))
SELECT a FROM t1, t2 WHERE a=b AND (b NOT IN (SELECT a FROM t1));
a
SELECT a FROM t1, t2 WHERE a=b AND (b NOT IN (SELECT a FROM t1 WHERE a > 4));
@@ -4922,8 +4922,8 @@ WHERE t1.id NOT IN (SELECT t2.id FROM t2
WHERE t3.name='xxx' AND t2.id=t3.id);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
-2 DEPENDENT SUBQUERY t2 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Using index; Full scan on NULL key
-2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Full scan on NULL key
+2 SUBQUERY t2 index PRIMARY PRIMARY 4 NULL 3 Using index
+2 SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t2.id 1 Using where
SELECT * FROM t1
WHERE t1.id NOT IN (SELECT t2.id FROM t2,t3
WHERE t3.name='xxx' AND t2.id=t3.id);
@@ -4956,7 +4956,7 @@ a
EXPLAIN SELECT a FROM t1 WHERE a NOT IN (SELECT a FROM t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
-2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using index; Using where
+2 SUBQUERY t2 index NULL PRIMARY 4 NULL 2 Using index
DROP TABLE t1, t2;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES(1);
@@ -6280,8 +6280,8 @@ INSERT INTO t2 VALUES (1), (2);
EXPLAIN
SELECT i FROM t1 WHERE (1) NOT IN (SELECT i FROM t2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY t2 index_subquery k k 5 const 2 Using index
+1 PRIMARY t1 system NULL NULL NULL NULL 1
+2 SUBQUERY t2 index NULL k 5 NULL 2 Using index
DROP TABLE t2;
DROP TABLE t1;
#
@@ -7045,7 +7045,7 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY,col_varchar_key NULL NULL NULL 1
+2 UNCACHEABLE SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey)
@@ -7068,7 +7068,7 @@ OR c_sq1_alias1.pk != @var3)) ) AS alias
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
-3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY,col_varchar_key NULL NULL NULL 1
+3 UNCACHEABLE SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT * FROM ( SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey)
@@ -7080,4 +7080,31 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey
DROP TABLE t1,t2;
+#
+# Test that indexsubquery_engine only does one lookup if
+# the technique is unique_subquery: does not try to read the
+# next row if the first row failed the subquery's WHERE
+# condition (here: b=3).
+#
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+explain select * from t1 where a in (select a from t2 where b=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where
+flush status;
+select * from t1 where a in (select a from t2 where b=3);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 3
+drop table t1,t2;
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_all_bka.result'
--- a/mysql-test/r/subquery_all_bka.result 2012-02-07 14:50:31 +0000
+++ b/mysql-test/r/subquery_all_bka.result 2012-02-08 15:25:17 +0000
@@ -891,9 +891,9 @@ a t1.a in (select t2.a from t2)
explain extended SELECT t1.a, t1.a in (select t2.a from t2) FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery a a 5 func 2 100.00 Using index
+2 SUBQUERY t2 index NULL a 5 NULL 3 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in t2 on a checking NULL having <is_not_null_test>(`test`.`t2`.`a`)))) AS `t1.a in (select t2.a from t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `t1.a in (select t2.a from t2)` from `test`.`t1`
CREATE TABLE t3 (a int(11) default '0');
INSERT INTO t3 VALUES (1),(2),(3);
SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
@@ -905,10 +905,10 @@ a t1.a in (select t2.a from t2,t3 where
explain extended SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
-2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 func 2 100.00 Using where; Using index
-2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t2 index a a 5 NULL 3 100.00 Using index
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (Block Nested Loop)
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t2` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t2`.`a`) and ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`))) having <is_not_null_test>(`test`.`t2`.`a`))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` join `test`.`t3` where (`test`.`t3`.`a` = `test`.`t2`.`a`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1`
drop table t1,t2,t3;
create table t1 (a float);
select 10.5 IN (SELECT * from t1 LIMIT 1);
@@ -1369,27 +1369,27 @@ a3 1
explain extended select s1, s1 NOT IN (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key
+2 SUBQUERY t2 index NULL s1 6 NULL 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key
+2 SUBQUERY t2 index NULL s1 6 NULL 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key
+2 SUBQUERY t2 index NULL s1 6 NULL 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Using where; Full scan on NULL key
+2 SUBQUERY t2 index s1 s1 6 NULL 2 50.00 Using where; Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL where (`test`.`t2`.`s1` < 'a2') having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` where (`test`.`t2`.`s1` < 'a2') ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1`
drop table t1,t2;
create table t2 (a int, b int);
create table t3 (a int);
@@ -1642,9 +1642,9 @@ id text
explain extended select * from t1 where id not in (select id from t1 where id < 8);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 12 100.00 Using where
-2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index; Using where
+2 SUBQUERY t1 range PRIMARY PRIMARY 4 NULL 7 100.00 Using where; Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`id`,<exists>(<primary_index_lookup>(<cache>(`test`.`t1`.`id`) in t1 on PRIMARY where ((`test`.`t1`.`id` < 8) and (<cache>(`test`.`t1`.`id`) = `test`.`t1`.`id`)))))))
+Note 1003 /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`id`,`test`.`t1`.`id` in ( <materialize> (/* select#2 */ select `test`.`t1`.`id` from `test`.`t1` where (`test`.`t1`.`id` < 8) ), <primary_index_lookup>(`test`.`t1`.`id` in <temporary table> on distinct_key where ((`test`.`t1`.`id` = `materialized subselect`.`id`)))))))
explain extended select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY tt ALL NULL NULL NULL NULL 12 100.00 Using where
@@ -2830,7 +2830,7 @@ INSERT INTO t2 VALUES (1),(2),(3);
EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 3
-2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 2 Using index; Full scan on NULL key
+2 SUBQUERY t1 index NULL a 5 NULL 5 Using index
SELECT a, a IN (SELECT a FROM t1) FROM t2;
a a IN (SELECT a FROM t1)
1 1
@@ -4181,14 +4181,14 @@ CREATE TABLE t1 (pk int PRIMARY KEY, int
INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
-# should have eq_ref for t1
+# should have eq_ref for t1, unless subquery materialization is used
EXPLAIN
SELECT * FROM t2 outr
WHERE outr.int_key NOT IN (SELECT t1.pk FROM t1, t2)
ORDER BY outr.pk;
id select_type table type possible_keys key key_len ref rows Extra
x x outr ALL x x x x x x
-x x t1 eq_ref x x x x x x
+x x t1 index x x x x x x
x x t2 index x x x x x x
# should not crash on debug binaries
SELECT * FROM t2 outr
@@ -4265,9 +4265,9 @@ Z
explain extended select a in (select max(ie) from t1 where oref=4 group by grp) from t3;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00
-2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using temporary; Using filesort
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using temporary; Using filesort
Warnings:
-Note 1003 /* select#1 */ select <in_optimizer>(`test`.`t3`.`a`,<exists>(/* select#2 */ select max(`test`.`t1`.`ie`) from `test`.`t1` where (`test`.`t1`.`oref` = 4) group by `test`.`t1`.`grp` having trigcond_if(outer_field_is_not_null, (<cache>(`test`.`t3`.`a`) = <ref_null_helper>(max(`test`.`t1`.`ie`))), true))) AS `a in (select max(ie) from t1 where oref=4 group by grp)` from `test`.`t3`
+Note 1003 /* select#1 */ select <in_optimizer>(`test`.`t3`.`a`,`test`.`t3`.`a` in ( <materialize> (/* select#2 */ select max(`test`.`t1`.`ie`) from `test`.`t1` where (`test`.`t1`.`oref` = 4) group by `test`.`t1`.`grp` ), <primary_index_lookup>(`test`.`t3`.`a` in <temporary table> on distinct_key where ((`test`.`t3`.`a` = `materialized subselect`.`max(ie)`))))) AS `a in (select max(ie) from t1 where oref=4 group by grp)` from `test`.`t3`
drop table t1, t2, t3;
create table t1 (a int, oref int, key(a));
insert into t1 values
@@ -4901,9 +4901,9 @@ SELECT a FROM t1, t2 WHERE a=b AND (b NO
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 100.00 Using index
-2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`b` = `test`.`t1`.`a`) and (not(<in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t1` where ((<cache>(`test`.`t2`.`b`) = `test`.`t1`.`a`) or isnull(`test`.`t1`.`a`)) having <is_not_null_test>(`test`.`t1`.`a`))))))
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`b` = `test`.`t1`.`a`) and (not(<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))))))
SELECT a FROM t1, t2 WHERE a=b AND (b NOT IN (SELECT a FROM t1));
a
SELECT a FROM t1, t2 WHERE a=b AND (b NOT IN (SELECT a FROM t1 WHERE a > 4));
@@ -4923,8 +4923,8 @@ WHERE t1.id NOT IN (SELECT t2.id FROM t2
WHERE t3.name='xxx' AND t2.id=t3.id);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
-2 DEPENDENT SUBQUERY t2 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Using index; Full scan on NULL key
-2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Full scan on NULL key
+2 SUBQUERY t2 index PRIMARY PRIMARY 4 NULL 3 Using index
+2 SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t2.id 1 Using where; Using join buffer (Batched Key Access)
SELECT * FROM t1
WHERE t1.id NOT IN (SELECT t2.id FROM t2,t3
WHERE t3.name='xxx' AND t2.id=t3.id);
@@ -4957,7 +4957,7 @@ a
EXPLAIN SELECT a FROM t1 WHERE a NOT IN (SELECT a FROM t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
-2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using index; Using where
+2 SUBQUERY t2 index NULL PRIMARY 4 NULL 2 Using index
DROP TABLE t1, t2;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES(1);
@@ -6281,8 +6281,8 @@ INSERT INTO t2 VALUES (1), (2);
EXPLAIN
SELECT i FROM t1 WHERE (1) NOT IN (SELECT i FROM t2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY t2 index_subquery k k 5 const 2 Using index
+1 PRIMARY t1 system NULL NULL NULL NULL 1
+2 SUBQUERY t2 index NULL k 5 NULL 2 Using index
DROP TABLE t2;
DROP TABLE t1;
#
@@ -7046,7 +7046,7 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY,col_varchar_key NULL NULL NULL 1
+2 UNCACHEABLE SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey)
@@ -7069,7 +7069,7 @@ OR c_sq1_alias1.pk != @var3)) ) AS alias
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
-3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY,col_varchar_key NULL NULL NULL 1
+3 UNCACHEABLE SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT * FROM ( SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey)
@@ -7081,5 +7081,32 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey
DROP TABLE t1,t2;
+#
+# Test that indexsubquery_engine only does one lookup if
+# the technique is unique_subquery: does not try to read the
+# next row if the first row failed the subquery's WHERE
+# condition (here: b=3).
+#
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+explain select * from t1 where a in (select a from t2 where b=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where; Using join buffer (Batched Key Access)
+flush status;
+select * from t1 where a in (select a from t2 where b=3);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 2
+Handler_read_prev 0
+Handler_read_rnd 2
+Handler_read_rnd_next 3
+drop table t1,t2;
set optimizer_switch=default;
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_all_bka_nixbnl.result'
--- a/mysql-test/r/subquery_all_bka_nixbnl.result 2012-02-07 14:50:31 +0000
+++ b/mysql-test/r/subquery_all_bka_nixbnl.result 2012-02-08 15:25:17 +0000
@@ -891,9 +891,9 @@ a t1.a in (select t2.a from t2)
explain extended SELECT t1.a, t1.a in (select t2.a from t2) FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery a a 5 func 2 100.00 Using index
+2 SUBQUERY t2 index NULL a 5 NULL 3 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in t2 on a checking NULL having <is_not_null_test>(`test`.`t2`.`a`)))) AS `t1.a in (select t2.a from t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `t1.a in (select t2.a from t2)` from `test`.`t1`
CREATE TABLE t3 (a int(11) default '0');
INSERT INTO t3 VALUES (1),(2),(3);
SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
@@ -905,10 +905,10 @@ a t1.a in (select t2.a from t2,t3 where
explain extended SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index
-2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 func 2 100.00 Using where; Using index
-2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where
+2 SUBQUERY t2 ref a a 5 test.t3.a 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t2` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t2`.`a`) and ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`))) having <is_not_null_test>(`test`.`t2`.`a`))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` join `test`.`t3` where (`test`.`t2`.`a` = `test`.`t3`.`a`) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1`
drop table t1,t2,t3;
create table t1 (a float);
select 10.5 IN (SELECT * from t1 LIMIT 1);
@@ -1369,27 +1369,27 @@ a3 1
explain extended select s1, s1 NOT IN (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key
+2 SUBQUERY t2 index NULL s1 6 NULL 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key
+2 SUBQUERY t2 index NULL s1 6 NULL 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key
+2 SUBQUERY t2 index NULL s1 6 NULL 2 100.00 Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index
-2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Using where; Full scan on NULL key
+2 SUBQUERY t2 index s1 s1 6 NULL 2 50.00 Using where; Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL where (`test`.`t2`.`s1` < 'a2') having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`s1`), true)))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1`
+Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,`test`.`t1`.`s1` in ( <materialize> (/* select#2 */ select `test`.`t2`.`s1` from `test`.`t2` where (`test`.`t2`.`s1` < 'a2') ), <primary_index_lookup>(`test`.`t1`.`s1` in <temporary table> on distinct_key where ((`test`.`t1`.`s1` = `materialized subselect`.`s1`))))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1`
drop table t1,t2;
create table t2 (a int, b int);
create table t3 (a int);
@@ -1642,9 +1642,9 @@ id text
explain extended select * from t1 where id not in (select id from t1 where id < 8);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 12 100.00 Using where
-2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index; Using where
+2 SUBQUERY t1 range PRIMARY PRIMARY 4 NULL 7 100.00 Using where; Using index
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`id`,<exists>(<primary_index_lookup>(<cache>(`test`.`t1`.`id`) in t1 on PRIMARY where ((`test`.`t1`.`id` < 8) and (<cache>(`test`.`t1`.`id`) = `test`.`t1`.`id`)))))))
+Note 1003 /* select#1 */ select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`id`,`test`.`t1`.`id` in ( <materialize> (/* select#2 */ select `test`.`t1`.`id` from `test`.`t1` where (`test`.`t1`.`id` < 8) ), <primary_index_lookup>(`test`.`t1`.`id` in <temporary table> on distinct_key where ((`test`.`t1`.`id` = `materialized subselect`.`id`)))))))
explain extended select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY tt ALL NULL NULL NULL NULL 12 100.00 Using where
@@ -2830,7 +2830,7 @@ INSERT INTO t2 VALUES (1),(2),(3);
EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 3
-2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 2 Using index; Full scan on NULL key
+2 SUBQUERY t1 index NULL a 5 NULL 5 Using index
SELECT a, a IN (SELECT a FROM t1) FROM t2;
a a IN (SELECT a FROM t1)
1 1
@@ -4181,14 +4181,14 @@ CREATE TABLE t1 (pk int PRIMARY KEY, int
INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
-# should have eq_ref for t1
+# should have eq_ref for t1, unless subquery materialization is used
EXPLAIN
SELECT * FROM t2 outr
WHERE outr.int_key NOT IN (SELECT t1.pk FROM t1, t2)
ORDER BY outr.pk;
id select_type table type possible_keys key key_len ref rows Extra
x x outr ALL x x x x x x
-x x t1 eq_ref x x x x x x
+x x t1 index x x x x x x
x x t2 index x x x x x x
# should not crash on debug binaries
SELECT * FROM t2 outr
@@ -4265,9 +4265,9 @@ Z
explain extended select a in (select max(ie) from t1 where oref=4 group by grp) from t3;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00
-2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using temporary; Using filesort
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using temporary; Using filesort
Warnings:
-Note 1003 /* select#1 */ select <in_optimizer>(`test`.`t3`.`a`,<exists>(/* select#2 */ select max(`test`.`t1`.`ie`) from `test`.`t1` where (`test`.`t1`.`oref` = 4) group by `test`.`t1`.`grp` having trigcond_if(outer_field_is_not_null, (<cache>(`test`.`t3`.`a`) = <ref_null_helper>(max(`test`.`t1`.`ie`))), true))) AS `a in (select max(ie) from t1 where oref=4 group by grp)` from `test`.`t3`
+Note 1003 /* select#1 */ select <in_optimizer>(`test`.`t3`.`a`,`test`.`t3`.`a` in ( <materialize> (/* select#2 */ select max(`test`.`t1`.`ie`) from `test`.`t1` where (`test`.`t1`.`oref` = 4) group by `test`.`t1`.`grp` ), <primary_index_lookup>(`test`.`t3`.`a` in <temporary table> on distinct_key where ((`test`.`t3`.`a` = `materialized subselect`.`max(ie)`))))) AS `a in (select max(ie) from t1 where oref=4 group by grp)` from `test`.`t3`
drop table t1, t2, t3;
create table t1 (a int, oref int, key(a));
insert into t1 values
@@ -4901,9 +4901,9 @@ SELECT a FROM t1, t2 WHERE a=b AND (b NO
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 100.00 Using index
-2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00 Using where
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00
Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`b` = `test`.`t1`.`a`) and (not(<in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t1` where ((<cache>(`test`.`t2`.`b`) = `test`.`t1`.`a`) or isnull(`test`.`t1`.`a`)) having <is_not_null_test>(`test`.`t1`.`a`))))))
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`b` = `test`.`t1`.`a`) and (not(<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))))))
SELECT a FROM t1, t2 WHERE a=b AND (b NOT IN (SELECT a FROM t1));
a
SELECT a FROM t1, t2 WHERE a=b AND (b NOT IN (SELECT a FROM t1 WHERE a > 4));
@@ -4923,8 +4923,8 @@ WHERE t1.id NOT IN (SELECT t2.id FROM t2
WHERE t3.name='xxx' AND t2.id=t3.id);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
-2 DEPENDENT SUBQUERY t2 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Using index; Full scan on NULL key
-2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Full scan on NULL key
+2 SUBQUERY t2 index PRIMARY PRIMARY 4 NULL 3 Using index
+2 SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t2.id 1 Using where; Using join buffer (Batched Key Access)
SELECT * FROM t1
WHERE t1.id NOT IN (SELECT t2.id FROM t2,t3
WHERE t3.name='xxx' AND t2.id=t3.id);
@@ -4957,7 +4957,7 @@ a
EXPLAIN SELECT a FROM t1 WHERE a NOT IN (SELECT a FROM t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 Using where
-2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using index; Using where
+2 SUBQUERY t2 index NULL PRIMARY 4 NULL 2 Using index
DROP TABLE t1, t2;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES(1);
@@ -6281,8 +6281,8 @@ INSERT INTO t2 VALUES (1), (2);
EXPLAIN
SELECT i FROM t1 WHERE (1) NOT IN (SELECT i FROM t2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY t2 index_subquery k k 5 const 2 Using index
+1 PRIMARY t1 system NULL NULL NULL NULL 1
+2 SUBQUERY t2 index NULL k 5 NULL 2 Using index
DROP TABLE t2;
DROP TABLE t1;
#
@@ -7046,7 +7046,7 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY,col_varchar_key NULL NULL NULL 1
+2 UNCACHEABLE SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey)
@@ -7069,7 +7069,7 @@ OR c_sq1_alias1.pk != @var3)) ) AS alias
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
-3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY,col_varchar_key NULL NULL NULL 1
+3 UNCACHEABLE SUBQUERY c_sq1_alias1 system PRIMARY NULL NULL NULL 1
SELECT * FROM ( SELECT sq4_alias1.*
FROM t1 AS sq4_alias1
WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey)
@@ -7081,5 +7081,32 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey
DROP TABLE t1,t2;
+#
+# Test that indexsubquery_engine only does one lookup if
+# the technique is unique_subquery: does not try to read the
+# next row if the first row failed the subquery's WHERE
+# condition (here: b=3).
+#
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+explain select * from t1 where a in (select a from t2 where b=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where; Using join buffer (Batched Key Access)
+flush status;
+select * from t1 where a in (select a from t2 where b=3);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 2
+Handler_read_prev 0
+Handler_read_rnd 2
+Handler_read_rnd_next 3
+drop table t1,t2;
set optimizer_switch=default;
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_mat.result'
--- a/mysql-test/r/subquery_mat.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_mat.result 2012-02-08 15:25:17 +0000
@@ -1294,5 +1294,485 @@ pk pk
1 NULL
DROP TABLE t1, t2;
# End of test for bug#13607423.
+
+Test of WL#6094 "Allow subquery materialization in NOT IN if all
+columns are not nullable"
+
+create table t1(a int not null);
+create table t2(a int not null);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+Test in SELECT list
+
+cols not nullable => subq materialization
+explain extended select a, (a,a) in (select a,a from t2) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`a`),(`test`.`t1`.`a`,`test`.`t1`.`a`) in ( <materialize> (/* select#2 */ select `test`.`t2`.`a`,`test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`) and (`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `(a,a) in (select a,a from t2)` from `test`.`t1`
+select a, (a,a) in (select a,a from t2) from t1;
+a (a,a) in (select a,a from t2)
+1 1
+2 1
+
+cols not nullable => subq materialization
+explain extended select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`a`),(`test`.`t1`.`a`,`test`.`t1`.`a`) in ( <materialize> (/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`) and (`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `(t1.a,t1.a) in (select a,a from t2 as t3)` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)
+select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+a a (t1.a,t1.a) in (select a,a from t2 as t3)
+
+t2.a is not nullable, but in the query it may appear as NULL
+as it's in an outer join. So, no materialization.
+explain extended select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where (trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or <cache>(isnull(`test`.`t3`.`a`))), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or <cache>(isnull(`test`.`t3`.`a`))), true)) having (trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true) and trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true)))) AS `(t2.a,t2.a) in (select a,a from t2 as t3)` from `test`.`t1` left join `test`.`t2` on(((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)) where 1
+select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+a a (t2.a,t2.a) in (select a,a from t2 as t3)
+1 NULL NULL
+2 NULL NULL
+
+alter table t2 modify a int;
+two nullable inner cols => no subq materialization
+explain extended select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where (((<cache>(`test`.`t1`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)) and ((<cache>(`test`.`t1`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`))) having (<is_not_null_test>(`test`.`t3`.`a`) and <is_not_null_test>(`test`.`t3`.`a`)))) AS `(t1.a,t1.a) in (select a,a from t2 as t3)` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)
+select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+a a (t1.a,t1.a) in (select a,a from t2 as t3)
+alter table t2 modify a int not null;
+
+Test in WHERE
+
+top-level => subq materialization. With one exception: if
+semijoin is enabled in @@optimizer_switch, semijoin is chosen,
+then rejected (due to outer join), and in that case, the
+fallback is IN->EXISTS, subq-materialization is not tried...
+explain extended select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) in (select a,a from t2 as t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),(`test`.`t2`.`a`,`test`.`t2`.`a`) in ( <materialize> (/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`) and (`test`.`t2`.`a` = `materialized subselect`.`a`))))) and ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 3))
+select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) in (select a,a from t2 as t3);
+a a
+2 1
+1 2
+
+cols not nullable => subq materialization
+explain extended select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) not in (select a,a from t2 as t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where ((not(<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),(`test`.`t2`.`a`,`test`.`t2`.`a`) in ( <materialize> (/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`) and (`test`.`t2`.`a` = `materialized subselect`.`a`))))))) and ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 3))
+select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) not in (select a,a from t2 as t3);
+a a
+drop table t1,t2;
+
+Test of WL6095 "Allow subquery materialization in NOT IN if
+single-column subquery"
+
+create table t1(a int null);
+create table t2(a int null);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+
+one col => subq materialization
+explain extended select a, a in (select a from t2) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `a in (select a from t2)` from `test`.`t1`
+select a, a in (select a from t2) from t1;
+a a in (select a from t2)
+1 1
+2 1
+
+t2.a is not nullable, but in the query it may appear as NULL
+as it's in an outer join. But there is only one inner column so
+materialization is possible
+explain extended select t1.a, t2.a, t2.a in (select * from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select `test`.`t3`.`a` from `test`.`t2` `t3` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`))))) AS `t2.a in (select * from t2 as t3)` from `test`.`t1` left join `test`.`t2` on(((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)) where 1
+select t1.a, t2.a, t2.a in (select * from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+a a t2.a in (select * from t2 as t3)
+1 NULL NULL
+2 NULL NULL
+
+_two_ outer columns, nullable => no materialization
+explain extended select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where (trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)), true)) having (trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true) and trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true)))) AS `(t2.a,t2.a) in (select a,a from t2 as t3)` from `test`.`t1` left join `test`.`t2` on(((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)) where 1
+select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+a a (t2.a,t2.a) in (select a,a from t2 as t3)
+1 NULL NULL
+2 NULL NULL
+drop table t1,t2;
+
+Test in HAVING
+create table t1(a int, b int);
+create table t2(a int);
+insert into t1 values(1,1),(1,2),(1,3),(2,1),(2,2),(2,3);
+insert into t2 values(10),(20);
+no NULLs.
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using temporary; Using filesort
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,`z` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`z` in <temporary table> on distinct_key where ((`z` = `materialized subselect`.`a`))))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+one outer NULL
+insert into t1 values(null,null);
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using temporary; Using filesort
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,`z` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`z` in <temporary table> on distinct_key where ((`z` = `materialized subselect`.`a`))))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+NULL NULL
+one outer NULL and one inner NULL
+insert into t2 values(null);
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using temporary; Using filesort
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,`z` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`z` in <temporary table> on distinct_key where ((`z` = `materialized subselect`.`a`))))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+NULL NULL
+1 6
+2 6
+one inner NULL
+delete from t1 where a is null;
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using temporary; Using filesort
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,`z` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`z` in <temporary table> on distinct_key where ((`z` = `materialized subselect`.`a`))))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+1 6
+2 6
+drop table t1,t2;
+
+Verify that an inner NULL is looked up only once (result is
+cached).
+create table t1(a int);
+create table t2(a int);
+insert into t1 values(1),(2),(3),(4),(5),(6);
+insert into t1 select * from t1;
+insert into t2 values(10),(20),(NULL);
+explain extended select a, (a in (select * from t2)) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 12 100.00
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `(a in (select * from t2))` from `test`.`t1`
+flush status;
+select a, (a in (select * from t2)) from t1;
+a (a in (select * from t2))
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
+6 NULL
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
+6 NULL
+There will be one look-up in the temporary table for each row
+of t1 (12), plus one additional look-up to check whether table
+contains a NULL value.
+show status like "handler_read_key";
+Variable_name Value
+Handler_read_key 13
+drop table t1,t2;
+#
+# Bug#13495157 - SUBQUERY MATERIALIZATION NOT USED FOR CERTAIN
+# STATEMENTS
+#
+CREATE TABLE t1(a INT);
+INSERT INTO t1 VALUES(1),(2),(3);
+CREATE TABLE t2(a INT);
+INSERT INTO t2 VALUES(1),(2),(4);
+# subquery materialization used for SELECT:
+EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where
+SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+a
+1
+# Also used for INSERT SELECT:
+CREATE TABLE t3 SELECT * FROM t1;
+EXPLAIN INSERT INTO t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where
+INSERT INTO t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t3;
+a
+1
+1
+2
+3
+EXPLAIN INSERT INTO t2 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Using temporary
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where
+INSERT INTO t2 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t2;
+a
+1
+1
+2
+4
+EXPLAIN INSERT INTO t2 SELECT * FROM t2 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Using temporary
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 Using where
+INSERT INTO t2 SELECT * FROM t2 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t2;
+a
+1
+1
+1
+1
+2
+4
+4
+# Not used for single-table UPDATE, DELETE:
+EXPLAIN SELECT * FROM t2 WHERE a IN (SELECT * FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3
+EXPLAIN UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t1);
+SELECT * FROM t2;
+a
+0
+0
+0
+0
+1
+4
+4
+EXPLAIN DELETE FROM t2 WHERE a IN (SELECT * FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+DELETE FROM t2 WHERE a IN (SELECT * FROM t1);
+SELECT * FROM t2;
+a
+0
+0
+0
+0
+4
+4
+EXPLAIN UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+EXPLAIN DELETE FROM t2 WHERE a IN (SELECT * FROM t2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+UPDATE t2 SET a=3 WHERE a=0;
+# Used for multi-table UPDATE, DELETE:
+EXPLAIN SELECT * FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 4
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+EXPLAIN UPDATE t2,t3 SET t2.a=t2.a-2 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 4
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+UPDATE t2,t3 SET t2.a=t2.a-2 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+SELECT * FROM t2;
+a
+1
+1
+1
+1
+4
+4
+EXPLAIN DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 4
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+SELECT * FROM t2;
+a
+4
+4
+EXPLAIN UPDATE t2,t3 SET t2.a=10 WHERE t2.a IN (SELECT * FROM t2 WHERE a <> 2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+EXPLAIN DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t2 WHERE a <> 2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+DROP TABLE t1,t2,t3;
+#
+# Test that subquery materialization only does one lookup: does
+# not try to read the next row if the first row failed the
+# subquery's WHERE. We use a case where index lookup is not
+# enough to satisfy IN(), because index has length two when the
+# outer value has length three, and thus the post-filtering
+# WHERE added by subselect_hash_sj_engine::setup() makes the
+# decision.
+#
+create table t1 (a varchar(3));
+create table t2 (a varchar(2));
+insert into t1 values('aaa'), ('aaa');
+insert into t2 values('aa'), ('aa');
+explain select * from t1 where a in (select a from t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2
+flush status;
+select * from t1 where a in (select a from t2);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 1
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 6
+drop table t1,t2;
+#
+# Bug#13655791 DIFFERENT RESULT WITH WL6094 ON QUERY WITH XOR
+# IN WHERE CLAUSE + MYISAM
+#
+CREATE TABLE t1 (
+pk int NOT NULL,
+col_varchar_nokey varchar(1) DEFAULT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t1 VALUES (10,'x');
+CREATE TABLE t2 (
+pk int NOT NULL,
+col_varchar_nokey varchar(1) DEFAULT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t2 VALUES (1,'v'), (5,'x'), (11,'z'), (12,'c'), (15,'y');
+CREATE TABLE t3 (
+pk int NOT NULL,
+col_int_key int DEFAULT NULL,
+PRIMARY KEY (pk),
+KEY col_int_key (col_int_key)
+);
+INSERT INTO t3 VALUES (10,8);
+CREATE TABLE t4 (
+pk int NOT NULL,
+col_varchar_nokey varchar(1) DEFAULT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t4 VALUES (1,'x');
+EXPLAIN SELECT OUTR.pk, OUTR.col_varchar_nokey, OUTR2.col_varchar_nokey
+FROM t2 AS OUTR2
+JOIN t4 AS OUTR
+ON (OUTR2.col_varchar_nokey > OUTR.col_varchar_nokey)
+WHERE
+OUTR.col_varchar_nokey IN (
+SELECT INNR.col_varchar_nokey
+FROM t3 AS INNR2
+LEFT JOIN t1 AS INNR
+ON (INNR2.col_int_key >= INNR.pk)
+)
+XOR OUTR.pk < 6
+;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY OUTR system NULL NULL NULL NULL 1
+1 PRIMARY OUTR2 ALL NULL NULL NULL NULL 5 Using where
+2 SUBQUERY INNR2 system NULL NULL NULL NULL 1
+2 SUBQUERY INNR system PRIMARY NULL NULL NULL 1
+FLUSH STATUS;
+SELECT OUTR.pk, OUTR.col_varchar_nokey, OUTR2.col_varchar_nokey
+FROM t2 AS OUTR2
+JOIN t4 AS OUTR
+ON (OUTR2.col_varchar_nokey > OUTR.col_varchar_nokey)
+WHERE
+OUTR.col_varchar_nokey IN (
+SELECT INNR.col_varchar_nokey
+FROM t3 AS INNR2
+LEFT JOIN t1 AS INNR
+ON (INNR2.col_int_key >= INNR.pk)
+)
+XOR OUTR.pk < 6
+;
+pk col_varchar_nokey col_varchar_nokey
+SHOW STATUS LIKE "HANDLER_READ%";
+Variable_name Value
+Handler_read_first 3
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 9
+DROP TABLE t1,t2,t3,t4;
# End of 5.6 tests
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_mat_all.result'
--- a/mysql-test/r/subquery_mat_all.result 2012-01-20 15:30:14 +0000
+++ b/mysql-test/r/subquery_mat_all.result 2012-02-08 15:25:17 +0000
@@ -1293,5 +1293,485 @@ pk pk
1 NULL
DROP TABLE t1, t2;
# End of test for bug#13607423.
+
+Test of WL#6094 "Allow subquery materialization in NOT IN if all
+columns are not nullable"
+
+create table t1(a int not null);
+create table t2(a int not null);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+Test in SELECT list
+
+cols not nullable => subq materialization
+explain extended select a, (a,a) in (select a,a from t2) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`a`),(`test`.`t1`.`a`,`test`.`t1`.`a`) in ( <materialize> (/* select#2 */ select `test`.`t2`.`a`,`test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`) and (`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `(a,a) in (select a,a from t2)` from `test`.`t1`
+select a, (a,a) in (select a,a from t2) from t1;
+a (a,a) in (select a,a from t2)
+1 1
+2 1
+
+cols not nullable => subq materialization
+explain extended select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`a`),(`test`.`t1`.`a`,`test`.`t1`.`a`) in ( <materialize> (/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`) and (`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `(t1.a,t1.a) in (select a,a from t2 as t3)` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)
+select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+a a (t1.a,t1.a) in (select a,a from t2 as t3)
+
+t2.a is not nullable, but in the query it may appear as NULL
+as it's in an outer join. So, no materialization.
+explain extended select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where (trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or <cache>(isnull(`test`.`t3`.`a`))), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or <cache>(isnull(`test`.`t3`.`a`))), true)) having (trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true) and trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true)))) AS `(t2.a,t2.a) in (select a,a from t2 as t3)` from `test`.`t1` left join `test`.`t2` on(((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)) where 1
+select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+a a (t2.a,t2.a) in (select a,a from t2 as t3)
+1 NULL NULL
+2 NULL NULL
+
+alter table t2 modify a int;
+two nullable inner cols => no subq materialization
+explain extended select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where (((<cache>(`test`.`t1`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)) and ((<cache>(`test`.`t1`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`))) having (<is_not_null_test>(`test`.`t3`.`a`) and <is_not_null_test>(`test`.`t3`.`a`)))) AS `(t1.a,t1.a) in (select a,a from t2 as t3)` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)
+select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+a a (t1.a,t1.a) in (select a,a from t2 as t3)
+alter table t2 modify a int not null;
+
+Test in WHERE
+
+top-level => subq materialization. With one exception: if
+semijoin is enabled in @@optimizer_switch, semijoin is chosen,
+then rejected (due to outer join), and in that case, the
+fallback is IN->EXISTS, subq-materialization is not tried...
+explain extended select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) in (select a,a from t2 as t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) and (<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`)))) and ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 3))
+select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) in (select a,a from t2 as t3);
+a a
+2 1
+1 2
+
+cols not nullable => subq materialization
+explain extended select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) not in (select a,a from t2 as t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where ((not(<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),(`test`.`t2`.`a`,`test`.`t2`.`a`) in ( <materialize> (/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`) and (`test`.`t2`.`a` = `materialized subselect`.`a`))))))) and ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 3))
+select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) not in (select a,a from t2 as t3);
+a a
+drop table t1,t2;
+
+Test of WL6095 "Allow subquery materialization in NOT IN if
+single-column subquery"
+
+create table t1(a int null);
+create table t2(a int null);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+
+one col => subq materialization
+explain extended select a, a in (select a from t2) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `a in (select a from t2)` from `test`.`t1`
+select a, a in (select a from t2) from t1;
+a a in (select a from t2)
+1 1
+2 1
+
+t2.a is not nullable, but in the query it may appear as NULL
+as it's in an outer join. But there is only one inner column so
+materialization is possible
+explain extended select t1.a, t2.a, t2.a in (select * from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (/* select#2 */ select `test`.`t3`.`a` from `test`.`t2` `t3` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`))))) AS `t2.a in (select * from t2 as t3)` from `test`.`t1` left join `test`.`t2` on(((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)) where 1
+select t1.a, t2.a, t2.a in (select * from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+a a t2.a in (select * from t2 as t3)
+1 NULL NULL
+2 NULL NULL
+
+_two_ outer columns, nullable => no materialization
+explain extended select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where (trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)), true)) having (trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true) and trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true)))) AS `(t2.a,t2.a) in (select a,a from t2 as t3)` from `test`.`t1` left join `test`.`t2` on(((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)) where 1
+select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+a a (t2.a,t2.a) in (select a,a from t2 as t3)
+1 NULL NULL
+2 NULL NULL
+drop table t1,t2;
+
+Test in HAVING
+create table t1(a int, b int);
+create table t2(a int);
+insert into t1 values(1,1),(1,2),(1,3),(2,1),(2,2),(2,3);
+insert into t2 values(10),(20);
+no NULLs.
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using temporary; Using filesort
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,`z` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`z` in <temporary table> on distinct_key where ((`z` = `materialized subselect`.`a`))))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+one outer NULL
+insert into t1 values(null,null);
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using temporary; Using filesort
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,`z` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`z` in <temporary table> on distinct_key where ((`z` = `materialized subselect`.`a`))))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+NULL NULL
+one outer NULL and one inner NULL
+insert into t2 values(null);
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using temporary; Using filesort
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,`z` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`z` in <temporary table> on distinct_key where ((`z` = `materialized subselect`.`a`))))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+NULL NULL
+1 6
+2 6
+one inner NULL
+delete from t1 where a is null;
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using temporary; Using filesort
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,`z` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`z` in <temporary table> on distinct_key where ((`z` = `materialized subselect`.`a`))))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+1 6
+2 6
+drop table t1,t2;
+
+Verify that an inner NULL is looked up only once (result is
+cached).
+create table t1(a int);
+create table t2(a int);
+insert into t1 values(1),(2),(3),(4),(5),(6);
+insert into t1 select * from t1;
+insert into t2 values(10),(20),(NULL);
+explain extended select a, (a in (select * from t2)) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 12 100.00
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (/* select#2 */ select `test`.`t2`.`a` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`a`))))) AS `(a in (select * from t2))` from `test`.`t1`
+flush status;
+select a, (a in (select * from t2)) from t1;
+a (a in (select * from t2))
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
+6 NULL
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
+6 NULL
+There will be one look-up in the temporary table for each row
+of t1 (12), plus one additional look-up to check whether table
+contains a NULL value.
+show status like "handler_read_key";
+Variable_name Value
+Handler_read_key 13
+drop table t1,t2;
+#
+# Bug#13495157 - SUBQUERY MATERIALIZATION NOT USED FOR CERTAIN
+# STATEMENTS
+#
+CREATE TABLE t1(a INT);
+INSERT INTO t1 VALUES(1),(2),(3);
+CREATE TABLE t2(a INT);
+INSERT INTO t2 VALUES(1),(2),(4);
+# subquery materialization used for SELECT:
+EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t1); Using join buffer (Block Nested Loop)
+SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+a
+1
+# Also used for INSERT SELECT:
+CREATE TABLE t3 SELECT * FROM t1;
+EXPLAIN INSERT INTO t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t1); Using join buffer (Block Nested Loop)
+INSERT INTO t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t3;
+a
+1
+1
+2
+3
+EXPLAIN INSERT INTO t2 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Using temporary
+1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t1); Using join buffer (Block Nested Loop)
+INSERT INTO t2 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t2;
+a
+1
+1
+2
+4
+EXPLAIN INSERT INTO t2 SELECT * FROM t2 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Using temporary
+1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; FirstMatch(t2); Using join buffer (Block Nested Loop)
+INSERT INTO t2 SELECT * FROM t2 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t2;
+a
+1
+1
+1
+1
+2
+4
+4
+# Not used for single-table UPDATE, DELETE:
+EXPLAIN SELECT * FROM t2 WHERE a IN (SELECT * FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Materialize; Scan
+1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where; Using join buffer (Block Nested Loop)
+EXPLAIN UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t1);
+SELECT * FROM t2;
+a
+0
+0
+0
+0
+1
+4
+4
+EXPLAIN DELETE FROM t2 WHERE a IN (SELECT * FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+DELETE FROM t2 WHERE a IN (SELECT * FROM t1);
+SELECT * FROM t2;
+a
+0
+0
+0
+0
+4
+4
+EXPLAIN UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+EXPLAIN DELETE FROM t2 WHERE a IN (SELECT * FROM t2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+UPDATE t2 SET a=3 WHERE a=0;
+# Used for multi-table UPDATE, DELETE:
+EXPLAIN SELECT * FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Materialize; Scan
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (Block Nested Loop)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 4 Using join buffer (Block Nested Loop)
+EXPLAIN UPDATE t2,t3 SET t2.a=t2.a-2 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Materialize; Scan
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (Block Nested Loop)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 4 Using join buffer (Block Nested Loop)
+UPDATE t2,t3 SET t2.a=t2.a-2 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+SELECT * FROM t2;
+a
+1
+1
+1
+1
+4
+4
+EXPLAIN DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Materialize; Scan
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (Block Nested Loop)
+1 PRIMARY t3 ALL NULL NULL NULL NULL 4 Using join buffer (Block Nested Loop)
+DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+SELECT * FROM t2;
+a
+4
+4
+EXPLAIN UPDATE t2,t3 SET t2.a=10 WHERE t2.a IN (SELECT * FROM t2 WHERE a <> 2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+EXPLAIN DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t2 WHERE a <> 2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+DROP TABLE t1,t2,t3;
+#
+# Test that subquery materialization only does one lookup: does
+# not try to read the next row if the first row failed the
+# subquery's WHERE. We use a case where index lookup is not
+# enough to satisfy IN(), because index has length two when the
+# outer value has length three, and thus the post-filtering
+# WHERE added by subselect_hash_sj_engine::setup() makes the
+# decision.
+#
+create table t1 (a varchar(3));
+create table t2 (a varchar(2));
+insert into t1 values('aaa'), ('aaa');
+insert into t2 values('aa'), ('aa');
+explain select * from t1 where a in (select a from t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; FirstMatch(t1); Using join buffer (Block Nested Loop)
+flush status;
+select * from t1 where a in (select a from t2);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 0
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 6
+drop table t1,t2;
+#
+# Bug#13655791 DIFFERENT RESULT WITH WL6094 ON QUERY WITH XOR
+# IN WHERE CLAUSE + MYISAM
+#
+CREATE TABLE t1 (
+pk int NOT NULL,
+col_varchar_nokey varchar(1) DEFAULT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t1 VALUES (10,'x');
+CREATE TABLE t2 (
+pk int NOT NULL,
+col_varchar_nokey varchar(1) DEFAULT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t2 VALUES (1,'v'), (5,'x'), (11,'z'), (12,'c'), (15,'y');
+CREATE TABLE t3 (
+pk int NOT NULL,
+col_int_key int DEFAULT NULL,
+PRIMARY KEY (pk),
+KEY col_int_key (col_int_key)
+);
+INSERT INTO t3 VALUES (10,8);
+CREATE TABLE t4 (
+pk int NOT NULL,
+col_varchar_nokey varchar(1) DEFAULT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t4 VALUES (1,'x');
+EXPLAIN SELECT OUTR.pk, OUTR.col_varchar_nokey, OUTR2.col_varchar_nokey
+FROM t2 AS OUTR2
+JOIN t4 AS OUTR
+ON (OUTR2.col_varchar_nokey > OUTR.col_varchar_nokey)
+WHERE
+OUTR.col_varchar_nokey IN (
+SELECT INNR.col_varchar_nokey
+FROM t3 AS INNR2
+LEFT JOIN t1 AS INNR
+ON (INNR2.col_int_key >= INNR.pk)
+)
+XOR OUTR.pk < 6
+;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY OUTR system NULL NULL NULL NULL 1
+1 PRIMARY OUTR2 ALL NULL NULL NULL NULL 5 Using where
+2 SUBQUERY INNR2 system NULL NULL NULL NULL 1
+2 SUBQUERY INNR system PRIMARY NULL NULL NULL 1
+FLUSH STATUS;
+SELECT OUTR.pk, OUTR.col_varchar_nokey, OUTR2.col_varchar_nokey
+FROM t2 AS OUTR2
+JOIN t4 AS OUTR
+ON (OUTR2.col_varchar_nokey > OUTR.col_varchar_nokey)
+WHERE
+OUTR.col_varchar_nokey IN (
+SELECT INNR.col_varchar_nokey
+FROM t3 AS INNR2
+LEFT JOIN t1 AS INNR
+ON (INNR2.col_int_key >= INNR.pk)
+)
+XOR OUTR.pk < 6
+;
+pk col_varchar_nokey col_varchar_nokey
+SHOW STATUS LIKE "HANDLER_READ%";
+Variable_name Value
+Handler_read_first 3
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 9
+DROP TABLE t1,t2,t3,t4;
# End of 5.6 tests
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_mat_none.result'
--- a/mysql-test/r/subquery_mat_none.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_mat_none.result 2012-02-08 15:25:17 +0000
@@ -1292,5 +1292,484 @@ pk pk
1 NULL
DROP TABLE t1, t2;
# End of test for bug#13607423.
+
+Test of WL#6094 "Allow subquery materialization in NOT IN if all
+columns are not nullable"
+
+create table t1(a int not null);
+create table t2(a int not null);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+Test in SELECT list
+
+cols not nullable => subq materialization
+explain extended select a, (a,a) in (select a,a from t2) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`a`),<exists>(/* select#2 */ select `test`.`t2`.`a`,`test`.`t2`.`a` from `test`.`t2` where ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`) and (<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`)) having (<is_not_null_test>(`test`.`t2`.`a`) and <is_not_null_test>(`test`.`t2`.`a`)))) AS `(a,a) in (select a,a from t2)` from `test`.`t1`
+select a, (a,a) in (select a,a from t2) from t1;
+a (a,a) in (select a,a from t2)
+1 1
+2 1
+
+cols not nullable => subq materialization
+explain extended select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where ((<cache>(`test`.`t1`.`a`) = `test`.`t3`.`a`) and (<cache>(`test`.`t1`.`a`) = `test`.`t3`.`a`)) having (<is_not_null_test>(`test`.`t3`.`a`) and <is_not_null_test>(`test`.`t3`.`a`)))) AS `(t1.a,t1.a) in (select a,a from t2 as t3)` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)
+select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+a a (t1.a,t1.a) in (select a,a from t2 as t3)
+
+t2.a is not nullable, but in the query it may appear as NULL
+as it's in an outer join. So, no materialization.
+explain extended select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where (trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or <cache>(isnull(`test`.`t3`.`a`))), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or <cache>(isnull(`test`.`t3`.`a`))), true)) having (trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true) and trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true)))) AS `(t2.a,t2.a) in (select a,a from t2 as t3)` from `test`.`t1` left join `test`.`t2` on(((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)) where 1
+select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+a a (t2.a,t2.a) in (select a,a from t2 as t3)
+1 NULL NULL
+2 NULL NULL
+
+alter table t2 modify a int;
+two nullable inner cols => no subq materialization
+explain extended select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t1`.`a`,`test`.`t1`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where (((<cache>(`test`.`t1`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)) and ((<cache>(`test`.`t1`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`))) having (<is_not_null_test>(`test`.`t3`.`a`) and <is_not_null_test>(`test`.`t3`.`a`)))) AS `(t1.a,t1.a) in (select a,a from t2 as t3)` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)
+select t1.a, t2.a, (t1.a,t1.a) in (select a,a from t2 as t3)
+from t1 join t2 on t1.a+t2.a=1000;
+a a (t1.a,t1.a) in (select a,a from t2 as t3)
+alter table t2 modify a int not null;
+
+Test in WHERE
+
+top-level => subq materialization. With one exception: if
+semijoin is enabled in @@optimizer_switch, semijoin is chosen,
+then rejected (due to outer join), and in that case, the
+fallback is IN->EXISTS, subq-materialization is not tried...
+explain extended select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) in (select a,a from t2 as t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where (<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) and (<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`)))) and ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 3))
+select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) in (select a,a from t2 as t3);
+a a
+2 1
+1 2
+
+cols not nullable => subq materialization
+explain extended select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) not in (select a,a from t2 as t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a` from `test`.`t1` join `test`.`t2` where ((not(<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) and (<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`)) having (<is_not_null_test>(`test`.`t3`.`a`) and <is_not_null_test>(`test`.`t3`.`a`)))))) and ((`test`.`t1`.`a` + `test`.`t2`.`a`) = 3))
+select t1.a, t2.a
+from t1 join t2 on t1.a+t2.a=3
+where (t2.a,t2.a) not in (select a,a from t2 as t3);
+a a
+drop table t1,t2;
+
+Test of WL6095 "Allow subquery materialization in NOT IN if
+single-column subquery"
+
+create table t1(a int null);
+create table t2(a int null);
+insert into t1 values(1),(2);
+insert into t2 values(1),(2);
+
+one col => subq materialization
+explain extended select a, a in (select a from t2) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t2` where trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`)), true) having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`a`), true))) AS `a in (select a from t2)` from `test`.`t1`
+select a, a in (select a from t2) from t1;
+a a in (select a from t2)
+1 1
+2 1
+
+t2.a is not nullable, but in the query it may appear as NULL
+as it's in an outer join. But there is only one inner column so
+materialization is possible
+explain extended select t1.a, t2.a, t2.a in (select * from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>(`test`.`t2`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t2` `t3` where trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)), true) having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true))) AS `t2.a in (select * from t2 as t3)` from `test`.`t1` left join `test`.`t2` on(((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)) where 1
+select t1.a, t2.a, t2.a in (select * from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+a a t2.a in (select * from t2 as t3)
+1 NULL NULL
+2 NULL NULL
+
+_two_ outer columns, nullable => no materialization
+explain extended select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a`,<in_optimizer>((`test`.`t2`.`a`,`test`.`t2`.`a`),<exists>(/* select#2 */ select `test`.`t3`.`a`,`test`.`t3`.`a` from `test`.`t2` `t3` where (trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)), true) and trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t2`.`a`) = `test`.`t3`.`a`) or isnull(`test`.`t3`.`a`)), true)) having (trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true) and trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t3`.`a`), true)))) AS `(t2.a,t2.a) in (select a,a from t2 as t3)` from `test`.`t1` left join `test`.`t2` on(((`test`.`t1`.`a` + `test`.`t2`.`a`) = 1000)) where 1
+select t1.a, t2.a, (t2.a,t2.a) in (select a,a from t2 as t3)
+from t1 left join t2 on t1.a+t2.a=1000;
+a a (t2.a,t2.a) in (select a,a from t2 as t3)
+1 NULL NULL
+2 NULL NULL
+drop table t1,t2;
+
+Test in HAVING
+create table t1(a int, b int);
+create table t2(a int);
+insert into t1 values(1,1),(1,2),(1,3),(2,1),(2,2),(2,3);
+insert into t2 values(10),(20);
+no NULLs.
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using temporary; Using filesort
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,<exists>(/* select#2 */ select 1 from `test`.`t2` where trigcond_if(outer_field_is_not_null, ((<cache>(`z`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`)), true) having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`a`), true))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+one outer NULL
+insert into t1 values(null,null);
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using temporary; Using filesort
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,<exists>(/* select#2 */ select 1 from `test`.`t2` where trigcond_if(outer_field_is_not_null, ((<cache>(`z`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`)), true) having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`a`), true))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+NULL NULL
+one outer NULL and one inner NULL
+insert into t2 values(null);
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using temporary; Using filesort
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,<exists>(/* select#2 */ select 1 from `test`.`t2` where trigcond_if(outer_field_is_not_null, ((<cache>(`z`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`)), true) having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`a`), true))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+NULL NULL
+1 6
+2 6
+one inner NULL
+delete from t1 where a is null;
+explain extended select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using temporary; Using filesort
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `z`,sum(`test`.`t1`.`b`) AS `sum(t1.b)` from `test`.`t1` group by `test`.`t1`.`a` having isnull(<in_optimizer>(`z`,<exists>(/* select#2 */ select 1 from `test`.`t2` where trigcond_if(outer_field_is_not_null, ((<cache>(`z`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`)), true) having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`a`), true))))
+select t1.a as z, sum(t1.b) from t1 group by t1.a
+having (z in (select * from t2)) is null;
+z sum(t1.b)
+1 6
+2 6
+drop table t1,t2;
+
+Verify that an inner NULL is looked up only once (result is
+cached).
+create table t1(a int);
+create table t2(a int);
+insert into t1 values(1),(2),(3),(4),(5),(6);
+insert into t1 select * from t1;
+insert into t2 values(10),(20),(NULL);
+explain extended select a, (a in (select * from t2)) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 12 100.00
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(/* select#2 */ select 1 from `test`.`t2` where trigcond_if(outer_field_is_not_null, ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`)), true) having trigcond_if(outer_field_is_not_null, <is_not_null_test>(`test`.`t2`.`a`), true))) AS `(a in (select * from t2))` from `test`.`t1`
+flush status;
+select a, (a in (select * from t2)) from t1;
+a (a in (select * from t2))
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
+6 NULL
+1 NULL
+2 NULL
+3 NULL
+4 NULL
+5 NULL
+6 NULL
+There will be one look-up in the temporary table for each row
+of t1 (12), plus one additional look-up to check whether table
+contains a NULL value.
+show status like "handler_read_key";
+Variable_name Value
+Handler_read_key 0
+drop table t1,t2;
+#
+# Bug#13495157 - SUBQUERY MATERIALIZATION NOT USED FOR CERTAIN
+# STATEMENTS
+#
+CREATE TABLE t1(a INT);
+INSERT INTO t1 VALUES(1),(2),(3);
+CREATE TABLE t2(a INT);
+INSERT INTO t2 VALUES(1),(2),(4);
+# subquery materialization used for SELECT:
+EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where
+SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+a
+1
+# Also used for INSERT SELECT:
+CREATE TABLE t3 SELECT * FROM t1;
+EXPLAIN INSERT INTO t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where
+INSERT INTO t3 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t3;
+a
+1
+1
+2
+3
+EXPLAIN INSERT INTO t2 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Using temporary
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where
+INSERT INTO t2 SELECT * FROM t1 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t2;
+a
+1
+1
+2
+4
+EXPLAIN INSERT INTO t2 SELECT * FROM t2 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Using temporary
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 4 Using where
+INSERT INTO t2 SELECT * FROM t2 WHERE a IN (SELECT * FROM t2 WHERE a <> 2);
+SELECT * FROM t2;
+a
+1
+1
+1
+1
+2
+4
+4
+# Not used for single-table UPDATE, DELETE:
+EXPLAIN SELECT * FROM t2 WHERE a IN (SELECT * FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+EXPLAIN UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t1);
+SELECT * FROM t2;
+a
+0
+0
+0
+0
+1
+4
+4
+EXPLAIN DELETE FROM t2 WHERE a IN (SELECT * FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 ALL NULL NULL NULL NULL 7 Using where
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+DELETE FROM t2 WHERE a IN (SELECT * FROM t1);
+SELECT * FROM t2;
+a
+0
+0
+0
+0
+4
+4
+EXPLAIN UPDATE t2 SET a=a-1 WHERE a IN (SELECT * FROM t2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+EXPLAIN DELETE FROM t2 WHERE a IN (SELECT * FROM t2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+UPDATE t2 SET a=3 WHERE a=0;
+# Used for multi-table UPDATE, DELETE:
+EXPLAIN SELECT * FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 4
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+EXPLAIN UPDATE t2,t3 SET t2.a=t2.a-2 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 4
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+UPDATE t2,t3 SET t2.a=t2.a-2 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+SELECT * FROM t2;
+a
+1
+1
+1
+1
+4
+4
+EXPLAIN DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 4
+1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (Block Nested Loop)
+2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
+DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t1 WHERE a <> 2);
+SELECT * FROM t2;
+a
+4
+4
+EXPLAIN UPDATE t2,t3 SET t2.a=10 WHERE t2.a IN (SELECT * FROM t2 WHERE a <> 2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+EXPLAIN DELETE t2.* FROM t2,t3 WHERE t2.a IN (SELECT * FROM t2 WHERE a <> 2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+DROP TABLE t1,t2,t3;
+#
+# Test that subquery materialization only does one lookup: does
+# not try to read the next row if the first row failed the
+# subquery's WHERE. We use a case where index lookup is not
+# enough to satisfy IN(), because index has length two when the
+# outer value has length three, and thus the post-filtering
+# WHERE added by subselect_hash_sj_engine::setup() makes the
+# decision.
+#
+create table t1 (a varchar(3));
+create table t2 (a varchar(2));
+insert into t1 values('aaa'), ('aaa');
+insert into t2 values('aa'), ('aa');
+explain select * from t1 where a in (select a from t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where
+flush status;
+select * from t1 where a in (select a from t2);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 0
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 9
+drop table t1,t2;
+#
+# Bug#13655791 DIFFERENT RESULT WITH WL6094 ON QUERY WITH XOR
+# IN WHERE CLAUSE + MYISAM
+#
+CREATE TABLE t1 (
+pk int NOT NULL,
+col_varchar_nokey varchar(1) DEFAULT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t1 VALUES (10,'x');
+CREATE TABLE t2 (
+pk int NOT NULL,
+col_varchar_nokey varchar(1) DEFAULT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t2 VALUES (1,'v'), (5,'x'), (11,'z'), (12,'c'), (15,'y');
+CREATE TABLE t3 (
+pk int NOT NULL,
+col_int_key int DEFAULT NULL,
+PRIMARY KEY (pk),
+KEY col_int_key (col_int_key)
+);
+INSERT INTO t3 VALUES (10,8);
+CREATE TABLE t4 (
+pk int NOT NULL,
+col_varchar_nokey varchar(1) DEFAULT NULL,
+PRIMARY KEY (pk)
+);
+INSERT INTO t4 VALUES (1,'x');
+EXPLAIN SELECT OUTR.pk, OUTR.col_varchar_nokey, OUTR2.col_varchar_nokey
+FROM t2 AS OUTR2
+JOIN t4 AS OUTR
+ON (OUTR2.col_varchar_nokey > OUTR.col_varchar_nokey)
+WHERE
+OUTR.col_varchar_nokey IN (
+SELECT INNR.col_varchar_nokey
+FROM t3 AS INNR2
+LEFT JOIN t1 AS INNR
+ON (INNR2.col_int_key >= INNR.pk)
+)
+XOR OUTR.pk < 6
+;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+2 DEPENDENT SUBQUERY INNR2 system NULL NULL NULL NULL 1
+2 DEPENDENT SUBQUERY INNR system PRIMARY NULL NULL NULL 1
+FLUSH STATUS;
+SELECT OUTR.pk, OUTR.col_varchar_nokey, OUTR2.col_varchar_nokey
+FROM t2 AS OUTR2
+JOIN t4 AS OUTR
+ON (OUTR2.col_varchar_nokey > OUTR.col_varchar_nokey)
+WHERE
+OUTR.col_varchar_nokey IN (
+SELECT INNR.col_varchar_nokey
+FROM t3 AS INNR2
+LEFT JOIN t1 AS INNR
+ON (INNR2.col_int_key >= INNR.pk)
+)
+XOR OUTR.pk < 6
+;
+pk col_varchar_nokey col_varchar_nokey
+SHOW STATUS LIKE "HANDLER_READ%";
+Variable_name Value
+Handler_read_first 3
+Handler_read_key 0
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 3
+DROP TABLE t1,t2,t3,t4;
# End of 5.6 tests
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_nomat_nosj.result'
--- a/mysql-test/r/subquery_nomat_nosj.result 2012-02-07 14:50:31 +0000
+++ b/mysql-test/r/subquery_nomat_nosj.result 2012-02-08 15:25:17 +0000
@@ -4180,7 +4180,7 @@ CREATE TABLE t1 (pk int PRIMARY KEY, int
INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
-# should have eq_ref for t1
+# should have eq_ref for t1, unless subquery materialization is used
EXPLAIN
SELECT * FROM t2 outr
WHERE outr.int_key NOT IN (SELECT t1.pk FROM t1, t2)
@@ -7080,4 +7080,31 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey
DROP TABLE t1,t2;
+#
+# Test that indexsubquery_engine only does one lookup if
+# the technique is unique_subquery: does not try to read the
+# next row if the first row failed the subquery's WHERE
+# condition (here: b=3).
+#
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+explain select * from t1 where a in (select a from t2 where b=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using where
+flush status;
+select * from t1 where a in (select a from t2 where b=3);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 3
+drop table t1,t2;
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_nomat_nosj_bka.result'
--- a/mysql-test/r/subquery_nomat_nosj_bka.result 2012-02-07 14:50:31 +0000
+++ b/mysql-test/r/subquery_nomat_nosj_bka.result 2012-02-08 15:25:17 +0000
@@ -4181,7 +4181,7 @@ CREATE TABLE t1 (pk int PRIMARY KEY, int
INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
-# should have eq_ref for t1
+# should have eq_ref for t1, unless subquery materialization is used
EXPLAIN
SELECT * FROM t2 outr
WHERE outr.int_key NOT IN (SELECT t1.pk FROM t1, t2)
@@ -7081,5 +7081,32 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey
DROP TABLE t1,t2;
+#
+# Test that indexsubquery_engine only does one lookup if
+# the technique is unique_subquery: does not try to read the
+# next row if the first row failed the subquery's WHERE
+# condition (here: b=3).
+#
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+explain select * from t1 where a in (select a from t2 where b=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using where
+flush status;
+select * from t1 where a in (select a from t2 where b=3);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 3
+drop table t1,t2;
set optimizer_switch=default;
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_nomat_nosj_bka_nixbnl.result'
--- a/mysql-test/r/subquery_nomat_nosj_bka_nixbnl.result 2012-02-07 14:50:31 +0000
+++ b/mysql-test/r/subquery_nomat_nosj_bka_nixbnl.result 2012-02-08 15:25:17 +0000
@@ -4181,7 +4181,7 @@ CREATE TABLE t1 (pk int PRIMARY KEY, int
INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
-# should have eq_ref for t1
+# should have eq_ref for t1, unless subquery materialization is used
EXPLAIN
SELECT * FROM t2 outr
WHERE outr.int_key NOT IN (SELECT t1.pk FROM t1, t2)
@@ -7081,5 +7081,32 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey
DROP TABLE t1,t2;
+#
+# Test that indexsubquery_engine only does one lookup if
+# the technique is unique_subquery: does not try to read the
+# next row if the first row failed the subquery's WHERE
+# condition (here: b=3).
+#
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+explain select * from t1 where a in (select a from t2 where b=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using where
+flush status;
+select * from t1 where a in (select a from t2 where b=3);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 3
+drop table t1,t2;
set optimizer_switch=default;
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_none.result'
--- a/mysql-test/r/subquery_none.result 2012-02-07 14:50:31 +0000
+++ b/mysql-test/r/subquery_none.result 2012-02-08 15:25:17 +0000
@@ -4179,7 +4179,7 @@ CREATE TABLE t1 (pk int PRIMARY KEY, int
INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
-# should have eq_ref for t1
+# should have eq_ref for t1, unless subquery materialization is used
EXPLAIN
SELECT * FROM t2 outr
WHERE outr.int_key NOT IN (SELECT t1.pk FROM t1, t2)
@@ -7079,4 +7079,31 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey
DROP TABLE t1,t2;
+#
+# Test that indexsubquery_engine only does one lookup if
+# the technique is unique_subquery: does not try to read the
+# next row if the first row failed the subquery's WHERE
+# condition (here: b=3).
+#
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+explain select * from t1 where a in (select a from t2 where b=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using where
+flush status;
+select * from t1 where a in (select a from t2 where b=3);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 3
+drop table t1,t2;
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_none_bka.result'
--- a/mysql-test/r/subquery_none_bka.result 2012-02-07 14:50:31 +0000
+++ b/mysql-test/r/subquery_none_bka.result 2012-02-08 15:25:17 +0000
@@ -4180,7 +4180,7 @@ CREATE TABLE t1 (pk int PRIMARY KEY, int
INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
-# should have eq_ref for t1
+# should have eq_ref for t1, unless subquery materialization is used
EXPLAIN
SELECT * FROM t2 outr
WHERE outr.int_key NOT IN (SELECT t1.pk FROM t1, t2)
@@ -7080,5 +7080,32 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey
DROP TABLE t1,t2;
+#
+# Test that indexsubquery_engine only does one lookup if
+# the technique is unique_subquery: does not try to read the
+# next row if the first row failed the subquery's WHERE
+# condition (here: b=3).
+#
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+explain select * from t1 where a in (select a from t2 where b=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using where
+flush status;
+select * from t1 where a in (select a from t2 where b=3);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 3
+drop table t1,t2;
set optimizer_switch=default;
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_none_bka_nixbnl.result'
--- a/mysql-test/r/subquery_none_bka_nixbnl.result 2012-02-07 14:50:31 +0000
+++ b/mysql-test/r/subquery_none_bka_nixbnl.result 2012-02-08 15:25:17 +0000
@@ -4180,7 +4180,7 @@ CREATE TABLE t1 (pk int PRIMARY KEY, int
INSERT INTO t1 VALUES (10,1), (14,1);
CREATE TABLE t2 (pk int PRIMARY KEY, int_key int);
INSERT INTO t2 VALUES (3,3), (5,NULL), (7,3);
-# should have eq_ref for t1
+# should have eq_ref for t1, unless subquery materialization is used
EXPLAIN
SELECT * FROM t2 outr
WHERE outr.int_key NOT IN (SELECT t1.pk FROM t1, t2)
@@ -7080,5 +7080,32 @@ WHERE (c_sq1_alias1.col_int_nokey != @va
OR c_sq1_alias1.pk != @var3)) ) AS alias3;
pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey
DROP TABLE t1,t2;
+#
+# Test that indexsubquery_engine only does one lookup if
+# the technique is unique_subquery: does not try to read the
+# next row if the first row failed the subquery's WHERE
+# condition (here: b=3).
+#
+create table t1(a int);
+insert into t1 values(1),(2);
+create table t2(a int primary key, b int);
+insert into t2 values(1,10),(2,10);
+explain select * from t1 where a in (select a from t2 where b=3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using where
+flush status;
+select * from t1 where a in (select a from t2 where b=3);
+a
+show status like "handler_read%";
+Variable_name Value
+Handler_read_first 0
+Handler_read_key 2
+Handler_read_last 0
+Handler_read_next 0
+Handler_read_prev 0
+Handler_read_rnd 0
+Handler_read_rnd_next 3
+drop table t1,t2;
set optimizer_switch=default;
set optimizer_switch=default;
=== modified file 'mysql-test/r/subquery_sj_all.result'
--- a/mysql-test/r/subquery_sj_all.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_sj_all.result 2012-02-08 15:25:17 +0000
@@ -6706,9 +6706,9 @@ AND grandparent1.col_varchar_key IS NOT
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
-2 DEPENDENT SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
-2 DEPENDENT SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using index condition; Using where; End temporary
+2 SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
+2 SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
+2 SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using index condition; End temporary
SELECT *
FROM t1
WHERE g1 NOT IN
@@ -7091,10 +7091,10 @@ ON parent1.col_int_nokey = parent2.col_i
AND grandparent1.col_int_key <> 3
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY parent1 ref col_int_key col_int_key 4 func 2 Using index condition; Start temporary
-2 DEPENDENT SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; Using join buffer (Block Nested Loop)
-2 DEPENDENT SUBQUERY grandparent1 ref col_int_key col_int_key 4 func 2 Using index condition; Using where; End temporary
+1 PRIMARY t3 system NULL NULL NULL NULL 1
+2 SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
+2 SUBQUERY parent1 ALL col_int_key NULL NULL NULL 11 Start materialize
+2 SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; End materialize; Using join buffer (Block Nested Loop)
SELECT * FROM t3
WHERE g1 NOT IN
(SELECT grandparent1.col_int_nokey AS g1
=== modified file 'mysql-test/r/subquery_sj_all_bka.result'
--- a/mysql-test/r/subquery_sj_all_bka.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_sj_all_bka.result 2012-02-08 15:25:17 +0000
@@ -6707,9 +6707,9 @@ AND grandparent1.col_varchar_key IS NOT
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
-2 DEPENDENT SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
-2 DEPENDENT SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using index condition; Using where; End temporary; Using join buffer (Batched Key Access)
+2 SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
+2 SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
+2 SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using index condition; End temporary; Using join buffer (Batched Key Access)
SELECT *
FROM t1
WHERE g1 NOT IN
@@ -7092,10 +7092,10 @@ ON parent1.col_int_nokey = parent2.col_i
AND grandparent1.col_int_key <> 3
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY parent1 ref col_int_key col_int_key 4 func 2 Using index condition; Start temporary
-2 DEPENDENT SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; Using join buffer (Block Nested Loop)
-2 DEPENDENT SUBQUERY grandparent1 ref col_int_key col_int_key 4 func 2 Using index condition; Using where; End temporary; Using join buffer (Batched Key Access)
+1 PRIMARY t3 system NULL NULL NULL NULL 1
+2 SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
+2 SUBQUERY parent1 ALL col_int_key NULL NULL NULL 11 Start materialize
+2 SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; End materialize; Using join buffer (Block Nested Loop)
SELECT * FROM t3
WHERE g1 NOT IN
(SELECT grandparent1.col_int_nokey AS g1
=== modified file 'mysql-test/r/subquery_sj_all_bka_nixbnl.result'
--- a/mysql-test/r/subquery_sj_all_bka_nixbnl.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_sj_all_bka_nixbnl.result 2012-02-08 15:25:17 +0000
@@ -6707,9 +6707,9 @@ AND grandparent1.col_varchar_key IS NOT
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
-2 DEPENDENT SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
-2 DEPENDENT SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using index condition; Using where; End temporary; Using join buffer (Batched Key Access)
+2 SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
+2 SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
+2 SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using index condition; End temporary; Using join buffer (Batched Key Access)
SELECT *
FROM t1
WHERE g1 NOT IN
@@ -7092,10 +7092,10 @@ ON parent1.col_int_nokey = parent2.col_i
AND grandparent1.col_int_key <> 3
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY grandparent1 ref col_int_key col_int_key 4 func 2 Using index condition; Using where
-2 DEPENDENT SUBQUERY parent1 ref col_int_key col_int_key 4 func 2 Using index condition
-2 DEPENDENT SUBQUERY parent2 ref col_int_key col_int_key 4 test.parent1.col_int_nokey 2 Using index; FirstMatch(grandparent1)
+1 PRIMARY t3 system NULL NULL NULL NULL 1
+2 SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
+2 SUBQUERY parent1 ALL col_int_key NULL NULL NULL 11 Start materialize
+2 SUBQUERY parent2 ref col_int_key col_int_key 4 test.parent1.col_int_nokey 2 Using index; End materialize
SELECT * FROM t3
WHERE g1 NOT IN
(SELECT grandparent1.col_int_nokey AS g1
=== modified file 'mysql-test/r/subquery_sj_all_bkaunique.result'
--- a/mysql-test/r/subquery_sj_all_bkaunique.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_sj_all_bkaunique.result 2012-02-08 15:25:17 +0000
@@ -6708,9 +6708,9 @@ AND grandparent1.col_varchar_key IS NOT
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
-2 DEPENDENT SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
-2 DEPENDENT SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using index condition; Using where; End temporary; Using join buffer (Batched Key Access (unique))
+2 SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
+2 SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
+2 SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using index condition; End temporary; Using join buffer (Batched Key Access (unique))
SELECT *
FROM t1
WHERE g1 NOT IN
@@ -7093,10 +7093,10 @@ ON parent1.col_int_nokey = parent2.col_i
AND grandparent1.col_int_key <> 3
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY parent1 ref col_int_key col_int_key 4 func 2 Using index condition; Start temporary
-2 DEPENDENT SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; Using join buffer (Block Nested Loop)
-2 DEPENDENT SUBQUERY grandparent1 ref col_int_key col_int_key 4 func 2 Using index condition; Using where; End temporary; Using join buffer (Batched Key Access (unique))
+1 PRIMARY t3 system NULL NULL NULL NULL 1
+2 SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
+2 SUBQUERY parent1 ALL col_int_key NULL NULL NULL 11 Start materialize
+2 SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; End materialize; Using join buffer (Block Nested Loop)
SELECT * FROM t3
WHERE g1 NOT IN
(SELECT grandparent1.col_int_nokey AS g1
=== modified file 'mysql-test/r/subquery_sj_mat.result'
--- a/mysql-test/r/subquery_sj_mat.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_sj_mat.result 2012-02-08 15:25:17 +0000
@@ -6706,9 +6706,9 @@ AND grandparent1.col_varchar_key IS NOT
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
-2 DEPENDENT SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
-2 DEPENDENT SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using where; End temporary
+2 SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
+2 SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
+2 SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using where; End temporary
SELECT *
FROM t1
WHERE g1 NOT IN
@@ -7091,10 +7091,10 @@ ON parent1.col_int_nokey = parent2.col_i
AND grandparent1.col_int_key <> 3
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY parent1 ref col_int_key col_int_key 4 func 2 Using where; Start temporary
-2 DEPENDENT SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; Using join buffer (Block Nested Loop)
-2 DEPENDENT SUBQUERY grandparent1 ref col_int_key col_int_key 4 func 2 Using where; End temporary
+1 PRIMARY t3 system NULL NULL NULL NULL 1
+2 SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
+2 SUBQUERY parent1 ALL col_int_key NULL NULL NULL 11 Start materialize
+2 SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; End materialize; Using join buffer (Block Nested Loop)
SELECT * FROM t3
WHERE g1 NOT IN
(SELECT grandparent1.col_int_nokey AS g1
=== modified file 'mysql-test/r/subquery_sj_mat_bka.result'
--- a/mysql-test/r/subquery_sj_mat_bka.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_sj_mat_bka.result 2012-02-08 15:25:17 +0000
@@ -6707,9 +6707,9 @@ AND grandparent1.col_varchar_key IS NOT
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
-2 DEPENDENT SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
-2 DEPENDENT SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using where; End temporary
+2 SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
+2 SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
+2 SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using where; End temporary
SELECT *
FROM t1
WHERE g1 NOT IN
@@ -7092,10 +7092,10 @@ ON parent1.col_int_nokey = parent2.col_i
AND grandparent1.col_int_key <> 3
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY parent1 ref col_int_key col_int_key 4 func 2 Using where; Start temporary
-2 DEPENDENT SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; Using join buffer (Block Nested Loop)
-2 DEPENDENT SUBQUERY grandparent1 ref col_int_key col_int_key 4 func 2 Using where; End temporary
+1 PRIMARY t3 system NULL NULL NULL NULL 1
+2 SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
+2 SUBQUERY parent1 ALL col_int_key NULL NULL NULL 11 Start materialize
+2 SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; End materialize; Using join buffer (Block Nested Loop)
SELECT * FROM t3
WHERE g1 NOT IN
(SELECT grandparent1.col_int_nokey AS g1
=== modified file 'mysql-test/r/subquery_sj_mat_bka_nixbnl.result'
--- a/mysql-test/r/subquery_sj_mat_bka_nixbnl.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_sj_mat_bka_nixbnl.result 2012-02-08 15:25:17 +0000
@@ -6707,9 +6707,9 @@ AND grandparent1.col_varchar_key IS NOT
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
-2 DEPENDENT SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
-2 DEPENDENT SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using where; End temporary
+2 SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
+2 SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
+2 SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using where; End temporary
SELECT *
FROM t1
WHERE g1 NOT IN
@@ -7092,10 +7092,10 @@ ON parent1.col_int_nokey = parent2.col_i
AND grandparent1.col_int_key <> 3
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY grandparent1 ref col_int_key col_int_key 4 func 2 Using where; Start temporary
-2 DEPENDENT SUBQUERY parent1 ref col_int_key col_int_key 4 func 2 Using where
-2 DEPENDENT SUBQUERY parent2 ref col_int_key col_int_key 4 test.parent1.col_int_nokey 2 Using index; End temporary
+1 PRIMARY t3 system NULL NULL NULL NULL 1
+2 SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
+2 SUBQUERY parent1 ALL col_int_key NULL NULL NULL 11 Start materialize
+2 SUBQUERY parent2 ref col_int_key col_int_key 4 test.parent1.col_int_nokey 2 Using index; End materialize
SELECT * FROM t3
WHERE g1 NOT IN
(SELECT grandparent1.col_int_nokey AS g1
=== modified file 'mysql-test/r/subquery_sj_mat_bkaunique.result'
--- a/mysql-test/r/subquery_sj_mat_bkaunique.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_sj_mat_bkaunique.result 2012-02-08 15:25:17 +0000
@@ -6708,9 +6708,9 @@ AND grandparent1.col_varchar_key IS NOT
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
-2 DEPENDENT SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
-2 DEPENDENT SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using where; End temporary
+2 SUBQUERY parent1 ALL NULL NULL NULL NULL 20 Start temporary
+2 SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
+2 SUBQUERY grandparent1 ref col_varchar_key col_varchar_key 3 test.parent1.col_varchar_nokey 1 Using where; End temporary
SELECT *
FROM t1
WHERE g1 NOT IN
@@ -7093,10 +7093,10 @@ ON parent1.col_int_nokey = parent2.col_i
AND grandparent1.col_int_key <> 3
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY parent1 ref col_int_key col_int_key 4 func 2 Using where; Start temporary
-2 DEPENDENT SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; Using join buffer (Block Nested Loop)
-2 DEPENDENT SUBQUERY grandparent1 ref col_int_key col_int_key 4 func 2 Using where; End temporary
+1 PRIMARY t3 system NULL NULL NULL NULL 1
+2 SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
+2 SUBQUERY parent1 ALL col_int_key NULL NULL NULL 11 Start materialize
+2 SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; End materialize; Using join buffer (Block Nested Loop)
SELECT * FROM t3
WHERE g1 NOT IN
(SELECT grandparent1.col_int_nokey AS g1
=== modified file 'mysql-test/r/subquery_sj_mat_nosj.result'
--- a/mysql-test/r/subquery_sj_mat_nosj.result 2012-01-31 11:19:25 +0000
+++ b/mysql-test/r/subquery_sj_mat_nosj.result 2012-02-08 15:25:17 +0000
@@ -6782,7 +6782,7 @@ AND grandparent1.col_varchar_key IS NOT
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY grandparent1 ALL col_varchar_key NULL NULL NULL 20 Using where
+2 SUBQUERY grandparent1 ALL col_varchar_key NULL NULL NULL 20 Using where
3 SUBQUERY parent1 ALL NULL NULL NULL NULL 20
3 SUBQUERY parent2 eq_ref PRIMARY PRIMARY 4 test.parent1.pk 1 Using index
SELECT *
@@ -7167,8 +7167,8 @@ ON parent1.col_int_nokey = parent2.col_i
AND grandparent1.col_int_key <> 3
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
+1 PRIMARY t3 system NULL NULL NULL NULL 1
+2 SUBQUERY grandparent1 ALL col_int_key NULL NULL NULL 11 Using where
3 SUBQUERY parent1 ALL NULL NULL NULL NULL 11
3 SUBQUERY parent2 index col_int_key col_int_key 4 NULL 1 Using where; Using index; Using join buffer (Block Nested Loop)
SELECT * FROM t3
=== modified file 'mysql-test/suite/innodb/r/innodb_mysql.result'
--- a/mysql-test/suite/innodb/r/innodb_mysql.result 2012-01-30 13:13:15 +0000
+++ b/mysql-test/suite/innodb/r/innodb_mysql.result 2012-02-08 15:25:17 +0000
@@ -1436,7 +1436,8 @@ explain
select b from t1 where a not in (select b from t1,t2 group by a) group by a;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
-2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+2 SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 1
DROP TABLE t1,t2;
End of 5.0 tests
CREATE TABLE `t2` (
=== modified file 'mysql-test/suite/opt_trace/include/general.inc'
--- a/mysql-test/suite/opt_trace/include/general.inc 2011-11-18 14:51:40 +0000
+++ b/mysql-test/suite/opt_trace/include/general.inc 2012-02-08 15:25:17 +0000
@@ -82,12 +82,12 @@ select * from information_schema.OPTIMIZ
select (@query:=QUERY)+NULL, (@trace:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
select length(@trace);
# The concatenation of query and trace above has length:
-# - >13900 in normal mode
-# - <13900 in ps-protocol mode (because IN->EXISTS is done at PREPARE
+# - >14100 in normal mode
+# - <14100 in ps-protocol mode (because IN->EXISTS is done at PREPARE
# and we trace only EXECUTE)
# - So in normal mode, the lines below verify truncation,
# whereas in ps-protocol mode they verify non-truncation.
-set optimizer_trace_max_mem_size=13900;
+set optimizer_trace_max_mem_size=14100;
select length(@query)+length(@trace) > @@optimizer_trace_max_mem_size;
SELECT * FROM t5 WHERE 5 IN (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null));
select (@missing_bytes:=missing_bytes_beyond_max_mem_size) from information_schema.OPTIMIZER_TRACE;
=== modified file 'mysql-test/suite/opt_trace/r/bugs_no_prot_all.result'
--- a/mysql-test/suite/opt_trace/r/bugs_no_prot_all.result 2012-01-30 13:13:15 +0000
+++ b/mysql-test/suite/opt_trace/r/bugs_no_prot_all.result 2012-02-08 15:25:17 +0000
@@ -190,7 +190,10 @@ WHERE sq2_alias1.col_varchar_nokey <= al
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": false,
+ "chosen": false,
+ "cause": "cannot_handle_partial_matches"
} /* transformation */
},
{
=== modified file 'mysql-test/suite/opt_trace/r/bugs_no_prot_none.result'
--- a/mysql-test/suite/opt_trace/r/bugs_no_prot_none.result 2012-01-26 13:09:59 +0000
+++ b/mysql-test/suite/opt_trace/r/bugs_no_prot_none.result 2012-02-08 15:25:17 +0000
@@ -174,14 +174,6 @@ WHERE sq2_alias1.col_varchar_nokey <= al
"transformation": {
"select#": 4,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 4,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -206,14 +198,6 @@ WHERE sq2_alias1.col_varchar_nokey <= al
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -383,14 +367,6 @@ FROM t1
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -823,14 +799,6 @@ ON table2 .col_int_key = table1 .col_int
"transformation": {
"select#": 3,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 3,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
=== modified file 'mysql-test/suite/opt_trace/r/bugs_ps_prot_all.result'
--- a/mysql-test/suite/opt_trace/r/bugs_ps_prot_all.result 2012-01-30 13:13:15 +0000
+++ b/mysql-test/suite/opt_trace/r/bugs_ps_prot_all.result 2012-02-08 15:25:17 +0000
@@ -190,7 +190,10 @@ WHERE sq2_alias1.col_varchar_nokey <= al
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": false,
+ "chosen": false,
+ "cause": "cannot_handle_partial_matches"
} /* transformation */
},
{
=== modified file 'mysql-test/suite/opt_trace/r/bugs_ps_prot_none.result'
--- a/mysql-test/suite/opt_trace/r/bugs_ps_prot_none.result 2012-01-30 08:57:24 +0000
+++ b/mysql-test/suite/opt_trace/r/bugs_ps_prot_none.result 2012-02-08 15:25:17 +0000
@@ -174,14 +174,6 @@ WHERE sq2_alias1.col_varchar_nokey <= al
"transformation": {
"select#": 4,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 4,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -206,14 +198,6 @@ WHERE sq2_alias1.col_varchar_nokey <= al
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -378,14 +362,6 @@ FROM t1
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -808,14 +784,6 @@ ON table2 .col_int_key = table1 .col_int
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 3,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
=== modified file 'mysql-test/suite/opt_trace/r/general2_no_prot.result'
--- a/mysql-test/suite/opt_trace/r/general2_no_prot.result 2012-01-26 13:09:59 +0000
+++ b/mysql-test/suite/opt_trace/r/general2_no_prot.result 2012-02-08 15:25:17 +0000
@@ -704,7 +704,10 @@ TRACE
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": false,
+ "chosen": false,
+ "cause": "cannot_handle_partial_matches"
} /* transformation */
},
{
@@ -2653,14 +2656,6 @@ from t0 where a in
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
=== modified file 'mysql-test/suite/opt_trace/r/general2_ps_prot.result'
--- a/mysql-test/suite/opt_trace/r/general2_ps_prot.result 2012-01-30 08:57:24 +0000
+++ b/mysql-test/suite/opt_trace/r/general2_ps_prot.result 2012-02-08 15:25:17 +0000
@@ -732,7 +732,8 @@ TRACE
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "already have strategy"
} /* transformation */
}
] /* steps */
@@ -2706,14 +2707,6 @@ from t0 where a in
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
=== modified file 'mysql-test/suite/opt_trace/r/general_no_prot_all.result'
--- a/mysql-test/suite/opt_trace/r/general_no_prot_all.result 2012-01-26 13:09:59 +0000
+++ b/mysql-test/suite/opt_trace/r/general_no_prot_all.result 2012-02-08 15:25:17 +0000
@@ -1005,7 +1005,8 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "in UNION"
} /* transformation */
},
{
@@ -1041,7 +1042,8 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"select#": 3,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "in UNION"
} /* transformation */
},
{
@@ -1230,7 +1232,8 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"select#": "fake",
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "in UNION"
} /* transformation */
}
] /* steps */
@@ -1341,8 +1344,8 @@ select (@query:=QUERY)+NULL, (@trace:=TR
NULL NULL
select length(@trace);
length(@trace)
-14543
-set optimizer_trace_max_mem_size=13900;
+14672
+set optimizer_trace_max_mem_size=14100;
select length(@query)+length(@trace) > @@optimizer_trace_max_mem_size;
length(@query)+length(@trace) > @@optimizer_trace_max_mem_size
1
@@ -1350,7 +1353,7 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
c
select (@missing_bytes:=missing_bytes_beyond_max_mem_size) from information_schema.OPTIMIZER_TRACE;
(@missing_bytes:=missing_bytes_beyond_max_mem_size)
-761
+681
select (@query2:=QUERY)+NULL,(@trace2:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
(@query2:=QUERY)+NULL (@trace2:=TRACE)+NULL
NULL NULL
@@ -1358,7 +1361,7 @@ select length(@trace2),
(length(@trace2) + @missing_bytes) = length(@trace),
@query2 = @query;
length(@trace2) (length(@trace2) + @missing_bytes) = length(@trace) @query2 = @query
-13782 1 1
+13991 1 1
select length(@query2) + length(@trace2)
between (@@optimizer_trace_max_mem_size-200) and (@@optimizer_trace_max_mem_size+200);
length(@query2) + length(@trace2)
@@ -1721,6 +1724,8 @@ explain SELECT c FROM t5 where c+1 in (s
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": true,
"chosen": true
} /* transformation */
}
@@ -2504,14 +2509,6 @@ explain extended select * from t1 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -2780,14 +2777,6 @@ explain extended select * from t1 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -3395,7 +3384,7 @@ where a1 in (select b1 from t2_16 where
"from": "IN (SELECT)",
"to": "materialization",
"chosen": false,
- "cause": "field_types"
+ "cause": "inner blob"
} /* transformation */
},
{
@@ -4420,6 +4409,8 @@ concat(c1,'y') IN
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": true,
"chosen": true
} /* transformation */
}
@@ -4446,6 +4437,8 @@ concat(c1,'y') IN
"select#": 3,
"from": "IN (SELECT)",
"to": "materialization",
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": true,
"chosen": true
} /* transformation */
}
@@ -6101,7 +6094,10 @@ select * from t1 where (t1.a,t1.b) not i
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": false,
+ "chosen": false,
+ "cause": "cannot_handle_partial_matches"
} /* transformation */
},
{
=== modified file 'mysql-test/suite/opt_trace/r/general_no_prot_none.result'
--- a/mysql-test/suite/opt_trace/r/general_no_prot_none.result 2012-01-26 13:09:59 +0000
+++ b/mysql-test/suite/opt_trace/r/general_no_prot_none.result 2012-02-08 15:25:17 +0000
@@ -1003,14 +1003,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -1039,14 +1031,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"transformation": {
"select#": 3,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 3,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -1223,14 +1207,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": "fake",
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -1340,16 +1316,16 @@ select (@query:=QUERY)+NULL, (@trace:=TR
NULL NULL
select length(@trace);
length(@trace)
-14543
-set optimizer_trace_max_mem_size=13900;
+13668
+set optimizer_trace_max_mem_size=14100;
select length(@query)+length(@trace) > @@optimizer_trace_max_mem_size;
length(@query)+length(@trace) > @@optimizer_trace_max_mem_size
-1
+0
SELECT * FROM t5 WHERE 5 IN (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null));
c
select (@missing_bytes:=missing_bytes_beyond_max_mem_size) from information_schema.OPTIMIZER_TRACE;
(@missing_bytes:=missing_bytes_beyond_max_mem_size)
-761
+0
select (@query2:=QUERY)+NULL,(@trace2:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
(@query2:=QUERY)+NULL (@trace2:=TRACE)+NULL
NULL NULL
@@ -1357,12 +1333,12 @@ select length(@trace2),
(length(@trace2) + @missing_bytes) = length(@trace),
@query2 = @query;
length(@trace2) (length(@trace2) + @missing_bytes) = length(@trace) @query2 = @query
-13782 1 1
+13668 1 1
select length(@query2) + length(@trace2)
between (@@optimizer_trace_max_mem_size-200) and (@@optimizer_trace_max_mem_size+200);
length(@query2) + length(@trace2)
between (@@optimizer_trace_max_mem_size-200) and (@@optimizer_trace_max_mem_size+200)
-1
+0
select instr(@trace, @trace2) = 1;
instr(@trace, @trace2) = 1
1
@@ -1412,14 +1388,6 @@ explain SELECT c FROM t5 where c+1 in (s
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -1702,14 +1670,6 @@ explain SELECT c FROM t5 where c+1 in (s
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -2465,14 +2425,6 @@ explain extended select * from t1 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -2741,14 +2693,6 @@ explain extended select * from t1 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -3354,14 +3298,6 @@ where a1 in (select b1 from t2_16 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -3639,14 +3575,6 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -4378,14 +4306,6 @@ concat(c1,'y') IN
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -4414,14 +4334,6 @@ concat(c1,'y') IN
"transformation": {
"select#": 3,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 3,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -4884,14 +4796,6 @@ trace
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -4933,14 +4837,6 @@ trace
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -5047,14 +4943,6 @@ trace
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -5356,14 +5244,6 @@ select * from t1 where (t1.a,t1.b) not i
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -7420,14 +7300,6 @@ select d into res from t6 where d in (se
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -9184,14 +9056,6 @@ select d into res from t6 where d in (se
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
=== modified file 'mysql-test/suite/opt_trace/r/general_ps_prot_all.result'
--- a/mysql-test/suite/opt_trace/r/general_ps_prot_all.result 2012-01-30 08:57:24 +0000
+++ b/mysql-test/suite/opt_trace/r/general_ps_prot_all.result 2012-02-08 15:25:17 +0000
@@ -1005,7 +1005,8 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "in UNION"
} /* transformation */
}
] /* steps */
@@ -1031,7 +1032,8 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"select#": 3,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "in UNION"
} /* transformation */
}
] /* steps */
@@ -1210,7 +1212,8 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"select#": "fake",
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "in UNION"
} /* transformation */
}
] /* steps */
@@ -1321,8 +1324,8 @@ select (@query:=QUERY)+NULL, (@trace:=TR
NULL NULL
select length(@trace);
length(@trace)
-13765
-set optimizer_trace_max_mem_size=13900;
+13894
+set optimizer_trace_max_mem_size=14100;
select length(@query)+length(@trace) > @@optimizer_trace_max_mem_size;
length(@query)+length(@trace) > @@optimizer_trace_max_mem_size
0
@@ -1338,7 +1341,7 @@ select length(@trace2),
(length(@trace2) + @missing_bytes) = length(@trace),
@query2 = @query;
length(@trace2) (length(@trace2) + @missing_bytes) = length(@trace) @query2 = @query
-13765 1 1
+13894 1 1
select length(@query2) + length(@trace2)
between (@@optimizer_trace_max_mem_size-200) and (@@optimizer_trace_max_mem_size+200);
length(@query2) + length(@trace2)
@@ -1701,6 +1704,8 @@ explain SELECT c FROM t5 where c+1 in (s
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": true,
"chosen": true
} /* transformation */
}
@@ -2484,14 +2489,6 @@ explain extended select * from t1 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -2760,14 +2757,6 @@ explain extended select * from t1 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -3375,7 +3364,7 @@ where a1 in (select b1 from t2_16 where
"from": "IN (SELECT)",
"to": "materialization",
"chosen": false,
- "cause": "field_types"
+ "cause": "inner blob"
} /* transformation */
},
{
@@ -4400,6 +4389,8 @@ concat(c1,'y') IN
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": true,
"chosen": true
} /* transformation */
}
@@ -4426,6 +4417,8 @@ concat(c1,'y') IN
"select#": 3,
"from": "IN (SELECT)",
"to": "materialization",
+ "has_nullable_expressions": true,
+ "treat_UNKNOWN_as_FALSE": true,
"chosen": true
} /* transformation */
}
@@ -6081,7 +6074,8 @@ select * from t1 where (t1.a,t1.b) not i
"select#": 2,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "already have strategy"
} /* transformation */
}
] /* steps */
=== modified file 'mysql-test/suite/opt_trace/r/general_ps_prot_none.result'
--- a/mysql-test/suite/opt_trace/r/general_ps_prot_none.result 2012-01-30 08:57:24 +0000
+++ b/mysql-test/suite/opt_trace/r/general_ps_prot_none.result 2012-02-08 15:25:17 +0000
@@ -998,14 +998,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -1024,14 +1016,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 3,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -1203,14 +1187,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": "fake",
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -1320,8 +1296,8 @@ select (@query:=QUERY)+NULL, (@trace:=TR
NULL NULL
select length(@trace);
length(@trace)
-13765
-set optimizer_trace_max_mem_size=13900;
+12890
+set optimizer_trace_max_mem_size=14100;
select length(@query)+length(@trace) > @@optimizer_trace_max_mem_size;
length(@query)+length(@trace) > @@optimizer_trace_max_mem_size
0
@@ -1337,12 +1313,12 @@ select length(@trace2),
(length(@trace2) + @missing_bytes) = length(@trace),
@query2 = @query;
length(@trace2) (length(@trace2) + @missing_bytes) = length(@trace) @query2 = @query
-13765 1 1
+12890 1 1
select length(@query2) + length(@trace2)
between (@@optimizer_trace_max_mem_size-200) and (@@optimizer_trace_max_mem_size+200);
length(@query2) + length(@trace2)
between (@@optimizer_trace_max_mem_size-200) and (@@optimizer_trace_max_mem_size+200)
-1
+0
select instr(@trace, @trace2) = 1;
instr(@trace, @trace2) = 1
1
@@ -1392,14 +1368,6 @@ explain SELECT c FROM t5 where c+1 in (s
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -1682,14 +1650,6 @@ explain SELECT c FROM t5 where c+1 in (s
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -2445,14 +2405,6 @@ explain extended select * from t1 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -2721,14 +2673,6 @@ explain extended select * from t1 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -3334,14 +3278,6 @@ where a1 in (select b1 from t2_16 where
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -3614,14 +3550,6 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -4348,14 +4276,6 @@ concat(c1,'y') IN
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -4384,14 +4304,6 @@ concat(c1,'y') IN
"transformation": {
"select#": 3,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 3,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -4854,14 +4766,6 @@ trace
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -4903,14 +4807,6 @@ trace
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -5017,14 +4913,6 @@ trace
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -5321,14 +5209,6 @@ select * from t1 where (t1.a,t1.b) not i
"to": "semijoin",
"chosen": false
} /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
}
] /* steps */
} /* join_preparation */
@@ -7340,14 +7220,6 @@ select d into res from t6 where d in (se
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
@@ -9118,14 +8990,6 @@ select d into res from t6 where d in (se
"transformation": {
"select#": 2,
"from": "IN (SELECT)",
- "to": "materialization",
- "chosen": false
- } /* transformation */
- },
- {
- "transformation": {
- "select#": 2,
- "from": "IN (SELECT)",
"to": "EXISTS (CORRELATED SELECT)",
"chosen": true,
"evaluating_constant_where_conditions": [
=== modified file 'mysql-test/suite/opt_trace/r/subquery_no_prot.result'
--- a/mysql-test/suite/opt_trace/r/subquery_no_prot.result 2012-01-26 13:09:59 +0000
+++ b/mysql-test/suite/opt_trace/r/subquery_no_prot.result 2012-02-08 15:25:17 +0000
@@ -996,7 +996,8 @@ field4,field5,field6 {
"select#": 6,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "correlated"
} /* transformation */
},
{
=== modified file 'mysql-test/suite/opt_trace/r/subquery_ps_prot.result'
--- a/mysql-test/suite/opt_trace/r/subquery_ps_prot.result 2012-01-30 08:57:24 +0000
+++ b/mysql-test/suite/opt_trace/r/subquery_ps_prot.result 2012-02-08 15:25:17 +0000
@@ -984,7 +984,8 @@ field4,field5,field6 {
"select#": 6,
"from": "IN (SELECT)",
"to": "materialization",
- "chosen": false
+ "chosen": false,
+ "cause": "correlated"
} /* transformation */
}
] /* steps */
=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc 2012-02-08 10:33:37 +0000
+++ b/sql/item_cmpfunc.cc 2012-02-08 15:25:17 +0000
@@ -1943,8 +1943,11 @@ void Item_in_optimizer::fix_after_pullou
/**
The implementation of optimized \<outer expression\> [NOT] IN \<subquery\>
- predicates. The implementation works as follows.
+ predicates. It applies to predicates which have gone through the IN->EXISTS
+ transformation in in_to_exists_transformer functions; not to subquery
+ materialization (which has no triggered conditions).
+ The implementation works as follows.
For the current value of the outer expression
- If it contains only NULL values, the original (before rewrite by the
@@ -2021,12 +2024,14 @@ longlong Item_in_optimizer::val_int()
if (cache->null_value)
{
+ Item_in_subselect * const item_subs=
+ static_cast<Item_in_subselect *>(args[1]);
/*
We're evaluating
"<outer_value_list> [NOT] IN (SELECT <inner_value_list>...)"
where one or more of the outer values is NULL.
*/
- if (((Item_in_subselect*)args[1])->is_top_level_item())
+ if (item_subs->is_top_level_item())
{
/*
We're evaluating a top level item, e.g.
@@ -2049,7 +2054,6 @@ longlong Item_in_optimizer::val_int()
SELECT evaluated over the non-NULL values produces at least
one row, FALSE otherwise
*/
- Item_in_subselect *item_subs=(Item_in_subselect*)args[1];
bool all_left_cols_null= true;
const uint ncols= cache->cols();
@@ -2080,7 +2084,7 @@ longlong Item_in_optimizer::val_int()
{
/* The subquery has to be evaluated */
(void) item_subs->val_bool_result();
- if (item_subs->engine->no_rows())
+ if (!item_subs->value)
null_value= item_subs->null_value;
else
null_value= TRUE;
=== modified file 'sql/item_cmpfunc.h'
--- a/sql/item_cmpfunc.h 2012-02-08 10:33:37 +0000
+++ b/sql/item_cmpfunc.h 2012-02-08 15:25:17 +0000
@@ -255,7 +255,7 @@ class Item_cache;
class Item_in_optimizer: public Item_bool_func
{
-protected:
+private:
Item_cache *cache;
bool save_cache;
/*
@@ -1481,7 +1481,8 @@ class Item_in_subselect;
/*
This is like IS NOT NULL but it also remembers if it ever has
- encountered a NULL.
+ encountered a NULL; it remembers this in the "was_null" property of the
+ "owner" item.
*/
class Item_is_not_null_test :public Item_func_isnull
{
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2012-01-17 09:45:08 +0000
+++ b/sql/item_subselect.cc 2012-02-08 15:25:17 +0000
@@ -151,7 +151,7 @@ void Item_in_subselect::cleanup()
delete left_expr_cache;
left_expr_cache= NULL;
}
- first_execution= TRUE;
+ left_expr_cache_filled= false;
need_expr_cache= TRUE;
Item_subselect::cleanup();
DBUG_VOID_RETURN;
@@ -452,20 +452,22 @@ bool Item_in_subselect::exec()
init_left_expr_cache())
DBUG_RETURN(TRUE);
- /* If the new left operand is already in the cache, reuse the old result. */
- if (left_expr_cache && test_if_item_cache_changed(*left_expr_cache) < 0)
+ if (left_expr_cache != NULL)
{
- /* Always compute IN for the first row as the cache is not valid for it. */
- if (!first_execution)
- DBUG_RETURN(FALSE);
- first_execution= FALSE;
+ const int result= test_if_item_cache_changed(*left_expr_cache);
+ if (left_expr_cache_filled && // cache was previously filled
+ result < 0) // new value is identical to previous cached value
+ {
+ /*
+ We needn't do a full execution, can just reuse "value", "was_null",
+ "null_value" of the previous execution.
+ */
+ DBUG_RETURN(false);
+ }
+ left_expr_cache_filled= true;
}
- /*
- The exec() method below updates item::value, and item::null_value, thus if
- we don't call it, the next call to item::val_int() will return whatever
- result was computed by its previous call.
- */
+ null_value= was_null= false;
const bool retval= Item_subselect::exec();
DBUG_RETURN(retval);
}
@@ -888,7 +890,7 @@ bool Item_in_subselect::test_limit(st_se
Item_in_subselect::Item_in_subselect(Item * left_exp,
st_select_lex *select_lex):
Item_exists_subselect(), left_expr(left_exp), left_expr_cache(NULL),
- first_execution(TRUE), need_expr_cache(TRUE), expr(NULL),
+ left_expr_cache_filled(false), need_expr_cache(TRUE), expr(NULL),
optimizer(NULL), was_null(FALSE), abort_on_null(FALSE),
pushed_cond_guards(NULL), upper_item(NULL)
{
@@ -1019,7 +1021,6 @@ double Item_in_subselect::val_real()
*/
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
- null_value= was_null= FALSE;
if (exec())
{
reset();
@@ -1039,7 +1040,6 @@ longlong Item_in_subselect::val_int()
*/
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
- null_value= was_null= FALSE;
if (exec())
{
reset();
@@ -1059,7 +1059,6 @@ String *Item_in_subselect::val_str(Strin
*/
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
- null_value= was_null= FALSE;
if (exec())
{
reset();
@@ -1078,7 +1077,6 @@ String *Item_in_subselect::val_str(Strin
bool Item_in_subselect::val_bool()
{
DBUG_ASSERT(fixed == 1);
- null_value= was_null= FALSE;
if (exec())
{
reset();
@@ -1096,7 +1094,6 @@ my_decimal *Item_in_subselect::val_decim
method should not be used
*/
DBUG_ASSERT(0);
- null_value= was_null= FALSE;
DBUG_ASSERT(fixed == 1);
if (exec())
{
@@ -2230,28 +2227,6 @@ bool subselect_union_engine::is_executed
}
-/*
- Check if last execution of the subquery engine produced any rows
-
- SYNOPSIS
- subselect_union_engine::no_rows()
-
- DESCRIPTION
- Check if last execution of the subquery engine produced any rows. The
- return value is undefined if last execution ended in an error.
-
- RETURN
- TRUE - Last subselect execution has produced no rows
- FALSE - Otherwise
-*/
-
-bool subselect_union_engine::no_rows() const
-{
- /* Check if we got any rows when reading UNION result from temp. table: */
- return test(!unit->fake_select_lex->join->send_records);
-}
-
-
subselect_union_engine::subselect_union_engine(st_select_lex_unit *u,
select_result_interceptor *result_arg,
Item_subselect *item_arg)
@@ -2325,7 +2300,7 @@ bool subselect_union_engine::prepare()
}
-bool subselect_uniquesubquery_engine::prepare()
+bool subselect_indexsubquery_engine::prepare()
{
/* Should never be called. */
DBUG_ASSERT(FALSE);
@@ -2333,27 +2308,6 @@ bool subselect_uniquesubquery_engine::pr
}
-/*
- Check if last execution of the subquery engine produced any rows
-
- SYNOPSIS
- subselect_single_select_engine::no_rows()
-
- DESCRIPTION
- Check if last execution of the subquery engine produced any rows. The
- return value is undefined if last execution ended in an error.
-
- RETURN
- TRUE - Last subselect execution has produced no rows
- FALSE - Otherwise
-*/
-
-bool subselect_single_select_engine::no_rows() const
-{
- return !item->assigned();
-}
-
-
/*
makes storage for the output values for the subquery and calcuates
their data and column types and their nullability.
@@ -2407,7 +2361,7 @@ void subselect_union_engine::fix_length_
}
}
-void subselect_uniquesubquery_engine::fix_length_and_dec(Item_cache **row)
+void subselect_indexsubquery_engine::fix_length_and_dec(Item_cache **row)
{
//this never should be called
DBUG_ASSERT(0);
@@ -2548,29 +2502,23 @@ bool subselect_union_engine::exec()
}
-/*
- Search for at least one row satisfying select condition
-
- SYNOPSIS
- subselect_uniquesubquery_engine::scan_table()
+/**
+ Search, using a table scan, for at least one row satisfying select
+ condition.
- DESCRIPTION
- Scan the table using sequential access until we find at least one row
- satisfying select condition.
-
- The caller must set this->empty_result_set=FALSE before calling this
- function. This function will set it to TRUE if it finds a matching row.
+ The caller must set item's 'value' to 'false' before calling this
+ function. This function will set it to 'true' if it finds a matching row.
- RETURN
- FALSE - OK
- TRUE - Error
+ @returns false if ok, true if read error.
*/
-
-bool subselect_uniquesubquery_engine::scan_table()
+bool subselect_indexsubquery_engine::scan_table()
{
int error;
TABLE *table= tab->table;
- DBUG_ENTER("subselect_uniquesubquery_engine::scan_table");
+ DBUG_ENTER("subselect_indexsubquery_engine::scan_table");
+
+ // We never need to do a table scan of the materialized table.
+ DBUG_ASSERT(engine_type() != HASH_SJ_ENGINE);
if (table->file->inited)
table->file->ha_index_end();
@@ -2594,7 +2542,6 @@ bool subselect_uniquesubquery_engine::sc
if (!cond || cond->val_int())
{
static_cast<Item_in_subselect*>(item)->value= true;
- empty_result_set= FALSE;
break;
}
}
@@ -2640,7 +2587,7 @@ bool subselect_uniquesubquery_engine::sc
value of NULL, not rows that match if the "inner_col IS NULL"
condition is disabled. Index lookup can be used for this.
- @see subselect_uniquesubquery_engine::exec()
+ @see subselect_indexsubquery_engine::exec()
@see Item_in_optimizer::val_int()
@param[out] require_scan true if a NULL value is found that falls
@@ -2651,10 +2598,10 @@ bool subselect_uniquesubquery_engine::sc
otherwise.
*/
-void subselect_uniquesubquery_engine::copy_ref_key(bool *require_scan,
- bool *convert_error)
+void subselect_indexsubquery_engine::copy_ref_key(bool *require_scan,
+ bool *convert_error)
{
- DBUG_ENTER("subselect_uniquesubquery_engine::copy_ref_key");
+ DBUG_ENTER("subselect_indexsubquery_engine::copy_ref_key");
*require_scan= false;
*convert_error= false;
@@ -2669,6 +2616,15 @@ void subselect_uniquesubquery_engine::co
if (s_key->null_key)
{
+ /*
+ If we have materialized the subquery:
+ - this NULL ref item cannot be local to the subquery (any such
+ conditions was handled during materialization)
+ - neither can it be outer, because this case is
+ separately managed in subselect_hash_sj_engine::exec().
+ */
+ DBUG_ASSERT(engine_type() != HASH_SJ_ENGINE);
+
const bool *cond_guard= tab->ref.cond_guards[part_no];
/*
@@ -2711,100 +2667,6 @@ void subselect_uniquesubquery_engine::co
/*
- Execute subselect
-
- SYNOPSIS
- subselect_uniquesubquery_engine::exec()
-
- DESCRIPTION
- Find rows corresponding to the ref key using index access.
- If some part of the lookup key is NULL, then we're evaluating
- NULL IN (SELECT ... )
- This is a special case, we don't need to search for NULL in the table,
- instead, the result value is
- - NULL if select produces empty row set
- - FALSE otherwise.
-
- In some cases (IN subselect is a top level item, i.e. abort_on_null==TRUE)
- the caller doesn't distinguish between NULL and FALSE result and we just
- return FALSE.
- Otherwise we make a full table scan to see if there is at least one
- matching row.
-
- The result of this function (info about whether a row was found) is
- stored in this->empty_result_set.
- NOTE
-
- RETURN
- FALSE - ok
- TRUE - an error occured while scanning
-*/
-
-bool subselect_uniquesubquery_engine::exec()
-{
- DBUG_ENTER("subselect_uniquesubquery_engine::exec");
- int error;
- TABLE *table= tab->table;
- TABLE_LIST *tl= table->pos_in_table_list;
- empty_result_set= TRUE;
- table->status= 0;
-
- if (engine_type() == UNIQUESUBQUERY_ENGINE &&
- tl->uses_materialization() && !tl->materialized)
- {
- bool err= mysql_handle_single_derived(table->in_use->lex, tl,
- mysql_derived_create) ||
- mysql_handle_single_derived(table->in_use->lex, tl,
- mysql_derived_materialize);
- if (!tab->table->in_use->lex->describe)
- mysql_handle_single_derived(table->in_use->lex, tl,
- mysql_derived_cleanup);
- if (err)
- DBUG_RETURN(1);
- }
-
- /* Copy the ref key and check for nulls... */
- bool require_scan, convert_error;
- copy_ref_key(&require_scan, &convert_error);
- if (convert_error)
- {
- ((Item_in_subselect *) item)->value= 0;
- DBUG_RETURN(0);
- }
-
- if (require_scan)
- {
- const bool scan_result= scan_table();
- DBUG_RETURN(scan_result);
- }
- if (!table->file->inited)
- table->file->ha_index_init(tab->ref.key, 0);
- error= table->file->ha_index_read_map(table->record[0],
- tab->ref.key_buff,
- make_prev_keypart_map(tab->ref.key_parts),
- HA_READ_KEY_EXACT);
- DBUG_PRINT("info", ("lookup result: %i", error));
- if (error &&
- error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
- error= report_error(table, error);
- else
- {
- error= 0;
- table->null_row= 0;
- if (!table->status && (!cond || cond->val_int()))
- {
- ((Item_in_subselect *) item)->value= 1;
- empty_result_set= FALSE;
- }
- else
- ((Item_in_subselect *) item)->value= 0;
- }
-
- DBUG_RETURN(error != 0);
-}
-
-
-/*
Index-lookup subselect 'engine' - run the subquery
SYNOPSIS
@@ -2825,6 +2687,8 @@ bool subselect_uniquesubquery_engine::ex
3. If check_null==TRUE, make another lookup via key=NULL, search for a
row that satisfies subq_where. If found, return NULL, otherwise
return FALSE.
+ 4. If unique==true, there can be only one row with key=oe and only one row
+ with key=NULL, we use that fact to shorten the search process.
TODO
The step #1 can be optimized further when the index has several key
@@ -2862,13 +2726,13 @@ bool subselect_indexsubquery_engine::exe
int error;
bool null_finding= 0;
TABLE *table= tab->table;
+ // 'tl' is NULL if this is a tmp table created by subselect_hash_sj_engine.
TABLE_LIST *tl= table->pos_in_table_list;
-
- ((Item_in_subselect *) item)->value= 0;
- empty_result_set= TRUE;
+ Item_in_subselect *const item_in= static_cast<Item_in_subselect*>(item);
+ item_in->value= false;
table->status= 0;
- if (tl->uses_materialization() && !tl->materialized)
+ if (tl && tl->uses_materialization() && !tl->materialized)
{
bool err= mysql_handle_single_derived(table->in_use->lex, tl,
mysql_derived_create) ||
@@ -2885,17 +2749,14 @@ bool subselect_indexsubquery_engine::exe
{
/* We need to check for NULL if there wasn't a matching value */
*tab->ref.null_ref_key= 0; // Search first for not null
- ((Item_in_subselect *) item)->was_null= 0;
+ item_in->was_null= false;
}
/* Copy the ref key and check for nulls... */
bool require_scan, convert_error;
copy_ref_key(&require_scan, &convert_error);
if (convert_error)
- {
- ((Item_in_subselect *) item)->value= 0;
DBUG_RETURN(0);
- }
if (require_scan)
{
@@ -2904,7 +2765,7 @@ bool subselect_indexsubquery_engine::exe
}
if (!table->file->inited)
- table->file->ha_index_init(tab->ref.key, 1);
+ table->file->ha_index_init(tab->ref.key, !unique /* sorted */);
error= table->file->ha_index_read_map(table->record[0],
tab->ref.key_buff,
make_prev_keypart_map(tab->ref.key_parts),
@@ -2922,13 +2783,21 @@ bool subselect_indexsubquery_engine::exe
{
if ((!cond || cond->val_int()) && (!having || having->val_int()))
{
- empty_result_set= FALSE;
+ item_in->value= true;
if (null_finding)
- ((Item_in_subselect *) item)->was_null= 1;
- else
- ((Item_in_subselect *) item)->value= 1;
+ {
+ /*
+ This is dead code; subqueries with check_null==true are always
+ transformed with IN-to-EXISTS and thus their artificial HAVING
+ rejects NULL values...
+ */
+ DBUG_ASSERT(false);
+ item_in->was_null= true;
+ }
break;
}
+ if (unique)
+ break;
error= table->file->ha_index_next_same(table->record[0],
tab->ref.key_buff,
tab->ref.key_length);
@@ -2942,9 +2811,14 @@ bool subselect_indexsubquery_engine::exe
{
if (!check_null || null_finding)
break; /* We don't need to check nulls */
+ /*
+ Check if there exists a row with a null value in the index. We come
+ here only if ref_or_null, and ref_or_null is always on a single
+ column (first keypart of the index). So we have only one NULL bit to
+ turn on:
+ */
*tab->ref.null_ref_key= 1;
null_finding= 1;
- /* Check if there exists a row with a null value in the index */
if ((error= (safe_index_read(tab) == 1)))
break;
}
@@ -2990,7 +2864,7 @@ void subselect_union_engine::exclude()
}
-void subselect_uniquesubquery_engine::exclude()
+void subselect_indexsubquery_engine::exclude()
{
//this never should be called
DBUG_ASSERT(0);
@@ -3085,41 +2959,12 @@ void subselect_union_engine::print(Strin
}
-void subselect_uniquesubquery_engine::print(String *str,
- enum_query_type query_type)
-{
- char *table_name= tab->table->s->table_name.str;
- str->append(STRING_WITH_LEN("<primary_index_lookup>("));
- tab->ref.items[0]->print(str, query_type);
- str->append(STRING_WITH_LEN(" in "));
- if (tab->table->s->table_category == TABLE_CATEGORY_TEMPORARY)
- {
- /*
- Temporary tables' names change across runs, so they can't be used for
- EXPLAIN EXTENDED.
- */
- str->append(STRING_WITH_LEN("<temporary table>"));
- }
- else
- str->append(table_name, tab->table->s->table_name.length);
- KEY *key_info= tab->table->key_info+ tab->ref.key;
- str->append(STRING_WITH_LEN(" on "));
- str->append(key_info->name);
- if (cond)
- {
- str->append(STRING_WITH_LEN(" where "));
- cond->print(str, query_type);
- }
- str->append(')');
-}
-
-
/*
TODO:
-The above ::print method should be changed as below. Do it after
+The ::print method below should be changed as follows. Do it after
all other tests pass.
-void subselect_uniquesubquery_engine::print(String *str)
+void subselect_indexsubquery_engine::print(String *str)
{
KEY *key_info= tab->table->key_info + tab->ref.key;
str->append(STRING_WITH_LEN("<primary_index_lookup>("));
@@ -3141,17 +2986,27 @@ void subselect_uniquesubquery_engine::pr
void subselect_indexsubquery_engine::print(String *str,
enum_query_type query_type)
{
- str->append(STRING_WITH_LEN("<index_lookup>("));
+ if (unique)
+ str->append(STRING_WITH_LEN("<primary_index_lookup>("));
+ else
+ str->append(STRING_WITH_LEN("<index_lookup>("));
tab->ref.items[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" in "));
- /*
- For materialized derived tables/views use table/view alias instead of
- temporary table name, as it changes on each run and not acceptable for
- EXPLAIN EXTENDED.
- */
if (tab->table->pos_in_table_list &&
- tab->table->pos_in_table_list->uses_materialization())
+ tab->table->pos_in_table_list->uses_materialization())
+ {
+ /*
+ For materialized derived tables/views use table/view alias instead of
+ temporary table name, as it changes on each run and not acceptable for
+ EXPLAIN EXTENDED.
+ */
str->append(tab->table->alias, strlen(tab->table->alias));
+ }
+ else if (tab->table->s->table_category == TABLE_CATEGORY_TEMPORARY)
+ {
+ // Could be from subselect_hash_sj_engine.
+ str->append(STRING_WITH_LEN("<temporary table>"));
+ }
else
str->append(tab->table->s->table_name.str, tab->table->s->table_name.length);
KEY *key_info= tab->table->key_info+ tab->ref.key;
@@ -3227,8 +3082,8 @@ bool subselect_union_engine::change_resu
TRUE error
*/
-bool subselect_uniquesubquery_engine::change_result(Item_subselect *si,
- select_result_interceptor *res)
+bool subselect_indexsubquery_engine::change_result(Item_subselect *si,
+ select_result_interceptor *res)
{
DBUG_ASSERT(0);
return TRUE;
@@ -3293,7 +3148,7 @@ bool subselect_union_engine::no_tables()
FALSE there are some tables in subquery
*/
-bool subselect_uniquesubquery_engine::no_tables() const
+bool subselect_indexsubquery_engine::no_tables() const
{
/* returning value is correct, but this method should never be called */
return 0;
@@ -3310,7 +3165,8 @@ bool subselect_uniquesubquery_engine::no
@detail
- Create a temporary table to store the result of the IN subquery. The
- temporary table has one hash index on all its columns.
+ temporary table has one hash index on all its columns. If single-column,
+ the index allows at most one NULL row.
- Create a new result sink that sends the result stream of the subquery to
the temporary table,
- Create and initialize a new JOIN_TAB, and TABLE_REF objects to perform
@@ -3393,7 +3249,7 @@ bool subselect_hash_sj_engine::setup(Lis
plan operator into the materialized subquery result. Notice that:
- this JOIN_TAB has no corresponding JOIN (and doesn't need one), and
- here we initialize only those members that are used by
- subselect_uniquesubquery_engine, so these objects are incomplete.
+ subselect_indexsubquery_engine, so these objects are incomplete.
*/
JOIN_TAB * const tmp_tab= new (thd->mem_root) JOIN_TAB;
if (tmp_tab == NULL)
@@ -3414,11 +3270,14 @@ bool subselect_hash_sj_engine::setup(Lis
/*
Create an artificial condition to post-filter those rows matched by index
lookups that cannot be distinguished by the index lookup procedure, e.g.
- because of truncation. Prepared statements execution requires that
- fix_fields is called for every execution. In order to call fix_fields we
- need to create a Name_resolution_context and a corresponding TABLE_LIST
- for the temporary table for the subquery, so that all column references
- to the materialized subquery table can be resolved correctly.
+ because of truncation (if the outer column type's length is bigger than
+ the inner column type's, index lookup will use a truncated outer
+ value as search key, yielding false positives).
+ Prepared statements execution requires that fix_fields is called
+ for every execution. In order to call fix_fields we need to create a
+ Name_resolution_context and a corresponding TABLE_LIST for the temporary
+ table for the subquery, so that all column references to the materialized
+ subquery table can be resolved correctly.
*/
DBUG_ASSERT(cond == NULL);
if (!(cond= new Item_cond_and))
@@ -3448,7 +3307,7 @@ bool subselect_hash_sj_engine::setup(Lis
Item_func_eq *eq_cond;
/* Item for the corresponding field from the materialized temp table. */
Item_field *right_col_item;
- int null_count= test(key_parts[part_no].field->real_maybe_null());
+ const bool nullable= key_parts[part_no].field->real_maybe_null();
tmp_tab->ref.items[part_no]= item_in->left_expr->element_index(part_no);
if (!(right_col_item= new Item_field(thd, context,
@@ -3470,10 +3329,26 @@ bool subselect_hash_sj_engine::setup(Lis
cur_ref_buff + test(maybe_null), we could
use that information instead.
*/
- cur_ref_buff + null_count,
- null_count ? cur_ref_buff : 0,
+ cur_ref_buff + (nullable ? 1 : 0),
+ nullable ? cur_ref_buff : 0,
key_parts[part_no].length,
tmp_tab->ref.items[part_no]);
+ if (nullable && // nullable column in tmp table,
+ // and UNKNOWN should not be interpreted as FALSE
+ !item_in->is_top_level_item())
+ {
+ // It must be the single column, or we wouldn't be here
+ DBUG_ASSERT(tmp_key_parts == 1);
+ // Be ready to search for NULL into inner column:
+ tmp_tab->ref.null_ref_key= cur_ref_buff;
+ mat_table_has_nulls= NEX_UNKNOWN;
+ }
+ else
+ {
+ tmp_tab->ref.null_ref_key= NULL;
+ mat_table_has_nulls= NEX_IRRELEVANT_OR_FALSE;
+ }
+
cur_ref_buff+= key_parts[part_no].store_length;
}
tmp_tab->ref.key_err= 1;
@@ -3543,7 +3418,7 @@ void subselect_hash_sj_engine::cleanup()
bool subselect_hash_sj_engine::exec()
{
Item_in_subselect *item_in= (Item_in_subselect *) item;
-
+ TABLE *const table= tab->table;
DBUG_ENTER("subselect_hash_sj_engine::exec");
/*
@@ -3552,7 +3427,7 @@ bool subselect_hash_sj_engine::exec()
*/
if (!is_materialized)
{
- bool res= false;
+ bool res;
THD * const thd= item->unit->thd;
SELECT_LEX *save_select= thd->lex->current_select;
thd->lex->current_select= materialize_engine->select_lex;
@@ -3576,21 +3451,10 @@ bool subselect_hash_sj_engine::exec()
unlocking).
*/
is_materialized= TRUE;
- /*
- If the subquery returned no rows, the temporary table is empty, so we know
- directly that the result of IN is FALSE. We first update the table
- statistics, then we test if the temporary table for the query result is
- empty.
- */
- tab->table->file->info(HA_STATUS_VARIABLE);
- if (!tab->table->file->stats.records)
- {
- empty_result_set= TRUE;
- item_in->value= FALSE;
- /* TODO: check we need this: item_in->null_value= FALSE; */
- thd->lex->current_select= save_select;
- DBUG_RETURN(FALSE);
- }
+
+ // Calculate row count:
+ table->file->info(HA_STATUS_VARIABLE);
+
/* Set tmp_param only if its usable, i.e. tmp_param->copy_field != NULL. */
tmp_param= &(item_in->unit->outer_select()->join->tmp_table_param);
if (tmp_param && !tmp_param->copy_field)
@@ -3600,12 +3464,71 @@ err:
thd->lex->current_select= save_select;
if (res)
DBUG_RETURN(res);
- }
+ } // if (!is_materialized)
+ if (table->file->stats.records == 0)
+ {
+ // The correct answer is FALSE.
+ item_in->value= false;
+ DBUG_RETURN(false);
+ }
/*
- Lookup the left IN operand in the hash index of the materialized subquery.
+ Here we could be brutal and set item_in->null_value. But we prefer to be
+ well-behaved and rather set the properties which
+ Item_in_subselect::val_bool() and Item_in_optimizer::val_int() expect,
+ and then those functions will set null_value based on those properties.
*/
- DBUG_RETURN(subselect_uniquesubquery_engine::exec());
+ if (item_in->left_expr->element_index(0)->null_value)
+ {
+ /*
+ The first outer expression oe1 is NULL. It is the single outer
+ expression because if there would be more ((oe1,oe2,...)IN(...)) then
+ either they would be non-nullable (so we wouldn't be here) or the
+ predicate would be top-level (so we wouldn't be here,
+ Item_in_optimizer::val_int() would have short-cut). The correct answer
+ is UNKNOWN. Do as if searching with all triggered conditions disabled:
+ this would surely find a row. The caller will translate this to UNKNOWN.
+ */
+ DBUG_ASSERT(item_in->left_expr->cols() == 1);
+ item_in->value= true;
+ DBUG_RETURN(false);
+ }
+
+ if (subselect_indexsubquery_engine::exec()) // Search with index
+ DBUG_RETURN(true);
+
+ if (!item_in->value && // no exact match
+ mat_table_has_nulls != NEX_IRRELEVANT_OR_FALSE)
+ {
+ /*
+ There is only one outer expression. It's not NULL. exec() above has set
+ the answer to FALSE, but if there exists an inner NULL in the temporary
+ table, then the correct answer is UNKNOWN, so let's find out.
+ */
+ if (mat_table_has_nulls == NEX_UNKNOWN) // We do not know yet
+ {
+ // Search for NULL inside tmp table, and remember the outcome.
+ DBUG_ASSERT(table->file->inited);
+ *tab->ref.null_ref_key= 1;
+ if (safe_index_read(tab) == 1)
+ DBUG_RETURN(true);
+ *tab->ref.null_ref_key= 0; // prepare for next searches of non-NULL
+ mat_table_has_nulls=
+ (table->status == 0) ? NEX_TRUE : NEX_IRRELEVANT_OR_FALSE;
+ }
+ if (mat_table_has_nulls == NEX_TRUE)
+ {
+ /*
+ There exists an inner NULL. The correct answer is UNKNOWN.
+ Do as if searching with all triggered conditions enabled; that
+ would not find any match, but Item_is_not_null_test would notice a
+ NULL:
+ */
+ item_in->value= false;
+ item_in->was_null= true;
+ }
+ }
+ DBUG_RETURN(false);
}
@@ -3619,7 +3542,7 @@ void subselect_hash_sj_engine::print(Str
materialize_engine->print(str, query_type);
str->append(STRING_WITH_LEN(" ), "));
if (tab)
- subselect_uniquesubquery_engine::print(str, query_type);
+ subselect_indexsubquery_engine::print(str, query_type);
else
str->append(STRING_WITH_LEN(
"<the access method for lookups is not yet created>"
=== modified file 'sql/item_subselect.h'
--- a/sql/item_subselect.h 2011-11-10 14:58:23 +0000
+++ b/sql/item_subselect.h 2012-02-08 15:25:17 +0000
@@ -320,7 +320,6 @@ public:
virtual void print(String *str, enum_query_type query_type);
friend class select_exists_subselect;
- friend class subselect_uniquesubquery_engine;
friend class subselect_indexsubquery_engine;
};
@@ -350,7 +349,7 @@ protected:
runtime memory root, for each execution, thus need not be freed.
*/
List<Cached_item> *left_expr_cache;
- bool first_execution;
+ bool left_expr_cache_filled; ///< Whether left_expr_cache holds a value
/** The need for expr cache may be optimized away, @sa init_left_expr_cache. */
bool need_expr_cache;
@@ -389,7 +388,7 @@ public:
Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
Item_in_subselect()
:Item_exists_subselect(), left_expr(NULL), left_expr_cache(NULL),
- first_execution(TRUE), need_expr_cache(TRUE), expr(NULL),
+ left_expr_cache_filled(false), need_expr_cache(TRUE), expr(NULL),
optimizer(NULL), was_null(FALSE), abort_on_null(FALSE),
pushed_cond_guards(NULL), upper_item(NULL)
{}
@@ -492,10 +491,6 @@ public:
either captured by previously set up select_result-based 'sink' or
stored somewhere by the exec() method itself.
- A required side effect: If at least one pushed-down predicate is
- disabled, subselect_engine->no_rows() must return correct result after
- the exec() call.
-
RETURN
0 - OK
1 - Either an execution error, or the engine was "changed", and the
@@ -515,8 +510,6 @@ public:
select_result_interceptor *result)= 0;
virtual bool no_tables() const = 0;
virtual bool is_executed() const { return FALSE; }
- /* Check if subquery produced any rows during last query execution */
- virtual bool no_rows() const = 0;
virtual enum_engine_type engine_type() const { return ABSTRACT_ENGINE; }
#ifndef DBUG_OFF
/**
@@ -557,7 +550,6 @@ public:
virtual bool no_tables() const;
virtual bool may_be_null() const;
virtual bool is_executed() const { return executed; }
- virtual bool no_rows() const;
virtual enum_engine_type engine_type() const { return SINGLE_SELECT_ENGINE; }
bool save_join_if_explain();
@@ -585,7 +577,6 @@ public:
select_result_interceptor *result);
virtual bool no_tables() const;
virtual bool is_executed() const;
- virtual bool no_rows() const;
virtual enum_engine_type engine_type() const { return UNION_ENGINE; }
private:
@@ -596,65 +587,32 @@ private:
struct st_join_table;
-/*
- A subquery execution engine that evaluates the subquery by doing one index
- lookup in a unique index.
+/**
+ A subquery execution engine that evaluates the subquery by doing index
+ lookups in a single table's index.
This engine is used to resolve subqueries in forms
-
- outer_expr IN (SELECT tbl.unique_key FROM tbl WHERE subq_where)
-
- or, tuple-based:
-
- (oe1, .. oeN) IN (SELECT uniq_key_part1, ... uniq_key_partK
- FROM tbl WHERE subqwhere)
-
+
+ outer_expr IN (SELECT tbl.key FROM tbl WHERE subq_where)
+
+ or, row-based:
+
+ (oe1, .. oeN) IN (SELECT key_part1, ... key_partK
+ FROM tbl WHERE subqwhere)
+
i.e. the subquery is a single table SELECT without GROUP BY, aggregate
functions, etc.
*/
-
-class subselect_uniquesubquery_engine: public subselect_engine
+class subselect_indexsubquery_engine : public subselect_engine
{
protected:
st_join_table *tab;
Item *cond; /* The WHERE condition of subselect */
- /*
- TRUE<=> last execution produced empty set. Valid only when left
- expression is NULL.
- */
- bool empty_result_set;
-public:
-
- // constructor can assign THD because it will be called after JOIN::prepare
- subselect_uniquesubquery_engine(THD *thd_arg, st_join_table *tab_arg,
- Item_subselect *subs, Item *where)
- :subselect_engine(subs, 0), tab(tab_arg), cond(where) {}
- virtual void cleanup() {}
- virtual bool prepare();
- virtual void fix_length_and_dec(Item_cache** row);
- virtual bool exec();
- virtual uint cols() const { return 1; }
- virtual uint8 uncacheable() const { return UNCACHEABLE_DEPENDENT; }
- virtual void exclude();
- virtual table_map upper_select_const_tables() const { return 0; }
- virtual void print (String *str, enum_query_type query_type);
- virtual bool change_result(Item_subselect *si,
- select_result_interceptor *result);
- virtual bool no_tables() const;
- bool scan_table();
- void copy_ref_key(bool *require_scan, bool *convert_error);
- virtual bool no_rows() const { return empty_result_set; }
- virtual enum_engine_type engine_type() const { return UNIQUESUBQUERY_ENGINE; }
-};
-
-
-class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
-{
private:
/* FALSE for 'ref', TRUE for 'ref-or-null'. */
bool check_null;
/*
- The "having" clause. This clause (further reffered to as "artificial
+ The "having" clause. This clause (further referred to as "artificial
having") was inserted by subquery transformation code. It contains
Item(s) that have a side-effect: they record whether the subquery has
produced a row with NULL certain components. We need to use it for cases
@@ -662,40 +620,39 @@ private:
(oe1, oe2) IN (SELECT t.key, t.no_key FROM t1)
where we do index lookup on t.key=oe1 but need also to check if there
was a row such that t.no_key IS NULL.
-
- NOTE: This is currently here and not in the uniquesubquery_engine. Ideally
- it should have been in uniquesubquery_engine in order to allow execution of
- subqueries like
-
- (oe1, oe2) IN (SELECT primary_key, non_key_maybe_null_field FROM tbl)
-
- We could use uniquesubquery_engine for the first component and let
- Item_is_not_null_test( non_key_maybe_null_field) to handle the second.
-
- However, subqueries like the above are currently not handled by index
- lookup-based subquery engines, the engine applicability check misses
- them: it doesn't switch the engine for case of artificial having and
- [eq_]ref access (only for artifical having + ref_or_null or no having).
- The above example subquery is handled as a full-blown SELECT with eq_ref
- access to one table.
-
- Due to this limitation, the "artificial having" currently needs to be
- checked by only in indexsubquery_engine.
*/
Item *having;
+ /**
+ Whether a lookup for key value (x0,y0) (x0 and/or y0 being NULL or not
+ NULL) will find at most one row.
+ */
+ bool unique;
public:
// constructor can assign THD because it will be called after JOIN::prepare
subselect_indexsubquery_engine(THD *thd_arg, st_join_table *tab_arg,
Item_subselect *subs, Item *where,
- Item *having_arg, bool chk_null)
- :subselect_uniquesubquery_engine(thd_arg, tab_arg, subs, where),
- check_null(chk_null),
- having(having_arg)
- {}
+ Item *having_arg, bool chk_null,
+ bool unique_arg)
+ :subselect_engine(subs, 0), tab(tab_arg), cond(where),
+ check_null(chk_null), having(having_arg), unique(unique_arg)
+ {};
virtual bool exec();
virtual void print (String *str, enum_query_type query_type);
- virtual enum_engine_type engine_type() const { return INDEXSUBQUERY_ENGINE; }
+ virtual enum_engine_type engine_type() const
+ { return unique ? UNIQUESUBQUERY_ENGINE : INDEXSUBQUERY_ENGINE; }
+ virtual void cleanup() {}
+ virtual bool prepare();
+ virtual void fix_length_and_dec(Item_cache** row);
+ virtual uint cols() const { return 1; }
+ virtual uint8 uncacheable() const { return UNCACHEABLE_DEPENDENT; }
+ virtual void exclude();
+ virtual table_map upper_select_const_tables() const { return 0; }
+ virtual bool change_result(Item_subselect *si,
+ select_result_interceptor *result);
+ virtual bool no_tables() const;
+ bool scan_table();
+ void copy_ref_key(bool *require_scan, bool *convert_error);
};
/*
@@ -723,14 +680,29 @@ inline bool Item_subselect::is_uncacheab
/**
Compute an IN predicate via a hash semi-join. The subquery is materialized
during the first evaluation of the IN predicate. The IN predicate is executed
- via the functionality inherited from subselect_uniquesubquery_engine.
+ via the functionality inherited from subselect_indexsubquery_engine.
*/
-class subselect_hash_sj_engine: public subselect_uniquesubquery_engine
+class subselect_hash_sj_engine: public subselect_indexsubquery_engine
{
private:
/* TRUE if the subquery was materialized into a temp table. */
bool is_materialized;
+ /**
+ Existence of inner NULLs in materialized table:
+ By design, other values than IRRELEVANT_OR_FALSE are possible only if the
+ subquery has only one inner expression.
+ */
+ enum nulls_exist
+ {
+ /// none, or they don't matter
+ NEX_IRRELEVANT_OR_FALSE= 0,
+ /// they matter, and we don't know yet if they exists
+ NEX_UNKNOWN= 1,
+ /// they matter, and we know there exists at least one.
+ NEX_TRUE= 2
+ };
+ enum nulls_exist mat_table_has_nulls;
/*
The old engine already chosen at parse time and stored in permanent memory.
Through this member we can re-create and re-prepare the join object
@@ -744,10 +716,10 @@ private:
public:
subselect_hash_sj_engine(THD *thd, Item_subselect *in_predicate,
- subselect_single_select_engine *old_engine)
- :subselect_uniquesubquery_engine(thd, NULL, in_predicate, NULL),
- is_materialized(FALSE), materialize_engine(old_engine),
- tmp_param(NULL)
+ subselect_single_select_engine *old_engine)
+ :subselect_indexsubquery_engine(thd, NULL, in_predicate, NULL,
+ NULL, false, true),
+ is_materialized(false), materialize_engine(old_engine), tmp_param(NULL)
{}
~subselect_hash_sj_engine();
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2012-01-31 15:16:16 +0000
+++ b/sql/sql_class.cc 2012-02-08 15:25:17 +0000
@@ -2978,6 +2978,12 @@ bool select_exists_subselect::send_data(
unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
+ /*
+ A subquery may be evaluated 1) by executing the JOIN 2) by optimized
+ functions (index_subquery, subquery materialization).
+ It's only in (1) that we get here when we find a row. In (2) "value" is
+ set elsewhere.
+ */
it->value= 1;
it->assigned(1);
DBUG_RETURN(0);
=== modified file 'sql/sql_optimizer.cc'
--- a/sql/sql_optimizer.cc 2012-02-07 20:32:47 +0000
+++ b/sql/sql_optimizer.cc 2012-02-08 15:25:17 +0000
@@ -768,8 +768,10 @@ JOIN::optimize()
join_tab[0].type= JT_UNIQUE_SUBQUERY;
error= 0;
changed= TRUE;
- engine= new subselect_uniquesubquery_engine(thd, join_tab, unit->item,
- where);
+ engine= new subselect_indexsubquery_engine(thd, join_tab, unit->item,
+ where, NULL /* having */,
+ false /* check_null */,
+ true /* unique */);
}
else if (join_tab[0].type == JT_REF &&
join_tab[0].ref.items[0]->name == in_left_expr_name)
@@ -780,7 +782,7 @@ JOIN::optimize()
error= 0;
changed= TRUE;
engine= new subselect_indexsubquery_engine(thd, join_tab, unit->item,
- where, NULL, 0);
+ where, NULL, false, false);
}
} else if (join_tab[0].type == JT_REF_OR_NULL &&
join_tab[0].ref.items[0]->name == in_left_expr_name &&
@@ -792,7 +794,13 @@ JOIN::optimize()
conds= remove_additional_cond(conds);
save_index_subquery_explain_info(join_tab, conds);
engine= new subselect_indexsubquery_engine(thd, join_tab, unit->item,
- conds, having, 1);
+ conds, having, true, false);
+ /**
+ @todo Above we passed unique=false. But for this query:
+ (oe1, oe2) IN (SELECT primary_key, non_key_maybe_null_field FROM tbl)
+ we could use "unique=true" for the first index component and let
+ Item_is_not_null_test(non_key_maybe_null_field) handle the second.
+ */
}
if (changed)
DBUG_RETURN(unit->item->change_engine(engine));
@@ -8591,8 +8599,7 @@ static Item *remove_additional_cond(Item
where Subquery's WHERE clause
DESCRIPTION
- For index lookup-based subquery (i.e. one executed with
- subselect_uniquesubquery_engine or subselect_indexsubquery_engine),
+ For index lookup-based subquery (subselect_indexsubquery_engine),
check its EXPLAIN output row should contain
"Using index" (TAB_INFO_FULL_SCAN_ON_NULL)
"Using Where" (TAB_INFO_USING_WHERE)
=== modified file 'sql/sql_resolver.cc'
--- a/sql/sql_resolver.cc 2012-01-10 18:58:10 +0000
+++ b/sql/sql_resolver.cc 2012-02-08 15:25:17 +0000
@@ -377,42 +377,136 @@ err:
/**
- @brief Check if subquery predicate's compared types allow materialization.
+ Check if the subquery predicate can be executed via materialization.
- @param predicate subquery predicate
+ @param predicate IN subquery predicate
+ @param thd THD
+ @param select_lex SELECT_LEX of the subquery
+ @param outer Parent SELECT_LEX (outer to subquery)
- @return TRUE if subquery types allow materialization, FALSE otherwise.
-
- @details
- This is a temporary fix for BUG#36752.
- See bug report for description of restrictions we need to put on the
- compared expressions.
+ @return TRUE if subquery allows materialization, FALSE otherwise.
*/
-static
-bool subquery_types_allow_materialization(Item_in_subselect *predicate)
+static
+bool subquery_allows_materialization(Item_in_subselect *predicate,
+ THD *thd,
+ SELECT_LEX *select_lex,
+ const SELECT_LEX *outer)
{
- DBUG_ENTER("subquery_types_allow_materialization");
+ bool has_nullables= false;
+ const uint elements= predicate->unit->first_select()->item_list.elements;
+ DBUG_ENTER("subquery_allows_materialization");
+ DBUG_ASSERT(elements >= 1);
+ DBUG_ASSERT(predicate->left_expr->cols() == elements);
+
+ OPT_TRACE_TRANSFORM(&thd->opt_trace, trace_wrapper, trace_mat,
+ select_lex->select_number,
+ "IN (SELECT)", "materialization");
- DBUG_ASSERT(predicate->left_expr->fixed);
- DBUG_ASSERT(predicate->left_expr->cols() ==
- predicate->unit->first_select()->item_list.elements);
-
- List_iterator<Item> it(predicate->unit->first_select()->item_list);
- uint elements= predicate->unit->first_select()->item_list.elements;
-
- for (uint i= 0; i < elements; i++)
- {
- Item *inner= it++;
- if (!types_allow_materialization(predicate->left_expr->element_index(i),
- inner))
- DBUG_RETURN(FALSE);
- if (inner->is_blob_field())
- DBUG_RETURN(FALSE);
+ const char *cause= NULL;
+ if (select_lex->is_part_of_union())
+ {
+ // Subquery must be a single query specification clause (not a UNION)
+ cause= "in UNION";
+ }
+ else if (!select_lex->master_unit()->first_select()->leaf_tables)
+ {
+ // Subquery has no tables, hence no point in materializing.
+ cause= "no inner tables";
+ }
+ else if (!outer->join)
+ {
+ /*
+ Maybe this is a subquery of a single table UPDATE/DELETE (TODO:
+ handle this by switching to multi-table UPDATE/DELETE).
+ */
+ cause= "parent query has no JOIN";
}
+ else if (!outer->leaf_tables)
+ {
+ /*
+ The upper query is SELECT ... FROM DUAL. We can't do materialization for
+ SELECT .. FROM DUAL because it does not call
+ setup_subquery_materialization(). We could fix it but it's not worth it.
+ */
+ cause= "no tables in outer query";
+ }
+ else if (predicate->is_correlated)
+ {
+ /*
+ Subquery should not be correlated.
+ TODO:
+ This is an overly restrictive condition. It can be extended to:
+ (Subquery is non-correlated ||
+ Subquery is correlated to any query outer to IN predicate ||
+ (Subquery is correlated to the immediate outer query &&
+ Subquery !contains {GROUP BY, ORDER BY [LIMIT],
+ aggregate functions}) && subquery predicate is not under "NOT IN"))
+ */
+ cause= "correlated";
+ }
+ else if (predicate->exec_method !=
+ Item_exists_subselect::EXEC_UNSPECIFIED)
+ {
+ // An execution method was already chosen (by a prepared statement).
+ cause= "already have strategy";
+ }
+ else
+ {
+ /*
+ Check that involved expression types allow materialization.
+ This is a temporary fix for BUG#36752; see bug report for
+ description of restrictions we need to put on the compared expressions.
+ */
+ DBUG_ASSERT(predicate->left_expr->fixed);
+ List_iterator<Item> it(predicate->unit->first_select()->item_list);
- DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed"));
- DBUG_RETURN(TRUE);
+ for (uint i= 0; i < elements; i++)
+ {
+ Item * const inner= it++;
+ Item * const outer= predicate->left_expr->element_index(i);
+ if (!types_allow_materialization(outer, inner))
+ {
+ cause= "type mismatch";
+ break;
+ }
+ if (inner->is_blob_field()) // 6
+ {
+ cause= "inner blob";
+ break;
+ }
+ has_nullables|= outer->maybe_null | inner->maybe_null;
+ }
+
+ if (!cause)
+ {
+ trace_mat.add("has_nullable_expressions", has_nullables);
+ /*
+ Subquery materialization cannot handle NULLs partial matching
+ properly, yet. If the outer or inner values are NULL, the
+ subselect_hash_sj_engine may reply FALSE when it should reply UNKNOWN.
+ So, we must limit it to those three cases:
+ - when FALSE and UNKNOWN are equivalent answers. I.e. this is a a
+ top-level predicate (this implies it is not negated).
+ - when outer and inner values cannot be NULL.
+ - when there is a single inner column (because for this we have a
+ limited implementation of NULLs partial matching).
+ */
+ const bool is_top_level= predicate->is_top_level_item();
+ trace_mat.add("treat_UNKNOWN_as_FALSE", is_top_level);
+
+ if (!is_top_level && has_nullables && (elements > 1))
+ cause= "cannot_handle_partial_matches";
+ else
+ {
+ trace_mat.add("chosen", true);
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+ DBUG_ASSERT(cause != NULL);
+ trace_mat.add("chosen", false).add_alnum("cause", cause);
+ DBUG_RETURN(false);
}
@@ -437,13 +531,11 @@ bool subquery_types_allow_materializatio
*/
-static
-bool resolve_subquery(THD *thd, JOIN *join)
+static bool resolve_subquery(THD *thd, JOIN *join)
{
DBUG_ENTER("resolve_subquery");
- enum {SQ_NONE, SQ_SEMIJOIN, SQ_MATERIALIZATION} sq_choice= SQ_NONE;
- bool types_problem= false; // if types prevented subq materialization
+ bool chose_semijoin= false;
SELECT_LEX *const select_lex= join->select_lex;
SELECT_LEX *const outer= select_lex->outer_select();
@@ -548,93 +640,37 @@ bool resolve_subquery(THD *thd, JOIN *jo
/* Register the subquery for further processing in flatten_subqueries() */
outer->join->sj_subselects.push_back(in_exists_predicate);
- sq_choice= SQ_SEMIJOIN;
+ chose_semijoin= true;
}
- else
+
+ if (subq_predicate_substype == Item_subselect::IN_SUBS)
+ {
+ Opt_trace_context * const trace= &join->thd->opt_trace;
+ OPT_TRACE_TRANSFORM(trace, oto0, oto1,
+ select_lex->select_number, "IN (SELECT)", "semijoin");
+ oto1.add("chosen", chose_semijoin);
+ }
+
+ if (!chose_semijoin &&
+ thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MATERIALIZATION) &&
+ (subq_predicate_substype == Item_subselect::IN_SUBS))
{
- DBUG_PRINT("info", ("Subquery can't be converted to semi-join"));
/*
Check if the subquery predicate can be executed via materialization.
- The required conditions are:
- 1. Subquery predicate is an IN/=ANY subquery predicate
- 2. Subquery is a single SELECT (not a UNION)
- 3. Subquery is not a table-less query. In this case there is no
- point in materializing.
- 3A The upper query is not a confluent SELECT ... FROM DUAL. We
- can't do materialization for SELECT .. FROM DUAL because it
- does not call setup_subquery_materialization(). We could make
- SELECT ... FROM DUAL call that function but that doesn't seem
- to be the case that is worth handling.
- 4. Subquery predicate is a top-level predicate
- (this implies it is not negated)
- TODO: this is a limitation that should be lifted once we
- implement correct NULL semantics (WL#3830)
- 5. Subquery is non-correlated
- TODO:
- This is an overly restrictive condition. It can be extended to:
- (Subquery is non-correlated ||
- Subquery is correlated to any query outer to IN predicate ||
- (Subquery is correlated to the immediate outer query &&
- Subquery !contains {GROUP BY, ORDER BY [LIMIT],
- aggregate functions}) && subquery predicate is not under "NOT IN"))
- 6. No execution method was already chosen (by a prepared statement).
- 7. Involved expression types allow materialization (temporary only)
-
- (*) The subquery must be part of a SELECT or CREATE SELECT statement. We
- should relax this and allow it in multi/single-table UPDATE/DELETE,
- INSERT SELECT (after studying potential problems when the
- inserts/updates/deletes are done to a table which is itself part of
- the subquery).
We have to determine whether we will perform subquery materialization
before calling the IN=>EXISTS transformation, so that we know whether to
perform the whole transformation or only that part of it which wraps
Item_in_subselect in an Item_in_optimizer.
*/
- Item_in_subselect *in_predicate= (Item_in_subselect *)subq_predicate;
-
- if (thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MATERIALIZATION) &&
- subq_predicate_substype == Item_subselect::IN_SUBS && // 1
- !select_lex->is_part_of_union() && // 2
- select_lex->master_unit()->first_select()->leaf_tables && // 3
- (thd->lex->sql_command == SQLCOM_SELECT ||
- thd->lex->sql_command == SQLCOM_CREATE_TABLE) && // *
- outer->leaf_tables && // 3A
- in_predicate->is_top_level_item() && // 4
- !in_predicate->is_correlated && // 5
- in_predicate->exec_method ==
- Item_exists_subselect::EXEC_UNSPECIFIED) // 6
- {
- if (subquery_types_allow_materialization(in_predicate)) // 7
- {
- in_predicate->exec_method=
- Item_exists_subselect::EXEC_MATERIALIZATION;
- sq_choice= SQ_MATERIALIZATION;
- }
- else
- types_problem= true;
- }
- }
-
- Opt_trace_context * const trace= &join->thd->opt_trace;
- if (subq_predicate_substype == Item_subselect::IN_SUBS)
- {
- {
- OPT_TRACE_TRANSFORM(trace, oto, oto1, select_lex->select_number,
- "IN (SELECT)", "semijoin");
- oto1.add("chosen", sq_choice == SQ_SEMIJOIN);
- }
- if (sq_choice != SQ_SEMIJOIN)
- {
- OPT_TRACE_TRANSFORM(trace, oto0, oto1, select_lex->select_number,
- "IN (SELECT)", "materialization");
- oto1.add("chosen", sq_choice == SQ_MATERIALIZATION);
- if (types_problem)
- oto1.add_alnum("cause", "field_types");
- }
+ Item_in_subselect *in_predicate= static_cast<Item_in_subselect *>
+ (subq_predicate);
+ if (subquery_allows_materialization(in_predicate, thd, select_lex, outer))
+ in_predicate->exec_method=
+ Item_exists_subselect::EXEC_MATERIALIZATION;
}
- if (sq_choice != SQ_SEMIJOIN &&
+ if (!chose_semijoin &&
subq_predicate->select_transformer(join) == Item_subselect::RES_ERROR)
DBUG_RETURN(TRUE);
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2012-02-01 09:59:13 +0000
+++ b/sql/sql_select.cc 2012-02-08 15:25:17 +0000
@@ -1510,7 +1510,10 @@ bool create_ref_for_key(JOIN *join, JOIN
instead of JT_REF_OR_NULL in case if field can't be null
*/
if ((keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL) && maybe_null)
- null_ref_key= key_buff;
+ {
+ DBUG_ASSERT(null_ref_key == NULL); // or we would overwrite it below
+ null_ref_key= key_buff;
+ }
key_buff+=keyinfo->key_part[part_no].store_length;
}
} /* not ftkey */
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (guilhem.bichot:3870) | Guilhem Bichot | 10 Feb |