diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 74049298981..434b3b46351 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4975,3 +4975,39 @@ k 3 drop table t1,t2,t3; drop view v2; +# +# Bug#52068: Optimizer generates invalid semijoin materialization plan +# +drop table if exists ot1, ot2, it1, it2; +CREATE TABLE ot1(a INTEGER); +INSERT INTO ot1 VALUES(5), (8); +CREATE TABLE it2(a INTEGER); +INSERT INTO it2 VALUES(9), (5), (1), (8); +CREATE TABLE it3(a INTEGER); +INSERT INTO it3 VALUES(7), (1), (0), (5), (1), (4); +CREATE TABLE ot4(a INTEGER); +INSERT INTO ot4 VALUES(1), (3), (5), (7), (9), (7), (3), (1); +SELECT * FROM ot1,ot4 +WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a +FROM it2,it3); +a a +5 1 +8 1 +5 5 +8 5 +5 7 +8 7 +5 7 +8 7 +5 1 +8 1 +explain SELECT * FROM ot1,ot4 +WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a +FROM it2,it3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 +1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 24 +1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) +2 SUBQUERY it2 ALL NULL NULL NULL NULL 4 +2 SUBQUERY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) +DROP TABLE IF EXISTS ot1, ot4, it2, it3; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 46e99151fb7..563762eedde 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -4978,6 +4978,41 @@ k 3 drop table t1,t2,t3; drop view v2; +# +# Bug#52068: Optimizer generates invalid semijoin materialization plan +# +drop table if exists ot1, ot2, it1, it2; +CREATE TABLE ot1(a INTEGER); +INSERT INTO ot1 VALUES(5), (8); +CREATE TABLE it2(a INTEGER); +INSERT INTO it2 VALUES(9), (5), (1), (8); +CREATE TABLE it3(a INTEGER); +INSERT INTO it3 VALUES(7), (1), (0), (5), (1), (4); +CREATE TABLE ot4(a INTEGER); +INSERT INTO ot4 VALUES(1), (3), (5), (7), (9), (7), (3), (1); +SELECT * FROM ot1,ot4 +WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a +FROM it2,it3); +a a +5 1 +8 1 +5 5 +8 5 +5 7 +8 7 +5 7 +8 7 +5 1 +8 1 +explain SELECT * FROM ot1,ot4 +WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a +FROM it2,it3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 Start temporary +1 PRIMARY it2 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +1 PRIMARY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) +1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; End temporary; Using join buffer (flat, BNL join) +DROP TABLE IF EXISTS ot1, ot4, it2, it3; set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; @@optimizer_switch like '%materialization=on%' diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index d697e2dbbc8..ee2e58b3e0c 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -4975,4 +4975,39 @@ k 3 drop table t1,t2,t3; drop view v2; +# +# Bug#52068: Optimizer generates invalid semijoin materialization plan +# +drop table if exists ot1, ot2, it1, it2; +CREATE TABLE ot1(a INTEGER); +INSERT INTO ot1 VALUES(5), (8); +CREATE TABLE it2(a INTEGER); +INSERT INTO it2 VALUES(9), (5), (1), (8); +CREATE TABLE it3(a INTEGER); +INSERT INTO it3 VALUES(7), (1), (0), (5), (1), (4); +CREATE TABLE ot4(a INTEGER); +INSERT INTO ot4 VALUES(1), (3), (5), (7), (9), (7), (3), (1); +SELECT * FROM ot1,ot4 +WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a +FROM it2,it3); +a a +5 1 +8 1 +5 5 +8 5 +5 7 +8 7 +5 7 +8 7 +5 1 +8 1 +explain SELECT * FROM ot1,ot4 +WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a +FROM it2,it3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 +1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) +2 DEPENDENT SUBQUERY it2 ALL NULL NULL NULL NULL 4 Using where +2 DEPENDENT SUBQUERY it3 ALL NULL NULL NULL NULL 6 Using where; Using join buffer (flat, BNL join) +DROP TABLE IF EXISTS ot1, ot4, it2, it3; set optimizer_switch=default; diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 1eae8184dfd..07655f837a3 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -4975,4 +4975,39 @@ k 3 drop table t1,t2,t3; drop view v2; +# +# Bug#52068: Optimizer generates invalid semijoin materialization plan +# +drop table if exists ot1, ot2, it1, it2; +CREATE TABLE ot1(a INTEGER); +INSERT INTO ot1 VALUES(5), (8); +CREATE TABLE it2(a INTEGER); +INSERT INTO it2 VALUES(9), (5), (1), (8); +CREATE TABLE it3(a INTEGER); +INSERT INTO it3 VALUES(7), (1), (0), (5), (1), (4); +CREATE TABLE ot4(a INTEGER); +INSERT INTO ot4 VALUES(1), (3), (5), (7), (9), (7), (3), (1); +SELECT * FROM ot1,ot4 +WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a +FROM it2,it3); +a a +5 1 +8 1 +5 5 +8 5 +5 7 +8 7 +5 7 +8 7 +5 1 +8 1 +explain SELECT * FROM ot1,ot4 +WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a +FROM it2,it3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ot1 ALL NULL NULL NULL NULL 2 +1 PRIMARY ot4 ALL NULL NULL NULL NULL 8 Using where; Using join buffer (flat, BNL join) +2 SUBQUERY it2 ALL NULL NULL NULL NULL 4 +2 SUBQUERY it3 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join) +DROP TABLE IF EXISTS ot1, ot4, it2, it3; set optimizer_switch=default; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index d1ca98962d6..047987da3f7 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4251,3 +4251,30 @@ select * from t3 where k in (select j from v2); drop table t1,t2,t3; drop view v2; + +--echo # +--echo # Bug#52068: Optimizer generates invalid semijoin materialization plan +--echo # +--disable_warnings +drop table if exists ot1, ot2, it1, it2; +--enable_warnings +CREATE TABLE ot1(a INTEGER); +INSERT INTO ot1 VALUES(5), (8); +CREATE TABLE it2(a INTEGER); +INSERT INTO it2 VALUES(9), (5), (1), (8); +CREATE TABLE it3(a INTEGER); +INSERT INTO it3 VALUES(7), (1), (0), (5), (1), (4); +CREATE TABLE ot4(a INTEGER); +INSERT INTO ot4 VALUES(1), (3), (5), (7), (9), (7), (3), (1); + +let $query= +SELECT * FROM ot1,ot4 +WHERE (ot1.a,ot4.a) IN (SELECT it2.a,it3.a + FROM it2,it3); + +eval $query; +eval explain $query; + +DROP TABLE IF EXISTS ot1, ot4, it2, it3; + + diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index 2c28aae781c..501ec0faf23 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -169,9 +169,17 @@ JOIN_TAB *JOIN_CACHE::get_next_table(JOIN_TAB *tab) if (join_tab->first_sjm_sibling) return tab; uint i= tab-join->join_tab; + /* + Temporary measure before MWL#90 refactorings are there: if 'tab' is at upper + level (i.e. it's not inside an SJM nest), still include into the join buffer + the tables from within SJM nest. We might need the subquery's select list + columns, because SJ-Materialization-Scan upacks data to those. + while (sj_is_materialize_strategy(join->best_positions[i].sj_strategy) && i < join->tables) i+= join->best_positions[i].n_sj_tables; + + */ return join->join_tab+i < join_tab ? join->join_tab+i : NULL; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 16fbb309d89..b3078bd3d47 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13168,6 +13168,15 @@ sub_select_sjm(JOIN *join, JOIN_TAB *join_tab, bool end_of_records) last_tab->read_record.read_record= rr_sequential_and_unpack; } } + else + { + if (sjm->is_sj_scan) + { + /* Reset the cursor for a new scan over the table */ + if (sjm->table->file->ha_rnd_init(TRUE)) + DBUG_RETURN(NESTED_LOOP_ERROR); + } + } if (sjm->is_sj_scan) {