summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <timour@askmonty.org>2011-09-01 23:53:12 +0300
committerunknown <timour@askmonty.org>2011-09-01 23:53:12 +0300
commitea8aa329099ee28ec6f1266d8d01a6fc664259cf (patch)
tree8b9a0b43ee89cd8fbae14deeb12012a2b7b83cdd
parent11ebbabb087a7bd6c315e6412d8e8ee677c6217b (diff)
downloadmariadb-git-ea8aa329099ee28ec6f1266d8d01a6fc664259cf.tar.gz
Fix for bug lp:834492
Analysis: In the test query semi-join merges the inner-most subquery into the outer subquery, and the optimization of the merged subquery finds some new index access methods. Later the IN-EXISTS transformation is applied to the unmerged subquery. Since the optimizer is instructed to not consider materialization, it reoptimizes the plan in-place to take into account the new IN-EXISTS conditions. Just before reoptimization JOIN::choose_subquery_plan resets the query plan, which also resets the access methods found during the semi-join merge. Then reoptimization discovers there are no new access methods, but it leaves the query plan in its reset state. Later semi-join crashes because it assumes these access methods are present. Solution: When reoptimizing in-place, reset the query plan only after new access methods were discovered. If no new access methods were discovered, leave the current plan as it was.
-rw-r--r--mysql-test/r/subselect_mat_cost_bugs.result35
-rw-r--r--mysql-test/t/subselect_mat_cost_bugs.test36
-rw-r--r--sql/opt_subselect.cc15
-rw-r--r--sql/sql_select.cc18
-rw-r--r--sql/sql_select.h1
5 files changed, 94 insertions, 11 deletions
diff --git a/mysql-test/r/subselect_mat_cost_bugs.result b/mysql-test/r/subselect_mat_cost_bugs.result
index 764e38dab9f..79f53c1ff86 100644
--- a/mysql-test/r/subselect_mat_cost_bugs.result
+++ b/mysql-test/r/subselect_mat_cost_bugs.result
@@ -318,4 +318,39 @@ SELECT * FROM t1
WHERE (f1) IN (SELECT f1 FROM t2)
LIMIT 0;
f1
+set @@optimizer_switch='default';
drop table t1, t2;
+#
+# LP BUG#834492: Crash in fix_semijoin_strategies_for_picked_join_order
+# with nested subqueries and LooseScan=ON
+#
+CREATE TABLE t3 (b int) ;
+INSERT INTO t3 VALUES (0),(0);
+CREATE TABLE t4 (a int, b int, c int, d int, PRIMARY KEY (a)) ;
+INSERT INTO t4 VALUES (28,0,0,0),(29,3,0,0);
+CREATE TABLE t5 (a int, b int, c int, d int, KEY (c,b)) ;
+INSERT INTO t5 VALUES (28,0,0,0),(29,3,0,0);
+SET @@optimizer_switch='semijoin=ON,loosescan=ON,firstmatch=OFF,materialization=OFF';
+EXPLAIN SELECT *
+FROM t3
+WHERE t3.b > ALL (
+SELECT c
+FROM t4
+WHERE t4.a >= t3.b
+AND a = SOME (SELECT b FROM t5));
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t5 index c c 10 NULL 2 Using where; Using index; LooseScan
+2 DEPENDENT SUBQUERY t4 eq_ref PRIMARY PRIMARY 4 test.t5.b 1 Using where
+SELECT *
+FROM t3
+WHERE t3.b > ALL (
+SELECT c
+FROM t4
+WHERE t4.a >= t3.b
+AND a = SOME (SELECT b FROM t5));
+b
+0
+0
+set @@optimizer_switch='default';
+drop table t3, t4, t5;
diff --git a/mysql-test/t/subselect_mat_cost_bugs.test b/mysql-test/t/subselect_mat_cost_bugs.test
index 37c7b617760..dbff9594309 100644
--- a/mysql-test/t/subselect_mat_cost_bugs.test
+++ b/mysql-test/t/subselect_mat_cost_bugs.test
@@ -348,4 +348,40 @@ SELECT * FROM t1
WHERE (f1) IN (SELECT f1 FROM t2)
LIMIT 0;
+set @@optimizer_switch='default';
drop table t1, t2;
+
+--echo #
+--echo # LP BUG#834492: Crash in fix_semijoin_strategies_for_picked_join_order
+--echo # with nested subqueries and LooseScan=ON
+--echo #
+
+CREATE TABLE t3 (b int) ;
+INSERT INTO t3 VALUES (0),(0);
+
+CREATE TABLE t4 (a int, b int, c int, d int, PRIMARY KEY (a)) ;
+INSERT INTO t4 VALUES (28,0,0,0),(29,3,0,0);
+
+CREATE TABLE t5 (a int, b int, c int, d int, KEY (c,b)) ;
+INSERT INTO t5 VALUES (28,0,0,0),(29,3,0,0);
+
+SET @@optimizer_switch='semijoin=ON,loosescan=ON,firstmatch=OFF,materialization=OFF';
+
+EXPLAIN SELECT *
+FROM t3
+WHERE t3.b > ALL (
+ SELECT c
+ FROM t4
+ WHERE t4.a >= t3.b
+ AND a = SOME (SELECT b FROM t5));
+
+SELECT *
+FROM t3
+WHERE t3.b > ALL (
+ SELECT c
+ FROM t4
+ WHERE t4.a >= t3.b
+ AND a = SOME (SELECT b FROM t5));
+
+set @@optimizer_switch='default';
+drop table t3, t4, t5;
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 6c5e177fe1d..b06d80860c5 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -4641,17 +4641,12 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
const_tables != table_count)
{
/*
- The subquery was not reoptimized either because the user allowed only
- the IN-EXISTS strategy, or because materialization was not possible
- based on semantic analysis. Cleanup the original plan and reoptimize.
+ The subquery was not reoptimized with the newly injected IN-EXISTS
+ conditions either because the user allowed only the IN-EXISTS strategy,
+ or because materialization was not possible based on semantic analysis.
*/
- for (uint i= 0; i < table_count; i++)
- {
- join_tab[i].keyuse= NULL;
- join_tab[i].checked_keys.clear_all();
- }
- if ((reopt_result= reoptimize(in_to_exists_where, join_tables, NULL)) ==
- REOPT_ERROR)
+ reopt_result= reoptimize(in_to_exists_where, join_tables, NULL);
+ if (reopt_result == REOPT_ERROR)
return TRUE;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 54c1215164e..d01c54d1f22 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -21547,6 +21547,19 @@ void JOIN::save_query_plan(Join_plan_state *save_to)
/**
+ Reset a query execution plan so that it can be reoptimized in-place.
+*/
+void JOIN::reset_query_plan()
+{
+ for (uint i= 0; i < table_count; i++)
+ {
+ join_tab[i].keyuse= NULL;
+ join_tab[i].checked_keys.clear_all();
+ }
+}
+
+
+/**
Restore a query execution plan previously saved by the caller.
@param The object from which the current query plan state is restored.
@@ -21579,7 +21592,8 @@ void JOIN::restore_query_plan(Join_plan_state *restore_from)
@param added_where An extra conjunct to the WHERE clause to reoptimize with
@param join_tables The set of tables to reoptimize
- @param save_to If != NULL, save here the state of the current query plan
+ @param save_to If != NULL, save here the state of the current query plan,
+ otherwise reuse the existing query plan structures.
@notes
Given a query plan that was already optimized taking into account some WHERE
@@ -21623,6 +21637,8 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
if (save_to)
save_query_plan(save_to);
+ else
+ reset_query_plan();
if (!keyuse.buffer &&
my_init_dynamic_array(&keyuse, sizeof(KEYUSE), 20, 64))
diff --git a/sql/sql_select.h b/sql/sql_select.h
index bbf390aaf7e..9b8e60e9cc1 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -698,6 +698,7 @@ protected:
enum_reopt_result reoptimize(Item *added_where, table_map join_tables,
Join_plan_state *save_to);
void save_query_plan(Join_plan_state *save_to);
+ void reset_query_plan();
void restore_query_plan(Join_plan_state *restore_from);
/* Choose a subquery plan for a table-less subquery. */
bool choose_tableless_subquery_plan();