diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index db869ba434a0725f91772b8056443bb74e1ed395..11114a032f93754256df8a1099982e985923164c 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5486,4 +5486,52 @@ i set join_cache_level = default; set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +# +# Bug #12546542: missing row with semijoin=off + join cache +# (LP bug #922971) +# +CREATE TABLE t1 (a varchar(1024)); +INSERT INTO t1 VALUES ('v'), ('we'); +CREATE TABLE t2 ( +a varchar(1024) CHARACTER SET utf8 DEFAULT NULL, b int, c int +); +INSERT INTO t2 VALUES ('we',4,NULL), ('v',1305673728,6); +CREATE TABLE t3 (b int, c int); +INSERT INTO t3 VALUES (4,4); +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off'; +set optimizer_switch='materialization=off'; +set join_cache_level=0; +EXPLAIN +SELECT * FROM t1 +WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b +WHERE t2.c < 10 OR t3.c > 1); +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 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 1 Using where +SELECT * FROM t1 +WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b +WHERE t2.c < 10 OR t3.c > 1); +a +v +we +set join_cache_level=2; +EXPLAIN +SELECT * FROM t1 +WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b +WHERE t2.c < 10 OR t3.c > 1); +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 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (flat, BNL join) +SELECT * FROM t1 +WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b +WHERE t2.c < 10 OR t3.c > 1); +a +v +we +set join_cache_level = default; +set optimizer_switch=@tmp_optimizer_switch; +DROP TABLE t1,t2,t3; set @@optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index cc1941e16b925fe6b7b9ca0542595d40d61ab6fc..8a61c00b7d432369ab99c5909106b83a79ceaf50 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3505,5 +3505,47 @@ set optimizer_switch=@tmp_optimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # Bug #12546542: missing row with semijoin=off + join cache +--echo # (LP bug #922971) +--echo # + +CREATE TABLE t1 (a varchar(1024)); +INSERT INTO t1 VALUES ('v'), ('we'); +CREATE TABLE t2 ( + a varchar(1024) CHARACTER SET utf8 DEFAULT NULL, b int, c int +); +INSERT INTO t2 VALUES ('we',4,NULL), ('v',1305673728,6); +CREATE TABLE t3 (b int, c int); +INSERT INTO t3 VALUES (4,4); + +set @tmp_optimizer_switch=@@optimizer_switch; +set optimizer_switch='semijoin=off'; +set optimizer_switch='materialization=off'; + +set join_cache_level=0; +EXPLAIN +SELECT * FROM t1 + WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b + WHERE t2.c < 10 OR t3.c > 1); + +SELECT * FROM t1 + WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b + WHERE t2.c < 10 OR t3.c > 1); + +set join_cache_level=2; +EXPLAIN +SELECT * FROM t1 + WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b + WHERE t2.c < 10 OR t3.c > 1); +SELECT * FROM t1 + WHERE a IN (SELECT t2.a FROM t2 LEFT JOIN t3 ON t2.b = t3.b + WHERE t2.c < 10 OR t3.c > 1); + +set join_cache_level = default; +set optimizer_switch=@tmp_optimizer_switch; + +DROP TABLE t1,t2,t3; + # this must be the last command in the file set @@optimizer_switch=@save_optimizer_switch; diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index af4b157ba90fa27dab72a6cdf38ddc875ec076f2..2a8db8b4fd1bce12064c052c78d79d08b343ab99 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -2109,16 +2109,6 @@ enum_nested_loop_state JOIN_CACHE::join_records(bool skip_last) if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) goto finish; } - if (outer_join_first_inner) - { - /* - All null complemented rows have been already generated for all - outer records from join buffer. Restore the state of the - first_unmatched values to 0 to avoid another null complementing. - */ - for (tab= join_tab->first_inner; tab <= join_tab->last_inner; tab++) - tab->first_unmatched= 0; - } if (skip_last) { @@ -2131,6 +2121,16 @@ enum_nested_loop_state JOIN_CACHE::join_records(bool skip_last) } finish: + if (outer_join_first_inner) + { + /* + All null complemented rows have been already generated for all + outer records from join buffer. Restore the state of the + first_unmatched values to 0 to avoid another null complementing. + */ + for (tab= join_tab->first_inner; tab <= join_tab->last_inner; tab++) + tab->first_unmatched= 0; + } restore_last_record(); reset(TRUE); DBUG_PRINT("exit", ("rc: %d", rc));