summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2017-04-22 10:30:55 -0700
committerIgor Babaev <igor@askmonty.org>2017-04-24 11:46:01 -0700
commit2e7ba70a94b5950a7d1d733c177d1b2a24916213 (patch)
tree2f74a4aaceaa0c3152471fefd5e418cd7055b61a
parentc6ee3fe9d4056dcd6ee9f9aabd3424c1b27fc506 (diff)
downloadmariadb-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.result14
-rw-r--r--mysql-test/t/subselect_innodb.test22
-rw-r--r--sql/sql_select.cc21
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;
/*