Skip to content

Commit 192427e

Browse files
committed
MDEV-30333 Wrong result with not_null_range_scan and LEFT JOIN with empty table
There was a bug in JOIN::make_notnull_conds_for_range_scans() when clearing TABLE->tmp_set, which was used to mark fields that could not be null. This function was only used if 'not_null_range_scan=on' is set. The effect was that tmp_set contained a 'random value' and this caused the optimizer to think that some fields could not be null. FLUSH TABLES clears tmp_set and because of this things worked temporarily. Fixed by clearing tmp_set properly.
1 parent 690fcfb commit 192427e

File tree

3 files changed

+95
-5
lines changed

3 files changed

+95
-5
lines changed

mysql-test/main/empty_table.result

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,61 @@ ERROR 42S02: Table 'test.t2' doesn't exist
1616
show status like "Empty_queries";
1717
Variable_name Value
1818
Empty_queries 2
19+
# End of 4.1 tests
20+
#
21+
# MDEV-30333 Wrong result with not_null_range_scan and LEFT JOIN with empty table
22+
#
23+
set @save_optimizer_switch=@@optimizer_switch;
24+
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
25+
INSERT INTO t1 (b) VALUES (1),(2);
26+
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
27+
SET optimizer_switch= 'not_null_range_scan=off';
28+
explain extended SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
29+
id select_type table type possible_keys key key_len ref rows filtered Extra
30+
1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 Const row not found
31+
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using filesort
32+
Warnings:
33+
Note 1003 select `test`.`t1`.`b` AS `b` from `test`.`t1` where `test`.`t1`.`a` is null order by `test`.`t1`.`b`
34+
SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
35+
b
36+
1
37+
2
38+
SET optimizer_switch = 'not_null_range_scan=on';
39+
explain extended SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
40+
id select_type table type possible_keys key key_len ref rows filtered Extra
41+
1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 Const row not found
42+
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where; Using filesort
43+
Warnings:
44+
Note 1003 select `test`.`t1`.`b` AS `b` from `test`.`t1` where `test`.`t1`.`a` is null order by `test`.`t1`.`b`
45+
SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
46+
b
47+
1
48+
2
49+
flush tables;
50+
SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
51+
b
52+
1
53+
2
54+
drop table t1,t2;
55+
# Second test in MDEV-30333
56+
CREATE TABLE t1 (a int, b varchar(10)) ENGINE=MyISAM;
57+
INSERT INTO t1 VALUES (69,'foo'),(71,'bar');
58+
CREATE TABLE t2 (c int) ENGINE=MyISAM;
59+
INSERT INTO t2 VALUES (1),(2);
60+
CREATE TABLE t3 (d int, e int, KEY(e)) ENGINE=MyISAM;
61+
SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t3.e = t3.d ON 1;
62+
a b c d e
63+
69 foo 1 NULL NULL
64+
71 bar 1 NULL NULL
65+
69 foo 2 NULL NULL
66+
71 bar 2 NULL NULL
67+
SET optimizer_switch = 'not_null_range_scan=on';
68+
SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t3.e = t3.d ON 1;
69+
a b c d e
70+
69 foo 1 NULL NULL
71+
71 bar 1 NULL NULL
72+
69 foo 2 NULL NULL
73+
71 bar 2 NULL NULL
74+
DROP TABLE t1, t2, t3;
75+
set @@optimizer_switch=@save_optimizer_switch;
76+
End of 10.5 tests

mysql-test/main/empty_table.test

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,38 @@ drop table t1;
2121
select * from t2;
2222
show status like "Empty_queries";
2323

24-
# End of 4.1 tests
24+
--echo # End of 4.1 tests
25+
26+
--echo #
27+
--echo # MDEV-30333 Wrong result with not_null_range_scan and LEFT JOIN with empty table
28+
--echo #
29+
30+
set @save_optimizer_switch=@@optimizer_switch;
31+
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
32+
INSERT INTO t1 (b) VALUES (1),(2);
33+
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
34+
SET optimizer_switch= 'not_null_range_scan=off'; # Default
35+
explain extended SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
36+
SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
37+
SET optimizer_switch = 'not_null_range_scan=on';
38+
explain extended SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
39+
SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
40+
flush tables;
41+
SELECT b FROM t1 LEFT JOIN t2 ON t2.c = a WHERE a IS NULL ORDER BY b;
42+
drop table t1,t2;
43+
44+
--echo # Second test in MDEV-30333
45+
46+
CREATE TABLE t1 (a int, b varchar(10)) ENGINE=MyISAM;
47+
INSERT INTO t1 VALUES (69,'foo'),(71,'bar');
48+
CREATE TABLE t2 (c int) ENGINE=MyISAM;
49+
INSERT INTO t2 VALUES (1),(2);
50+
CREATE TABLE t3 (d int, e int, KEY(e)) ENGINE=MyISAM;
51+
SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t3.e = t3.d ON 1;
52+
SET optimizer_switch = 'not_null_range_scan=on';
53+
SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t3.e = t3.d ON 1;
54+
DROP TABLE t1, t2, t3;
55+
set @@optimizer_switch=@save_optimizer_switch;
56+
57+
--echo End of 10.5 tests
58+

sql/sql_select.cc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29683,7 +29683,6 @@ void JOIN::make_notnull_conds_for_range_scans()
2968329683
{
2968429684
DBUG_ENTER("JOIN::make_notnull_conds_for_range_scans");
2968529685

29686-
2968729686
if (impossible_where ||
2968829687
!optimizer_flag(thd, OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN))
2968929688
{
@@ -29769,21 +29768,20 @@ bool build_notnull_conds_for_range_scans(JOIN *join, Item *cond,
2976929768
table_map allowed)
2977029769
{
2977129770
THD *thd= join->thd;
29772-
2977329771
DBUG_ENTER("build_notnull_conds_for_range_scans");
2977429772

2977529773
for (JOIN_TAB *s= join->join_tab;
2977629774
s < join->join_tab + join->table_count ; s++)
2977729775
{
2977829776
/* Clear all needed bitmaps to mark found fields */
2977929777
if ((allowed & s->table->map) &&
29780-
!(s->table->map && join->const_table_map))
29778+
!(s->table->map & join->const_table_map))
2978129779
bitmap_clear_all(&s->table->tmp_set);
2978229780
}
2978329781

2978429782
/*
2978529783
Find all null-rejected fields assuming that cond is null-rejected and
29786-
only formulas over tables from 'allowed' are to be taken into account
29784+
only formulas over tables from 'allowed' are to be taken into account
2978729785
*/
2978829786
if (cond->find_not_null_fields(allowed))
2978929787
DBUG_RETURN(true);

0 commit comments

Comments
 (0)