diff options
author | unknown <timour@askmonty.org> | 2011-09-01 23:53:12 +0300 |
---|---|---|
committer | unknown <timour@askmonty.org> | 2011-09-01 23:53:12 +0300 |
commit | ea8aa329099ee28ec6f1266d8d01a6fc664259cf (patch) | |
tree | 8b9a0b43ee89cd8fbae14deeb12012a2b7b83cdd | |
parent | 11ebbabb087a7bd6c315e6412d8e8ee677c6217b (diff) | |
download | mariadb-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.result | 35 | ||||
-rw-r--r-- | mysql-test/t/subselect_mat_cost_bugs.test | 36 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 15 | ||||
-rw-r--r-- | sql/sql_select.cc | 18 | ||||
-rw-r--r-- | sql/sql_select.h | 1 |
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(); |