diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result index 2ed58245b54..ea578accaaa 100644 --- a/mysql-test/r/index_merge_myisam.result +++ b/mysql-test/r/index_merge_myisam.result @@ -1594,4 +1594,24 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge a,b,c a,c 5,5 NULL 54 Using sort_union(a,c); Using where set optimizer_switch=default; drop table t0, t1; +# +# BUG#834514 Assertion `!table || (!table->read_set || bitmap_is_set(...' with aggregates +# +CREATE TABLE t1 ( a int , b int, c int, KEY (b), PRIMARY KEY (a)) ; +INSERT INTO t1 VALUES (1,4,0),(5,0,0),(6,7,0),(7,7,0),(8,1,0),(9,7,0),(10,1,0); +CREATE TABLE t2 ( b int, c int, KEY (c,b)) ; +INSERT INTO t2 VALUES (7,0),(1,0),(7,0),(1,0); +CREATE TABLE t3 ( a int ) ; +SELECT COUNT(DISTINCT t2.b), CONCAT(t1.c) +FROM t1, t2 +WHERE (t2.c = t1.c) +AND ( +t1.b IN ( 4 ) +OR t1.a = 137 +AND EXISTS ( SELECT a FROM t3 ) +) +GROUP BY 2; +COUNT(DISTINCT t2.b) CONCAT(t1.c) +2 0 +DROP TABLE t1,t2,t3; set optimizer_switch= @optimizer_switch_save; diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 9acf709a8cc..4a38ccf75b9 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -3,7 +3,7 @@ set @subselect_sj_mat_tmp= @@optimizer_switch; set optimizer_switch=ifnull(@subselect_mat_test_optimizer_switch_value, 'semijoin=on,firstmatch=on,loosescan=on'); set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set @optimizer_switch_local_default= @@optimizer_switch; -drop table if exists t1, t2, t3, t1i, t2i, t3i; +drop table if exists t1, t2, t3, t4, t5, t1i, t2i, t3i; drop table if exists columns; drop table if exists t1_16, t2_16, t3_16; drop view if exists v1, v2, v1m, v2m; @@ -1579,6 +1579,83 @@ GROUP BY 1 , 2; a c 1 2 drop table t1,t2,t3; +# +# BUG#836523: Crash in JOIN::get_partial_cost_and_fanout with semijoin+materialization +# +CREATE TABLE t1 (a varchar(1)); +INSERT INTO t1 VALUES ('a'),('a'); +CREATE TABLE t2 (a varchar(1)); +CREATE TABLE t3 (a int); +INSERT INTO t3 VALUES (1),(2); +CREATE TABLE t4 (a varchar(1)); +INSERT INTO t4 VALUES ('a'),('a'); +SELECT t1.a +FROM t1 +WHERE t1.a IN ( +SELECT t2.a +FROM t2, t3 +) +HAVING a IN ( +SELECT a +FROM t4 +); +a +DROP TABLE t1, t2, t3, t4; +# +# BUG#836507: Crash in setup_sj_materialization_part1() with semijoin+materialization +# +CREATE TABLE t1 (a int) ; +INSERT IGNORE INTO t1 VALUES (1),(1); +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 (a int); +CREATE TABLE t4 (a int); +INSERT INTO t4 VALUES (2),(2); +CREATE TABLE t5 (a int); +INSERT INTO t5 VALUES (1); +SELECT * FROM t1 +WHERE (a) IN ( +SELECT t5.a +FROM ( +t2 +LEFT JOIN ( t3 , t4 ) +ON 1 = 1 +) +JOIN t5 +); +a +1 +1 +DROP TABLE t1,t2,t3,t4,t5; +# +# BUG#836532: Crash in Item_equal_fields_iterator::get_curr_field with semijoin+materialization +# +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES ('a'),('a'); +Warnings: +Warning 1366 Incorrect integer value: 'a' for column 'a' at row 1 +Warning 1366 Incorrect integer value: 'a' for column 'a' at row 2 +CREATE TABLE t4 (a varchar(1)); +INSERT INTO t4 VALUES ('m'),('o'); +CREATE TABLE t3 (a varchar(1) , b varchar(1) ) ; +INSERT INTO t3 VALUES ('b','b'); +CREATE TABLE t5 (a varchar(1), KEY (a)) ; +INSERT INTO t5 VALUES ('d'),('e'); +SELECT * +FROM t2 +WHERE t2.a = ALL ( +SELECT t4.a +FROM t4 +WHERE t4.a IN ( +SELECT t3.a +FROM t3 , t5 +WHERE ( t5.a = t3.b ) +) +); +a +0 +0 +DROP TABLE t2,t3,t4,t5; set optimizer_switch=@subselect_sj_mat_tmp; set @subselect_mat_test_optimizer_switch_value=null; set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off'; diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index 12a3eee2e33..3bbb13dd42d 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -1,4 +1,4 @@ -drop table if exists t0, t1, t2, t3, t4, t10, t11, t12; +drop table if exists t0, t1, t2, t3, t4, t5, t10, t11, t12; drop view if exists v1, v2, v3, v4; drop procedure if exists p1; set @subselect_sj_tmp= @@optimizer_switch; @@ -1749,4 +1749,66 @@ FROM t2 ); a drop table t1, t2,t3; +# +# BUG#834758: Wrong result with innner join, LooseScan, two-column IN() predicate +# +set @tmp835758=@@optimizer_switch; +set optimizer_switch='semijoin=on,loosescan=on,materialization=off,firstmatch=off'; +CREATE TABLE t1 (b int) ; +INSERT INTO t1 VALUES (1),(5); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ; +INSERT INTO t2 VALUES (6),(10); +CREATE TABLE t3 (a int, b int, KEY (b)) ; +INSERT INTO t3 VALUES (6,5),(6,2),(8,0),(9,1),(6,5); +# This used to incorrectly pick a join order of (t1, LooseScan(t3), t2): +explain +SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Start temporary +1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 2 Using index; Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL b NULL NULL NULL 5 Using where; End temporary; Using join buffer (flat, BNL join) +SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); +b a +5 6 +DROP TABLE t1, t2, t3; +set @@optimizer_switch= @tmp835758; +# +# BUG#834739: Wrong result with 3-way inner join, LooseScan,multipart keys +# +set @tmp834739=@@optimizer_switch; +set optimizer_switch='semijoin=on,loosescan=on,materialization=off,firstmatch=off'; +CREATE TABLE t2 ( b int, c int, KEY (b)) ; +INSERT INTO t2 VALUES (1,0),(1,0),(9,0),(1,0),(5,0); +CREATE TABLE t3 ( a int); +INSERT INTO t3 VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0); +CREATE TABLE t4 ( a int); +INSERT INTO t4 VALUES (0),(0),(0); +CREATE TABLE t5 ( b int, a int , KEY (a,b)) ; +INSERT INTO t5 VALUES (7,0),(9,0); +explain +SELECT * FROM t3 WHERE t3.a IN (SELECT t5.a FROM t2, t4, t5 WHERE t2.c = t5.a AND t2.b = t5.b); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t5 index a a 10 NULL 2 Using where; Using index; LooseScan +1 PRIMARY t4 ALL NULL NULL NULL NULL 3 +1 PRIMARY t2 ref b b 5 test.t5.b 2 Using where; FirstMatch(t5) +1 PRIMARY t3 ALL NULL NULL NULL NULL 15 Using where; Using join buffer (flat, BNL join) +SELECT * FROM t3 WHERE t3.a IN (SELECT t5.a FROM t2, t4, t5 WHERE t2.c = t5.a AND t2.b = t5.b); +a +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +DROP TABLE t2, t3, t4, t5; +set @@optimizer_switch=@tmp834739; set optimizer_switch=@subselect_sj_tmp; diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index ef14f2b642a..f3c56084279 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -9,7 +9,7 @@ set join_cache_level=6; show variables like 'join_cache_level'; Variable_name Value join_cache_level 6 -drop table if exists t0, t1, t2, t3, t4, t10, t11, t12; +drop table if exists t0, t1, t2, t3, t4, t5, t10, t11, t12; drop view if exists v1, v2, v3, v4; drop procedure if exists p1; set @subselect_sj_tmp= @@optimizer_switch; @@ -1760,6 +1760,68 @@ FROM t2 ); a drop table t1, t2,t3; +# +# BUG#834758: Wrong result with innner join, LooseScan, two-column IN() predicate +# +set @tmp835758=@@optimizer_switch; +set optimizer_switch='semijoin=on,loosescan=on,materialization=off,firstmatch=off'; +CREATE TABLE t1 (b int) ; +INSERT INTO t1 VALUES (1),(5); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ; +INSERT INTO t2 VALUES (6),(10); +CREATE TABLE t3 (a int, b int, KEY (b)) ; +INSERT INTO t3 VALUES (6,5),(6,2),(8,0),(9,1),(6,5); +# This used to incorrectly pick a join order of (t1, LooseScan(t3), t2): +explain +SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Start temporary +1 PRIMARY t2 index PRIMARY PRIMARY 4 NULL 2 Using index; Using join buffer (flat, BNL join) +1 PRIMARY t3 ALL b NULL NULL NULL 5 Using where; End temporary; Using join buffer (incremental, BNL join) +SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); +b a +5 6 +DROP TABLE t1, t2, t3; +set @@optimizer_switch= @tmp835758; +# +# BUG#834739: Wrong result with 3-way inner join, LooseScan,multipart keys +# +set @tmp834739=@@optimizer_switch; +set optimizer_switch='semijoin=on,loosescan=on,materialization=off,firstmatch=off'; +CREATE TABLE t2 ( b int, c int, KEY (b)) ; +INSERT INTO t2 VALUES (1,0),(1,0),(9,0),(1,0),(5,0); +CREATE TABLE t3 ( a int); +INSERT INTO t3 VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0); +CREATE TABLE t4 ( a int); +INSERT INTO t4 VALUES (0),(0),(0); +CREATE TABLE t5 ( b int, a int , KEY (a,b)) ; +INSERT INTO t5 VALUES (7,0),(9,0); +explain +SELECT * FROM t3 WHERE t3.a IN (SELECT t5.a FROM t2, t4, t5 WHERE t2.c = t5.a AND t2.b = t5.b); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t5 index a a 10 NULL 2 Using where; Using index; LooseScan +1 PRIMARY t4 ALL NULL NULL NULL NULL 3 +1 PRIMARY t2 ref b b 5 test.t5.b 2 Using where; FirstMatch(t5) +1 PRIMARY t3 ALL NULL NULL NULL NULL 15 Using where; Using join buffer (flat, BNL join) +SELECT * FROM t3 WHERE t3.a IN (SELECT t5.a FROM t2, t4, t5 WHERE t2.c = t5.a AND t2.b = t5.b); +a +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +DROP TABLE t2, t3, t4, t5; +set @@optimizer_switch=@tmp834739; set optimizer_switch=@subselect_sj_tmp; # # BUG#49129: Wrong result with IN-subquery with join_cache_level=6 and firstmatch=off diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index c545863bccb..2ce54609fa4 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -2,7 +2,7 @@ set @subselect_sj_mat_tmp= @@optimizer_switch; set optimizer_switch=ifnull(@subselect_mat_test_optimizer_switch_value, 'semijoin=on,firstmatch=on,loosescan=on'); set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set @optimizer_switch_local_default= @@optimizer_switch; -drop table if exists t1, t2, t3, t1i, t2i, t3i; +drop table if exists t1, t2, t3, t4, t5, t1i, t2i, t3i; drop table if exists columns; drop table if exists t1_16, t2_16, t3_16; drop view if exists v1, v2, v1m, v2m; @@ -856,15 +856,16 @@ explain extended select left(a1,7), left(a2,7) from t1_1024 where a1 in (select substring(b1,1,1024) from t2_1024 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 -1 PRIMARY eq_ref NULL distinct_key 15 func,func 1 100.00 -2 SUBQUERY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t1_1024 ALL NULL NULL NULL NULL 3 100.00 Start temporary +1 PRIMARY t2_1024 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` semi join (`test`.`t2_1024`) where ((`test`.`t2_1024`.`b1` > '0') and (`test`.`t1_1024`.`a1` = substr(`test`.`t2_1024`.`b1`,1,1024))) select left(a1,7), left(a2,7) from t1_1024 where a1 in (select substring(b1,1,1024) from t2_1024 where b1 > '0'); left(a1,7) left(a2,7) +1 - 01x 2 - 01x +1 - 02x 2 - 02x explain extended select left(a1,7), left(a2,7) from t1_1024 where a1 in (select group_concat(b1) from t2_1024 group by b2); @@ -950,15 +951,16 @@ explain extended select left(a1,7), left(a2,7) from t1_1025 where a1 in (select substring(b1,1,1025) from t2_1025 where b1 > '0'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 -1 PRIMARY eq_ref NULL distinct_key 15 func,func 1 100.00 -2 SUBQUERY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t1_1025 ALL NULL NULL NULL NULL 3 100.00 Start temporary +1 PRIMARY t2_1025 ALL NULL NULL NULL NULL 3 100.00 Using where; End temporary; Using join buffer (flat, BNL join) Warnings: Note 1003 select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` semi join (`test`.`t2_1025`) where ((`test`.`t2_1025`.`b1` > '0') and (`test`.`t1_1025`.`a1` = substr(`test`.`t2_1025`.`b1`,1,1025))) select left(a1,7), left(a2,7) from t1_1025 where a1 in (select substring(b1,1,1025) from t2_1025 where b1 > '0'); left(a1,7) left(a2,7) +1 - 01x 2 - 01x +1 - 02x 2 - 02x explain extended select left(a1,7), left(a2,7) from t1_1025 where a1 in (select group_concat(b1) from t2_1025 group by b2); @@ -1617,4 +1619,81 @@ GROUP BY 1 , 2; a c 1 2 drop table t1,t2,t3; +# +# BUG#836523: Crash in JOIN::get_partial_cost_and_fanout with semijoin+materialization +# +CREATE TABLE t1 (a varchar(1)); +INSERT INTO t1 VALUES ('a'),('a'); +CREATE TABLE t2 (a varchar(1)); +CREATE TABLE t3 (a int); +INSERT INTO t3 VALUES (1),(2); +CREATE TABLE t4 (a varchar(1)); +INSERT INTO t4 VALUES ('a'),('a'); +SELECT t1.a +FROM t1 +WHERE t1.a IN ( +SELECT t2.a +FROM t2, t3 +) +HAVING a IN ( +SELECT a +FROM t4 +); +a +DROP TABLE t1, t2, t3, t4; +# +# BUG#836507: Crash in setup_sj_materialization_part1() with semijoin+materialization +# +CREATE TABLE t1 (a int) ; +INSERT IGNORE INTO t1 VALUES (1),(1); +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 (a int); +CREATE TABLE t4 (a int); +INSERT INTO t4 VALUES (2),(2); +CREATE TABLE t5 (a int); +INSERT INTO t5 VALUES (1); +SELECT * FROM t1 +WHERE (a) IN ( +SELECT t5.a +FROM ( +t2 +LEFT JOIN ( t3 , t4 ) +ON 1 = 1 +) +JOIN t5 +); +a +1 +1 +DROP TABLE t1,t2,t3,t4,t5; +# +# BUG#836532: Crash in Item_equal_fields_iterator::get_curr_field with semijoin+materialization +# +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES ('a'),('a'); +Warnings: +Warning 1366 Incorrect integer value: 'a' for column 'a' at row 1 +Warning 1366 Incorrect integer value: 'a' for column 'a' at row 2 +CREATE TABLE t4 (a varchar(1)); +INSERT INTO t4 VALUES ('m'),('o'); +CREATE TABLE t3 (a varchar(1) , b varchar(1) ) ; +INSERT INTO t3 VALUES ('b','b'); +CREATE TABLE t5 (a varchar(1), KEY (a)) ; +INSERT INTO t5 VALUES ('d'),('e'); +SELECT * +FROM t2 +WHERE t2.a = ALL ( +SELECT t4.a +FROM t4 +WHERE t4.a IN ( +SELECT t3.a +FROM t3 , t5 +WHERE ( t5.a = t3.b ) +) +); +a +0 +0 +DROP TABLE t2,t3,t4,t5; set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/mysql-test/t/index_merge_myisam.test b/mysql-test/t/index_merge_myisam.test index 5431c6dba2b..614c6595d61 100644 --- a/mysql-test/t/index_merge_myisam.test +++ b/mysql-test/t/index_merge_myisam.test @@ -125,5 +125,29 @@ set optimizer_switch=default; drop table t0, t1; + +--echo # +--echo # BUG#834514 Assertion `!table || (!table->read_set || bitmap_is_set(...' with aggregates +--echo # +CREATE TABLE t1 ( a int , b int, c int, KEY (b), PRIMARY KEY (a)) ; +INSERT INTO t1 VALUES (1,4,0),(5,0,0),(6,7,0),(7,7,0),(8,1,0),(9,7,0),(10,1,0); + +CREATE TABLE t2 ( b int, c int, KEY (c,b)) ; +INSERT INTO t2 VALUES (7,0),(1,0),(7,0),(1,0); + +CREATE TABLE t3 ( a int ) ; + +SELECT COUNT(DISTINCT t2.b), CONCAT(t1.c) +FROM t1, t2 +WHERE (t2.c = t1.c) +AND ( + t1.b IN ( 4 ) + OR t1.a = 137 + AND EXISTS ( SELECT a FROM t3 ) +) +GROUP BY 2; + +DROP TABLE t1,t2,t3; + set optimizer_switch= @optimizer_switch_save; diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index a175a2f7cf0..49ecfe86fbc 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -2,7 +2,7 @@ # Nested Loops semi-join subquery evaluation tests # --disable_warnings -drop table if exists t0, t1, t2, t3, t4, t10, t11, t12; +drop table if exists t0, t1, t2, t3, t4, t5, t10, t11, t12; drop view if exists v1, v2, v3, v4; drop procedure if exists p1; --enable_warnings @@ -1594,5 +1594,53 @@ WHERE (t3.a) IN ( ); drop table t1, t2,t3; +--echo # +--echo # BUG#834758: Wrong result with innner join, LooseScan, two-column IN() predicate +--echo # + +set @tmp835758=@@optimizer_switch; +set optimizer_switch='semijoin=on,loosescan=on,materialization=off,firstmatch=off'; + +CREATE TABLE t1 (b int) ; +INSERT INTO t1 VALUES (1),(5); + +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ; +INSERT INTO t2 VALUES (6),(10); + +CREATE TABLE t3 (a int, b int, KEY (b)) ; +INSERT INTO t3 VALUES (6,5),(6,2),(8,0),(9,1),(6,5); + +--echo # This used to incorrectly pick a join order of (t1, LooseScan(t3), t2): +explain +SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); +SELECT * FROM t1, t2 WHERE (t2.a , t1.b) IN (SELECT a, b FROM t3); + +DROP TABLE t1, t2, t3; +set @@optimizer_switch= @tmp835758; + +--echo # +--echo # BUG#834739: Wrong result with 3-way inner join, LooseScan,multipart keys +--echo # +set @tmp834739=@@optimizer_switch; +set optimizer_switch='semijoin=on,loosescan=on,materialization=off,firstmatch=off'; +CREATE TABLE t2 ( b int, c int, KEY (b)) ; +INSERT INTO t2 VALUES (1,0),(1,0),(9,0),(1,0),(5,0); + +CREATE TABLE t3 ( a int); +INSERT INTO t3 VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0); + +CREATE TABLE t4 ( a int); +INSERT INTO t4 VALUES (0),(0),(0); + +CREATE TABLE t5 ( b int, a int , KEY (a,b)) ; +INSERT INTO t5 VALUES (7,0),(9,0); + +explain +SELECT * FROM t3 WHERE t3.a IN (SELECT t5.a FROM t2, t4, t5 WHERE t2.c = t5.a AND t2.b = t5.b); +SELECT * FROM t3 WHERE t3.a IN (SELECT t5.a FROM t2, t4, t5 WHERE t2.c = t5.a AND t2.b = t5.b); + +DROP TABLE t2, t3, t4, t5; +set @@optimizer_switch=@tmp834739; + # The following command must be the last one the file set optimizer_switch=@subselect_sj_tmp; diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index 324b16123c2..95ef6a25df3 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -9,7 +9,7 @@ set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set @optimizer_switch_local_default= @@optimizer_switch; --disable_warnings -drop table if exists t1, t2, t3, t1i, t2i, t3i; +drop table if exists t1, t2, t3, t4, t5, t1i, t2i, t3i; drop table if exists columns; drop table if exists t1_16, t2_16, t3_16; drop view if exists v1, v2, v1m, v2m; @@ -1263,5 +1263,91 @@ GROUP BY 1 , 2; drop table t1,t2,t3; +--echo # +--echo # BUG#836523: Crash in JOIN::get_partial_cost_and_fanout with semijoin+materialization +--echo # +CREATE TABLE t1 (a varchar(1)); +INSERT INTO t1 VALUES ('a'),('a'); + +CREATE TABLE t2 (a varchar(1)); + +CREATE TABLE t3 (a int); +INSERT INTO t3 VALUES (1),(2); + +CREATE TABLE t4 (a varchar(1)); +INSERT INTO t4 VALUES ('a'),('a'); + +SELECT t1.a +FROM t1 +WHERE t1.a IN ( + SELECT t2.a + FROM t2, t3 +) +HAVING a IN ( + SELECT a + FROM t4 +); +DROP TABLE t1, t2, t3, t4; + +--echo # +--echo # BUG#836507: Crash in setup_sj_materialization_part1() with semijoin+materialization +--echo # +CREATE TABLE t1 (a int) ; +INSERT IGNORE INTO t1 VALUES (1),(1); + +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES (1); + +CREATE TABLE t3 (a int); + +CREATE TABLE t4 (a int); +INSERT INTO t4 VALUES (2),(2); + +CREATE TABLE t5 (a int); +INSERT INTO t5 VALUES (1); + +SELECT * FROM t1 +WHERE (a) IN ( + SELECT t5.a + FROM ( + t2 + LEFT JOIN ( t3 , t4 ) + ON 1 = 1 + ) + JOIN t5 +); + +DROP TABLE t1,t2,t3,t4,t5; + +--echo # +--echo # BUG#836532: Crash in Item_equal_fields_iterator::get_curr_field with semijoin+materialization +--echo # + +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES ('a'),('a'); + +CREATE TABLE t4 (a varchar(1)); +INSERT INTO t4 VALUES ('m'),('o'); + +CREATE TABLE t3 (a varchar(1) , b varchar(1) ) ; +INSERT INTO t3 VALUES ('b','b'); + +CREATE TABLE t5 (a varchar(1), KEY (a)) ; +INSERT INTO t5 VALUES ('d'),('e'); + +SELECT * +FROM t2 +WHERE t2.a = ALL ( + SELECT t4.a + FROM t4 + WHERE t4.a IN ( + SELECT t3.a + FROM t3 , t5 + WHERE ( t5.a = t3.b ) + ) +); + +DROP TABLE t2,t3,t4,t5; + set optimizer_switch=@subselect_sj_mat_tmp; diff --git a/sql/filesort.cc b/sql/filesort.cc index 559f4f1dcf6..b3bb15bd7f0 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -624,15 +624,21 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, SQL_SELECT::skip_record evaluates this condition. it may include a correlated subquery predicate, such that some field in the subquery refers to 'sort_form'. + + PSergey-todo: discuss the above with Timour. */ + MY_BITMAP *tmp_read_set= sort_form->read_set; + MY_BITMAP *tmp_write_set= sort_form->write_set; + MY_BITMAP *tmp_vcol_set= sort_form->vcol_set; + if (select->cond->with_subselect) sort_form->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set); write_record= (select->skip_record(thd) > 0); if (select->cond->with_subselect) - sort_form->column_bitmaps_set(&sort_form->tmp_set, - &sort_form->tmp_set, - &sort_form->tmp_set); + sort_form->column_bitmaps_set(tmp_read_set, + tmp_write_set, + tmp_vcol_set); } else write_record= true; diff --git a/sql/item.cc b/sql/item.cc index ca4d41fcbdb..4fcffcfbc2a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5191,6 +5191,10 @@ Field *Item::make_string_field(TABLE *table) { Field *field; DBUG_ASSERT(collation.collation); + /* + Note: the following check is repeated in + subquery_types_allow_materialization(): + */ if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) field= new Field_blob(max_length, maybe_null, name, collation.collation); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 4dbaa4c8c4e..a70d04fccbe 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2264,7 +2264,12 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg) { /* The argument list of the top-level AND may change after fix fields. */ and_args= ((Item_cond*) join_arg->conds)->argument_list(); - and_args->concat((List *) &join_arg->cond_equal->current_level); + List_iterator li(join_arg->cond_equal->current_level); + Item_equal *elem; + while ((elem= li++)) + { + and_args->push_back(elem); + } } } diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 579d7b2d9bc..3cb13b0b88c 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -559,6 +559,16 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs) if (inner->field_type() == MYSQL_TYPE_BLOB || inner->field_type() == MYSQL_TYPE_GEOMETRY) DBUG_RETURN(FALSE); + /* + Materialization also is unable to work when create_tmp_table() will + create a blob column because item->max_length is too big. + The following check is copied from Item::make_string_field(): + */ + if (inner->max_length / inner->collation.collation->mbmaxlen > + CONVERT_IF_BIGGER_TO_BLOB) + { + DBUG_RETURN(FALSE); + } break; case TIME_RESULT: if (mysql_type_to_time_type(outer->field_type()) != @@ -2639,6 +2649,7 @@ ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest, { res |= 1ULL << i; } + i++; } return res; } @@ -2935,6 +2946,11 @@ bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab) DBUG_ENTER("setup_sj_materialization"); JOIN_TAB *tab= sjm_tab->bush_children->start; TABLE_LIST *emb_sj_nest= tab->table->pos_in_table_list->embedding; + + /* Walk out of outer join nests until we reach the semi-join nest we're in */ + while (!emb_sj_nest->sj_mat_info) + emb_sj_nest= emb_sj_nest->embedding; + SJ_MATERIALIZATION_INFO *sjm= emb_sj_nest->sj_mat_info; THD *thd= tab->join->thd; /* First the calls come to the materialization function */ @@ -2983,6 +2999,9 @@ bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab) DBUG_ENTER("setup_sj_materialization_part2"); JOIN_TAB *tab= sjm_tab->bush_children->start; TABLE_LIST *emb_sj_nest= tab->table->pos_in_table_list->embedding; + /* Walk out of outer join nests until we reach the semi-join nest we're in */ + while (!emb_sj_nest->sj_mat_info) + emb_sj_nest= emb_sj_nest->embedding; SJ_MATERIALIZATION_INFO *sjm= emb_sj_nest->sj_mat_info; THD *thd= tab->join->thd; uint i; @@ -3818,6 +3837,8 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, { /* We jump from the last table to the first one */ tab->loosescan_match_tab= tab + pos->n_sj_tables - 1; + for (uint j= i; j < pos->n_sj_tables; j++) + join->join_tab[j].inside_loosescan_range= TRUE; /* Calculate key length */ keylen= 0; @@ -4478,20 +4499,6 @@ bool JOIN::choose_subquery_plan(table_map join_tables) outer_join= unit->outer_select() ? unit->outer_select()->join : NULL; if (outer_join && outer_join->table_count > 0) { - /* - The index of the last JOIN_TAB in the outer JOIN where in_subs is - attached (pushed to). - */ - uint max_outer_join_tab_idx; - /* - Make_cond_for_table is called for predicates only in the WHERE/ON - clauses. In all other cases, predicates are not pushed to any - JOIN_TAB, and their join_tab_idx remains MAX_TABLES. Such predicates - are evaluated for each complete row of the outer join. - */ - max_outer_join_tab_idx= (in_subs->get_join_tab_idx() == MAX_TABLES) ? - outer_join->table_count - 1: - in_subs->get_join_tab_idx(); /* TODO: Currently outer_lookup_keys is computed as the number of rows in @@ -4504,7 +4511,7 @@ bool JOIN::choose_subquery_plan(table_map join_tables) If the join order: t1, t2, the number of unique lookup keys is ~ to the number of unique values t2.c2 in the partial join t1 join t2. */ - outer_join->get_partial_cost_and_fanout(max_outer_join_tab_idx, + outer_join->get_partial_cost_and_fanout(in_subs->get_join_tab_idx(), table_map(-1), &dummy, &outer_lookup_keys); diff --git a/sql/sql_list.h b/sql/sql_list.h index 50673921aeb..4655b4e3577 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -310,6 +310,26 @@ public: friend class error_list; friend class error_list_iterator; + /* + Debugging help: return N-th element in the list, or NULL if the list has + less than N elements. + */ + inline void *nth_element(int n) + { + list_node *node= first; + void *data= NULL; + for (int i=0; i <= n; i++) + { + if (node == &end_of_list) + { + data= NULL; + break; + } + data= node->info; + node= node->next; + } + return data; + } #ifdef LIST_EXTRA_DEBUG /* Check list invariants and print results into trace. Invariants are: @@ -488,6 +508,7 @@ public: } empty(); } + inline T *nth_element(int n) { return (T*)base_list::nth_element(n); } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f4bd8705e5e..a3f2562d1d9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -175,14 +175,14 @@ int join_read_always_key_or_null(JOIN_TAB *tab); int join_read_next_same_or_null(READ_RECORD *info); static COND *make_cond_for_table(THD *thd, Item *cond,table_map table, table_map used_table, - uint join_tab_idx_arg, + int join_tab_idx_arg, bool exclude_expensive_cond, bool retain_ref_cond); static COND *make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond, table_map tables, table_map used_table, - uint join_tab_idx_arg, + int join_tab_idx_arg, bool exclude_expensive_cond, bool retain_ref_cond); @@ -1088,7 +1088,7 @@ JOIN::optimize() if (conds && !(thd->lex->describe & DESCRIBE_EXTENDED)) { COND *table_independent_conds= - make_cond_for_table(thd, conds, PSEUDO_TABLE_BITS, 0, MAX_TABLES, + make_cond_for_table(thd, conds, PSEUDO_TABLE_BITS, 0, -1, FALSE, FALSE); DBUG_EXECUTE("where", print_where(table_independent_conds, @@ -2535,7 +2535,7 @@ JOIN::exec() Item* sort_table_cond= make_cond_for_table(thd, curr_join->tmp_having, used_tables, - (table_map)0, MAX_TABLES, + (table_map)0, -1, FALSE, FALSE); if (sort_table_cond) { @@ -2573,7 +2573,7 @@ JOIN::exec() QT_ORDINARY);); curr_join->tmp_having= make_cond_for_table(thd, curr_join->tmp_having, ~ (table_map) 0, - ~used_tables, MAX_TABLES, + ~used_tables, -1, FALSE, FALSE); DBUG_EXECUTE("where",print_where(curr_join->tmp_having, "having after sort", @@ -6047,7 +6047,7 @@ greedy_search(JOIN *join, read_time_arg and record_count_arg contain the computed cost and fanout */ -void JOIN::get_partial_cost_and_fanout(uint end_tab_idx, +void JOIN::get_partial_cost_and_fanout(int end_tab_idx, table_map filter_map, double *read_time_arg, double *record_count_arg) @@ -6057,14 +6057,14 @@ void JOIN::get_partial_cost_and_fanout(uint end_tab_idx, double sj_inner_fanout= 1.0; JOIN_TAB *end_tab= NULL; JOIN_TAB *tab; - uint i; - uint last_sj_table= MAX_TABLES; + int i; + int last_sj_table= MAX_TABLES; /* Handle a special case where the join is degenerate, and produces no records */ - if (table_count == 0) + if (table_count == const_tables) { *read_time_arg= 0.0; /* @@ -6074,6 +6074,7 @@ void JOIN::get_partial_cost_and_fanout(uint end_tab_idx, calculations. */ *record_count_arg=1.0; + return; } for (tab= first_depth_first_tab(this), i= const_tables; @@ -6086,19 +6087,17 @@ void JOIN::get_partial_cost_and_fanout(uint end_tab_idx, } for (tab= first_depth_first_tab(this), i= const_tables; - (i <= end_tab_idx && tab); + ; tab= next_depth_first_tab(this, tab), i++) { - /* - We've entered the SJM nest that contains the end_tab. The caller is - actually - - interested in fanout inside the nest (because that's how many times - we'll invoke the attached WHERE conditions) - - not interested in cost - */ if (end_tab->bush_root_tab && end_tab->bush_root_tab == tab) { - /* Ok, end_tab is inside SJM nest and we're entering that nest now */ + /* + We've entered the SJM nest that contains the end_tab. The caller is + - interested in fanout inside the nest (because that's how many times + we'll invoke the attached WHERE conditions) + - not interested in cost + */ record_count= 1.0; read_time= 0.0; } @@ -6112,8 +6111,18 @@ void JOIN::get_partial_cost_and_fanout(uint end_tab_idx, sj_inner_fanout= 1.0; last_sj_table= i + tab->n_sj_tables; } - - if (tab->records_read && (tab->table->map & filter_map)) + + table_map cur_table_map; + if (tab->table) + cur_table_map= tab->table->map; + else + { + /* This is a SJ-Materialization nest. Check all of its tables */ + TABLE *first_child= tab->bush_children->start->table; + TABLE_LIST *sjm_nest= first_child->pos_in_table_list->embedding; + cur_table_map= sjm_nest->nested_join->used_tables; + } + if (tab->records_read && (cur_table_map & filter_map)) { record_count *= tab->records_read; read_time += tab->read_time; @@ -6127,6 +6136,9 @@ void JOIN::get_partial_cost_and_fanout(uint end_tab_idx, sj_inner_fanout= 1.0; last_sj_table= MAX_TABLES; } + + if (tab == end_tab) + break; } *read_time_arg= read_time;// + record_count / TIME_FOR_COMPARE; *record_count_arg= record_count; @@ -6615,7 +6627,7 @@ int JOIN_TAB::make_scan_filter() if (cond && (tmp= make_cond_for_table(join->thd, cond, join->const_table_map | table->map, - table->map, MAX_TABLES, FALSE, TRUE))) + table->map, -1, FALSE, TRUE))) { DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY);); if (!(cache_select= @@ -7087,6 +7099,7 @@ get_best_combination(JOIN *join) goto loop_end; // Handled in make_join_stat.. j->loosescan_match_tab= NULL; //non-nulls will be set later + j->inside_loosescan_range= FALSE; j->ref.key = -1; j->ref.key_parts=0; @@ -7901,7 +7914,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) join->exec_const_cond= make_cond_for_table(thd, cond, join->const_table_map, - (table_map) 0, MAX_TABLES, FALSE, FALSE); + (table_map) 0, -1, FALSE, FALSE); /* Add conditions added by add_not_null_conds(). */ for (uint i= 0 ; i < join->const_tables ; i++) add_cond_and_fix(thd, &join->exec_const_cond, @@ -7920,7 +7933,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) COND *outer_ref_cond= make_cond_for_table(thd, cond, OUTER_REF_TABLE_BIT, OUTER_REF_TABLE_BIT, - MAX_TABLES, FALSE, FALSE); + -1, FALSE, FALSE); if (outer_ref_cond) { add_cond_and_fix(thd, &outer_ref_cond, join->outer_ref_cond); @@ -8090,7 +8103,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) { COND *push_cond= make_cond_for_table(thd, tmp, current_map, current_map, - MAX_TABLES, FALSE, FALSE); + -1, FALSE, FALSE); if (push_cond) { /* Push condition to handler */ @@ -8262,7 +8275,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) JOIN_TAB *cond_tab= join_tab->first_inner; COND *tmp= make_cond_for_table(thd, *join_tab->on_expr_ref, join->const_table_map, - (table_map) 0, MAX_TABLES, FALSE, FALSE); + (table_map) 0, -1, FALSE, FALSE); if (!tmp) continue; tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl); @@ -8308,10 +8321,10 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) current_map= tab->table->map; used_tables2|= current_map; /* - psergey: have put the MAX_TABLES below. It's bad, will need to fix it. + psergey: have put the -1 below. It's bad, will need to fix it. */ COND *tmp_cond= make_cond_for_table(thd, on_expr, used_tables2, - current_map, /*(tab - first_tab)*/ MAX_TABLES, + current_map, /*(tab - first_tab)*/ -1, FALSE, FALSE); if (tab == first_inner_tab && tab->on_precond) add_cond_and_fix(thd, &tmp_cond, tab->on_precond); @@ -8971,6 +8984,15 @@ uint check_join_cache_usage(JOIN_TAB *tab, if (tab->use_quick == 2) goto no_join_cache; + + /* + Don't use join cache if we're inside a join tab range covered by LooseScan + strategy (TODO: LooseScan is very similar to FirstMatch so theoretically it + should be possible to use join buffering in the same way we're using it for + multi-table firstmatch ranges). + */ + if (tab->inside_loosescan_range) + goto no_join_cache; if (tab->is_inner_table_of_semi_join_with_first_match() && !join->allowed_semijoin_with_cache) @@ -16684,7 +16706,7 @@ bool test_if_ref(Item *root_cond, Item_field *left_item,Item *right_item) static Item * make_cond_for_table(THD *thd, Item *cond, table_map tables, table_map used_table, - uint join_tab_idx_arg, + int join_tab_idx_arg, bool exclude_expensive_cond __attribute__((unused)), bool retain_ref_cond) { @@ -16698,7 +16720,7 @@ make_cond_for_table(THD *thd, Item *cond, table_map tables, static Item * make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond, table_map tables, table_map used_table, - uint join_tab_idx_arg, + int join_tab_idx_arg, bool exclude_expensive_cond __attribute__ ((unused)), bool retain_ref_cond) diff --git a/sql/sql_select.h b/sql/sql_select.h index 9b8e60e9cc1..15711dca7b3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -347,6 +347,9 @@ typedef struct st_join_table { NULL - Not doing a loose scan on this join tab. */ struct st_join_table *loosescan_match_tab; + + /* TRUE <=> we are inside LooseScan range */ + bool inside_loosescan_range; /* Buffer to save index tuple to be able to skip duplicates */ uchar *loosescan_buf; @@ -1154,7 +1157,7 @@ public: max_allowed_join_cache_level > JOIN_CACHE_HASHED_BIT; } bool choose_subquery_plan(table_map join_tables); - void get_partial_cost_and_fanout(uint end_tab_idx, + void get_partial_cost_and_fanout(int end_tab_idx, table_map filter_map, double *read_time_arg, double *record_count_arg);