Commit e5bca74b authored by unknown's avatar unknown

Fixed bug mdev-277 as part of the fix for lp:944706

The cause for this bug is that the method JOIN::get_examined_rows iterates over all
JOIN_TABs of the join assuming they are just a sequence. In the query above, the
innermost subquery is merged into its parent query. When we call
JOIN::get_examined_rows for the second-level subquery, the iteration that
assumes sequential order of join tabs goes outside the join_tab array and calls
the method JOIN_TAB::get_examined_rows on uninitialized memory. 

The fix is to iterate over JOIN_TABs in a way that takes into account the nested
semi-join structure of JOIN_TABs. In particular iterate as select_describe.
parent da521483
...@@ -6594,5 +6594,26 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 ); ...@@ -6594,5 +6594,26 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 );
MAX( alias2.a ) MAX( alias2.a )
Arden-Arcade Arden-Arcade
drop table t1; drop table t1;
#
# MDEV-277 CHEAP SQ: Server crashes in st_join_table::get_examined_rows
# with semijoin+materialization, IN and = subqueries
#
CREATE TABLE t1 (a1 INT);
INSERT INTO t1 VALUES (4),(6);
CREATE TABLE t2 (b1 INT);
INSERT INTO t2 VALUES (1),(7);
EXPLAIN
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
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 SUBQUERY t1 ALL NULL NULL NULL NULL 2
2 SUBQUERY <subquery3> eq_ref distinct_key distinct_key 4 func 1
3 MATERIALIZED t1 ALL NULL NULL NULL NULL 2
3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join)
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
a1
drop table t1, t2;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
...@@ -6593,6 +6593,26 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 ); ...@@ -6593,6 +6593,26 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 );
MAX( alias2.a ) MAX( alias2.a )
Arden-Arcade Arden-Arcade
drop table t1; drop table t1;
#
# MDEV-277 CHEAP SQ: Server crashes in st_join_table::get_examined_rows
# with semijoin+materialization, IN and = subqueries
#
CREATE TABLE t1 (a1 INT);
INSERT INTO t1 VALUES (4),(6);
CREATE TABLE t2 (b1 INT);
INSERT INTO t2 VALUES (1),(7);
EXPLAIN
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
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 SUBQUERY t1 ALL NULL NULL NULL NULL 2
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where; Start temporary; Using join buffer (flat, BNL join)
2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 End temporary; Using join buffer (flat, BNL join)
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
a1
drop table t1, t2;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
set optimizer_switch=default; set optimizer_switch=default;
......
...@@ -6589,6 +6589,27 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 ); ...@@ -6589,6 +6589,27 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 );
MAX( alias2.a ) MAX( alias2.a )
Arden-Arcade Arden-Arcade
drop table t1; drop table t1;
#
# MDEV-277 CHEAP SQ: Server crashes in st_join_table::get_examined_rows
# with semijoin+materialization, IN and = subqueries
#
CREATE TABLE t1 (a1 INT);
INSERT INTO t1 VALUES (4),(6);
CREATE TABLE t2 (b1 INT);
INSERT INTO t2 VALUES (1),(7);
EXPLAIN
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
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 SUBQUERY t1 ALL NULL NULL NULL NULL 2
2 SUBQUERY <subquery3> eq_ref distinct_key distinct_key 4 func 1
3 MATERIALIZED t1 ALL NULL NULL NULL NULL 2
3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join)
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
a1
drop table t1, t2;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
set @optimizer_switch_for_subselect_test=null; set @optimizer_switch_for_subselect_test=null;
...@@ -6600,6 +6600,27 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 ); ...@@ -6600,6 +6600,27 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 );
MAX( alias2.a ) MAX( alias2.a )
Arden-Arcade Arden-Arcade
drop table t1; drop table t1;
#
# MDEV-277 CHEAP SQ: Server crashes in st_join_table::get_examined_rows
# with semijoin+materialization, IN and = subqueries
#
CREATE TABLE t1 (a1 INT);
INSERT INTO t1 VALUES (4),(6);
CREATE TABLE t2 (b1 INT);
INSERT INTO t2 VALUES (1),(7);
EXPLAIN
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
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 SUBQUERY t1 ALL NULL NULL NULL NULL 2
2 SUBQUERY <subquery3> eq_ref distinct_key distinct_key 4 func 1
3 MATERIALIZED t1 ALL NULL NULL NULL NULL 2
3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join)
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
a1
drop table t1, t2;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
set optimizer_switch=default; set optimizer_switch=default;
......
...@@ -6589,6 +6589,27 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 ); ...@@ -6589,6 +6589,27 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 );
MAX( alias2.a ) MAX( alias2.a )
Arden-Arcade Arden-Arcade
drop table t1; drop table t1;
#
# MDEV-277 CHEAP SQ: Server crashes in st_join_table::get_examined_rows
# with semijoin+materialization, IN and = subqueries
#
CREATE TABLE t1 (a1 INT);
INSERT INTO t1 VALUES (4),(6);
CREATE TABLE t2 (b1 INT);
INSERT INTO t2 VALUES (1),(7);
EXPLAIN
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
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 SUBQUERY t1 ALL NULL NULL NULL NULL 2
2 SUBQUERY <subquery3> eq_ref distinct_key distinct_key 4 func 1
3 MATERIALIZED t1 ALL NULL NULL NULL NULL 2
3 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 Using join buffer (flat, BNL join)
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
a1
drop table t1, t2;
# return optimizer switch changed in the beginning of this test # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
set @optimizer_switch_for_subselect_test=null; set @optimizer_switch_for_subselect_test=null;
......
...@@ -5561,5 +5561,24 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 ); ...@@ -5561,5 +5561,24 @@ WHERE alias1.a = alias2.a OR ('Moscow') IN ( SELECT a FROM t1 );
drop table t1; drop table t1;
--echo #
--echo # MDEV-277 CHEAP SQ: Server crashes in st_join_table::get_examined_rows
--echo # with semijoin+materialization, IN and = subqueries
--echo #
CREATE TABLE t1 (a1 INT);
INSERT INTO t1 VALUES (4),(6);
CREATE TABLE t2 (b1 INT);
INSERT INTO t2 VALUES (1),(7);
EXPLAIN
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
SELECT * FROM t1
WHERE a1 = (SELECT COUNT(*) FROM t1 WHERE a1 IN (SELECT a1 FROM t1, t2));
drop table t1, t2;
--echo # return optimizer switch changed in the beginning of this test --echo # return optimizer switch changed in the beginning of this test
set optimizer_switch=@subselect_tmp; set optimizer_switch=@subselect_tmp;
...@@ -270,6 +270,8 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field, ...@@ -270,6 +270,8 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
bool *inherited_fl); bool *inherited_fl);
JOIN_TAB *first_depth_first_tab(JOIN* join); JOIN_TAB *first_depth_first_tab(JOIN* join);
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab); JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab);
JOIN_TAB *first_breadth_first_tab(JOIN *join);
JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab);
/** /**
This handles SELECT with and without UNION. This handles SELECT with and without UNION.
...@@ -6615,19 +6617,18 @@ void JOIN::get_prefix_cost_and_fanout(uint n_tables, ...@@ -6615,19 +6617,18 @@ void JOIN::get_prefix_cost_and_fanout(uint n_tables,
double JOIN::get_examined_rows() double JOIN::get_examined_rows()
{ {
/* Each constant table examines one row, and the result is at most one row. */ ha_rows examined_rows;
ha_rows examined_rows= const_tables;
uint i= const_tables;
double prev_fanout= 1; double prev_fanout= 1;
JOIN_TAB *tab= first_breadth_first_tab(this);
JOIN_TAB *prev_tab= tab;
if (table_count == const_tables) examined_rows= tab->get_examined_rows();
return examined_rows;
examined_rows+= join_tab[i++].get_examined_rows(); while ((tab= next_breadth_first_tab(this, tab)))
for (; i < table_count ; i++)
{ {
prev_fanout *= best_positions[i-1].records_read; prev_fanout *= prev_tab->records_read;
examined_rows+= join_tab[i].get_examined_rows() * prev_fanout; examined_rows+= tab->get_examined_rows() * prev_fanout;
prev_tab= tab;
} }
return examined_rows; return examined_rows;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment