diff options
author | Igor Babaev <igor@askmonty.org> | 2017-04-22 10:30:55 -0700 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2017-04-24 11:46:01 -0700 |
commit | 2e7ba70a94b5950a7d1d733c177d1b2a24916213 (patch) | |
tree | 2f74a4aaceaa0c3152471fefd5e418cd7055b61a | |
parent | c6ee3fe9d4056dcd6ee9f9aabd3424c1b27fc506 (diff) | |
download | mariadb-git-2e7ba70a94b5950a7d1d733c177d1b2a24916213.tar.gz |
Fixed the bug mdev-10693.
The code that chooses between materialization of a non-correlated
IN subquery and its transformation into an EXISTS correlated
subquery assumes that the execution plan for the outer select
has been already built. However it was not always so if subqueries
occurred in the expressions used for ref access to tables of
the outer select. A call of the function create_ref_for_key() in
get_best_combination() could trigger a premature execution of
the above mentioned code when the execution plan structures for
the outer select were not fully built. This could cause a crash
of the server.
The fix postpones the calls of create_ref_for_key() until the
structures for the execution plan is fully built.
-rw-r--r-- | mysql-test/r/subselect_innodb.result | 14 | ||||
-rw-r--r-- | mysql-test/t/subselect_innodb.test | 22 | ||||
-rw-r--r-- | sql/sql_select.cc | 21 |
3 files changed, 51 insertions, 6 deletions
diff --git a/mysql-test/r/subselect_innodb.result b/mysql-test/r/subselect_innodb.result index 06cfb8b45d2..f92615f22cf 100644 --- a/mysql-test/r/subselect_innodb.result +++ b/mysql-test/r/subselect_innodb.result @@ -469,3 +469,17 @@ f1 f2 set join_cache_level = default; drop view v1; drop table t1,t2; +# +# MDEV-10693: cost-based choice between materialization and in-to-exists +# for a subquery from the expression used in ref access +# +CREATE TABLE t1 (i1 INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (i2 INT) ENGINE=InnoDB; +CREATE TABLE t3 (i3 INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t3 VALUES (3); +SELECT * FROM t1 +WHERE NULL IN ( SELECT i2 FROM t2 +WHERE i1 IN ( i2 IN ( SELECT i3 FROM t3 ) ) AND i2 = 2 ); +i1 +DROP TABLE t1,t2,t3; diff --git a/mysql-test/t/subselect_innodb.test b/mysql-test/t/subselect_innodb.test index d764c435c82..3945c6b10b9 100644 --- a/mysql-test/t/subselect_innodb.test +++ b/mysql-test/t/subselect_innodb.test @@ -453,3 +453,25 @@ SELECT * FROM v1, t2 WHERE ( f1, f2 ) IN ( SELECT f1, f1 FROM t1 ); set join_cache_level = default; drop view v1; drop table t1,t2; + +--echo # +--echo # MDEV-10693: cost-based choice between materialization and in-to-exists +--echo # for a subquery from the expression used in ref access +--echo # + +--source include/have_innodb.inc + +CREATE TABLE t1 (i1 INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2 (i2 INT) ENGINE=InnoDB; + +CREATE TABLE t3 (i3 INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t3 VALUES (3); + +SELECT * FROM t1 + WHERE NULL IN ( SELECT i2 FROM t2 + WHERE i1 IN ( i2 IN ( SELECT i3 FROM t3 ) ) AND i2 = 2 ); + +DROP TABLE t1,t2,t3; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d83e8e2bfce..c5f2a83fc01 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7728,8 +7728,6 @@ get_best_combination(JOIN *join) join->full_join=0; join->hash_join= FALSE; - used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read - fix_semijoin_strategies_for_picked_join_order(join); JOIN_TAB_RANGE *root_range; @@ -7791,7 +7789,6 @@ get_best_combination(JOIN *join) j->bush_root_tab= sjm_nest_root; form=join->table[tablenr]=j->table; - used_tables|= form->map; form->reginfo.join_tab=j; DBUG_PRINT("info",("type: %d", j->type)); if (j->type == JT_CONST) @@ -7818,9 +7815,6 @@ get_best_combination(JOIN *join) join->best_positions[tablenr].loosescan_picker.loosescan_key); j->index= join->best_positions[tablenr].loosescan_picker.loosescan_key; }*/ - - if (keyuse && create_ref_for_key(join, j, keyuse, TRUE, used_tables)) - DBUG_RETURN(TRUE); // Something went wrong if ((j->type == JT_REF || j->type == JT_EQ_REF) && is_hash_join_key_no(j->ref.key)) @@ -7845,6 +7839,21 @@ get_best_combination(JOIN *join) } root_range->end= j; + used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read + for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++) + { + if (j->bush_children) + j= j->bush_children->start; + + used_tables|= j->table->map; + if ((keyuse= join->best_positions[tablenr].key) && + create_ref_for_key(join, j, keyuse, TRUE, used_tables)) + DBUG_RETURN(TRUE); // Something went wrong + + if (j->last_leaf_in_bush) + j= j->bush_root_tab; + } + join->top_join_tab_count= join->join_tab_ranges.head()->end - join->join_tab_ranges.head()->start; /* |