diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index cf5076724d1..894384d5bfc 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -848,4 +848,61 @@ SELECT * FROM t1 WHERE t1.a IN (SELECT b FROM (SELECT t2.b FROM t2 WHERE NOT EXISTS (SELECT 1 FROM t3) GROUP BY b) sq); a DROP TABLE t1, t2, t3; +# +# MDEV-23878: Wrong result with semi-join and splittable derived table +# +CREATE TABLE t1 ( +groupId int, +id int unsigned, +PRIMARY KEY (groupId, id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +INSERT INTO t1 VALUES +(8,1),(8,2),(8,3),(8,4),(8,5),(8,6),(8,7),(8,8),(8,9),(8,10), +(8,11),(8,12),(8,13),(8,14),(8,15),(8,16),(8,17),(8,18),(8,19); +set statement in_predicate_conversion_threshold=2 for SELECT COUNT(*) AS cnt FROM t1 +JOIN +( +SELECT groupId, id +FROM t1 +WHERE id IN (1,2,3,4,5,6) +GROUP BY groupId, id +) AS t2 +USING (groupId, id) +WHERE id IN (1,2,3,4,5,6,7,8); +cnt +6 +set statement in_predicate_conversion_threshold=2 for EXPLAIN SELECT COUNT(*) AS cnt FROM t1 +JOIN +( +SELECT groupId, id +FROM t1 +WHERE id IN (1,2,3,4,5,6) +GROUP BY groupId, id +) AS t2 +USING (groupId, id) +WHERE id IN (1,2,3,4,5,6,7,8); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index PRIMARY PRIMARY 8 NULL 19 Using index +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 Using where +1 PRIMARY ref key0 key0 8 test.t1.groupId,test.t1.id 2 +4 MATERIALIZED ALL NULL NULL NULL NULL 8 +5 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +3 LATERAL DERIVED t1 eq_ref PRIMARY PRIMARY 8 test.t1.groupId,test.t1.id 1 Using index +3 LATERAL DERIVED ref key0 key0 4 test.t1.id 2 Using where; FirstMatch(t1) +7 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +set statement optimizer_switch='split_materialized=off, loosescan=off' for +set statement in_predicate_conversion_threshold=2 for +SELECT COUNT(*) AS cnt FROM t1 +JOIN +( +SELECT groupId, id +FROM t1 +WHERE id IN (1,2,3,4,5,6) +GROUP BY groupId, id +) AS t2 +USING (groupId, id) +WHERE id IN (1,2,3,4,5,6,7,8); +cnt +6 +DROP TABLE t1; # End of 10.4 tests diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index 0909e3de9a6..d7756cb8fc5 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -503,4 +503,46 @@ SELECT * FROM t1 WHERE t1.a IN (SELECT b FROM DROP TABLE t1, t2, t3; +--echo # +--echo # MDEV-23878: Wrong result with semi-join and splittable derived table +--echo # + +CREATE TABLE t1 ( + groupId int, + id int unsigned, + PRIMARY KEY (groupId, id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO t1 VALUES + (8,1),(8,2),(8,3),(8,4),(8,5),(8,6),(8,7),(8,8),(8,9),(8,10), + (8,11),(8,12),(8,13),(8,14),(8,15),(8,16),(8,17),(8,18),(8,19); + +let $query= +SELECT COUNT(*) AS cnt FROM t1 +JOIN +( + SELECT groupId, id + FROM t1 + WHERE id IN (1,2,3,4,5,6) + GROUP BY groupId, id +) AS t2 +USING (groupId, id) +WHERE id IN (1,2,3,4,5,6,7,8); + +let $tvc_conversion_threshold = + set statement in_predicate_conversion_threshold=2 for; + +eval $tvc_conversion_threshold $query; +eval $tvc_conversion_threshold EXPLAIN $query; + +let $no_split_materialized_loosescan= + set statement optimizer_switch='split_materialized=off, loosescan=off' for; + +# Correct result with split materializied optimization disabled +eval $no_split_materialized_loosescan + $tvc_conversion_threshold + $query; + +DROP TABLE t1; + --echo # End of 10.4 tests diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 63d430384b8..0d479bbda3e 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -1332,6 +1332,7 @@ bool JOIN::fix_all_splittings_in_plan() { table_map prev_tables= 0; table_map all_tables= (table_map(1) << table_count) - 1; + table_map prev_sjm_lookup_tables= 0; for (uint tablenr= 0; tablenr < table_count; tablenr++) { POSITION *cur_pos= &best_positions[tablenr]; @@ -1340,7 +1341,7 @@ bool JOIN::fix_all_splittings_in_plan() { SplM_plan_info *spl_plan= cur_pos->spl_plan; table_map excluded_tables= (all_tables & ~prev_tables) | - sjm_lookup_tables; + prev_sjm_lookup_tables; ; if (spl_plan) { @@ -1358,6 +1359,8 @@ bool JOIN::fix_all_splittings_in_plan() return true; } prev_tables|= tab->table->map; + if (cur_pos->sj_strategy == SJ_OPT_MATERIALIZE) + prev_sjm_lookup_tables|= tab->table->map; } return false; }