From f670b6d22f55401d4329f9ac9827a5145d1dd667 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 23 Oct 2010 21:28:58 +0300 Subject: [PATCH] MWL#89: Cost-based choice between Materialization and IN->EXISTS transformation Added missing logic to handle the case when subquery tables are optimized away early during optimization. --- mysql-test/include/subselect_mat_cost.inc | 12 +- mysql-test/r/subselect_mat_cost.result | 174 ++++++++++++++++++++++ sql/item_subselect.cc | 32 ++-- sql/item_subselect.h | 26 +++- sql/opt_subselect.cc | 62 ++++++++ sql/sql_select.cc | 43 +----- sql/sql_select.h | 2 + 7 files changed, 284 insertions(+), 67 deletions(-) diff --git a/mysql-test/include/subselect_mat_cost.inc b/mysql-test/include/subselect_mat_cost.inc index 4ccbd08693a..04b116e9527 100644 --- a/mysql-test/include/subselect_mat_cost.inc +++ b/mysql-test/include/subselect_mat_cost.inc @@ -123,13 +123,13 @@ select a1 from t1 where a1 in (select b1 from t2 where b1 = b2 and b2 = '1 - 03' -- echo /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ -- echo TODO this test produces wrong result due to missing logic to handle the case -- echo when JOIN::optimize detects an empty subquery result. -#explain -#select a1 from t1 where a1 in (select max(b1) from t2); -#select a1 from t1 where a1 in (select max(b1) from t2); +explain +select a1 from t1 where a1 in (select max(b1) from t2); +select a1 from t1 where a1 in (select max(b1) from t2); -- echo -#explain -#select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); -#select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); -- echo /* E.6 make_join_select detects impossible WHERE. * diff --git a/mysql-test/r/subselect_mat_cost.result b/mysql-test/r/subselect_mat_cost.result index c6cb7685f4a..9d6986cf092 100644 --- a/mysql-test/r/subselect_mat_cost.result +++ b/mysql-test/r/subselect_mat_cost.result @@ -342,7 +342,21 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 9 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 9 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -609,7 +623,21 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 9 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 9 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -876,7 +904,21 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 8 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 8 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -1193,7 +1235,22 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +1 - 03 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -1505,7 +1562,22 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +1 - 03 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -1817,7 +1889,22 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +1 - 03 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -2134,7 +2221,22 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +1 - 03 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -2446,7 +2548,22 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +1 - 03 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -2758,7 +2875,22 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +1 - 03 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 Using where +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -3032,7 +3164,21 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 9 NULL 3 Using where; Using index +2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 9 NULL 3 Using where; Using index +2 SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -3299,7 +3445,21 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 9 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 9 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ @@ -3566,7 +3726,21 @@ a1 /* E.5 opt_sum_query detects no matching min/max row or substitutes MIN/MAX with a const. */ TODO this test produces wrong result due to missing logic to handle the case when JOIN::optimize detects an empty subquery result. +explain +select a1 from t1 where a1 in (select max(b1) from t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 8 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select a1 from t1 where a1 in (select max(b1) from t2); +a1 +explain +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL it1i1 8 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select a1 from t1 where a1 in (select max(b1) from t2 where b1 = '7 - 02'); +a1 /* E.6 make_join_select detects impossible WHERE. * TODO /* E.7 constant optimization detects "no matching row in const table". */ diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 5f9285e5df6..475a58df88e 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -36,7 +36,7 @@ Item_subselect::Item_subselect(): Item_result_field(), value_assigned(0), thd(0), substitution(0), engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0), const_item_cache(1), - inside_first_fix_fields(0), done_first_fix_fields(FALSE), + inside_first_fix_fields(0), done_first_fix_fields(FALSE), forced_const(FALSE), eliminated(FALSE), engine_changed(0), changed(0), is_correlated(FALSE) { @@ -121,6 +121,7 @@ void Item_subselect::cleanup() depends_on.empty(); reset(); value_assigned= 0; + forced_const= FALSE; DBUG_VOID_RETURN; } @@ -158,7 +159,6 @@ void Item_in_subselect::cleanup() left_expr_cache= NULL; } first_execution= TRUE; - is_constant= FALSE; if (in_strategy & SUBS_MATERIALIZATION) in_strategy= 0; pushed_cond_guards= NULL; @@ -682,12 +682,15 @@ Item *Item_subselect::get_tmp_table_item(THD *thd_arg) void Item_subselect::update_used_tables() { - recalc_used_tables(parent_select, FALSE); - if (!engine->uncacheable()) + if (!forced_const) { - // did all used tables become static? - if (!(used_tables_cache & ~engine->upper_select_const_tables())) - const_item_cache= 1; + recalc_used_tables(parent_select, FALSE); + if (!engine->uncacheable()) + { + // did all used tables become static? + if (!(used_tables_cache & ~engine->upper_select_const_tables())) + const_item_cache= 1; + } } } @@ -753,7 +756,7 @@ Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param, of Items belonged to subquery, which will be not repeated */ used_tables_cache= parent->get_used_tables_cache(); - const_item_cache= parent->get_const_item_cache(); + const_item_cache= parent->const_item(); /* this subquery always creates during preparation, so we can assign @@ -791,8 +794,7 @@ void Item_maxmin_subselect::print(String *str, enum_query_type query_type) void Item_singlerow_subselect::reset() { - eliminated= FALSE; - null_value= 1; + Item_subselect::reset(); if (value) value->null_value= 1; } @@ -1082,8 +1084,7 @@ bool Item_in_subselect::test_limit(st_select_lex_unit *unit_arg) Item_in_subselect::Item_in_subselect(Item * left_exp, st_select_lex *select_lex): Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE), - is_constant(FALSE), optimizer(0), pushed_cond_guards(NULL), - in_strategy(0), upper_item(0) + optimizer(0), pushed_cond_guards(NULL), in_strategy(0), upper_item(0) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; @@ -1313,7 +1314,7 @@ bool Item_in_subselect::val_bool() { DBUG_ASSERT(fixed == 1); null_value= 0; - if (is_constant) + if (forced_const) return value; if (exec()) { @@ -4147,11 +4148,10 @@ int subselect_hash_sj_engine::exec() tmp_table->file->info(HA_STATUS_VARIABLE); if (!tmp_table->file->stats.records) { - item_in->value= FALSE; /* The value of IN will not change during this execution. */ - item_in->is_constant= TRUE; + item_in->reset(); + item_in->make_const(); item_in->set_first_execution(); - /* TIMOUR: check if we need this: item_in->null_value= FALSE; */ DBUG_RETURN(FALSE); } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 2a6d310cbb4..dc29323f756 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -70,6 +70,13 @@ protected: bool inside_first_fix_fields; bool done_first_fix_fields; + /* + Set to TRUE if at optimization or execution time we determine that this + item's value is a constant. We need this member because it is not possible + to substitute 'this' with a constant item. + */ + bool forced_const; + public: /* A reference from inside subquery predicate to somewhere outside of it */ class Ref_to_outside : public Sql_alloc @@ -154,12 +161,21 @@ public: void fix_after_pullout(st_select_lex *new_parent, Item **ref); void recalc_used_tables(st_select_lex *new_parent, bool after_pullout); virtual bool exec(); + /* + If subquery optimization or execution determines that the subquery has + an empty result, mark the subquery predicate as a constant value. + */ + void make_const() + { + used_tables_cache= 0; + const_item_cache= 0; + forced_const= TRUE; + } virtual void fix_length_and_dec(); table_map used_tables() const; table_map not_null_tables() const { return 0; } bool const_item() const; inline table_map get_used_tables_cache() { return used_tables_cache; } - inline bool get_const_item_cache() { return const_item_cache; } Item *get_tmp_table_item(THD *thd); void update_used_tables(); virtual void print(String *str, enum_query_type query_type); @@ -353,12 +369,6 @@ protected: */ List *left_expr_cache; bool first_execution; - /* - Set to TRUE if at query execution time we determine that this item's - value is a constant during this execution. We need this member because - it is not possible to substitute 'this' with a constant item. - */ - bool is_constant; /* expr & optimizer used in subselect rewriting to store Item for @@ -435,7 +445,7 @@ public: Item_in_subselect(Item * left_expr, st_select_lex *select_lex); Item_in_subselect() :Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE), - is_constant(FALSE), optimizer(0), abort_on_null(0), + optimizer(0), abort_on_null(0), pushed_cond_guards(NULL), func(NULL), in_strategy(0), upper_item(0) {} diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 25d3aa29904..a15418ad23d 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -3823,3 +3823,65 @@ bool JOIN::choose_subquery_plan(table_map join_tables) return FALSE; } + + +/** + Choose a query plan for a table-less subquery. + + @notes + + @retval FALSE success. + @retval TRUE error occurred. +*/ + +bool JOIN::choose_tableless_subquery_plan() +{ + DBUG_ASSERT(!tables_list || !tables); + if (select_lex->master_unit()->item) + { + DBUG_ASSERT(select_lex->master_unit()->item->type() == + Item::SUBSELECT_ITEM); + Item_subselect *subs_predicate= select_lex->master_unit()->item; + + /* + If the optimizer determined that his query has an empty result, + in most cases the subquery predicate is a known constant value - + either FALSE or NULL. The implementation of Item_subselect::reset() + determines which one. + */ + if (zero_result_cause) + { + if (!implicit_grouping) + { + /* + Both group by queries and non-group by queries without aggregate + functions produce empty subquery result. + */ + subs_predicate->reset(); + subs_predicate->make_const(); + return FALSE; + } + + /* TODO: + A further optimization is possible when a non-group query with + MIN/MAX/COUNT is optimized by opt_sum_query. Then, if there are + only MIN/MAX functions over an empty result set, the subquery + result is a NULL value/row, thus the value of subs_predicate is + NULL. + */ + } + + if (subs_predicate->is_in_predicate()) + { + Item_in_subselect *in_subs; + in_subs= (Item_in_subselect*) subs_predicate; + in_subs->in_strategy= SUBS_IN_TO_EXISTS; + if (in_subs->create_in_to_exists_cond(this) || + in_subs->inject_in_to_exists_cond(this)) + return TRUE; + tmp_having= having; + } + } + return FALSE; +} + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4e5dc9074f2..6f9c02b77ec 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -829,6 +829,7 @@ JOIN::optimize() "Impossible HAVING" : "Impossible WHERE"; tables= 0; error= 0; + choose_tableless_subquery_plan(); goto setup_subq_exit; } } @@ -873,12 +874,13 @@ JOIN::optimize() */ if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds))) { - if (res == HA_ERR_KEY_NOT_FOUND) + if (res == HA_ERR_KEY_NOT_FOUND || res < 0) { DBUG_PRINT("info",("No matching min/max row")); zero_result_cause= "No matching min/max row"; tables= 0; error=0; + choose_tableless_subquery_plan(); goto setup_subq_exit; } if (res > 1) @@ -887,14 +889,7 @@ JOIN::optimize() DBUG_PRINT("error",("Error from opt_sum_query")); DBUG_RETURN(1); } - if (res < 0) - { - DBUG_PRINT("info",("No matching min/max row")); - zero_result_cause= "No matching min/max row"; - tables= 0; - error=0; - goto setup_subq_exit; - } + DBUG_PRINT("info",("Select tables optimized away")); zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved @@ -919,40 +914,14 @@ JOIN::optimize() QT_ORDINARY);); conds= table_independent_conds; } - goto setup_subq_exit; } } if (!tables_list) { DBUG_PRINT("info",("No tables")); error= 0; - if (optimize_unflattened_subqueries()) - DBUG_RETURN(1); - /* - TIMOUR: TODO: consider do we need to optimize here at all and refactor - this block and JOIN::choose_subquery_plan. - - if (choose_subquery_plan()) - DBUG_RETURN(1); - */ - Item_in_subselect *in_subs; - if (select_lex->master_unit()->item && - select_lex->master_unit()->item->is_in_predicate()) - { - in_subs= (Item_in_subselect*) select_lex->master_unit()->item; - if (in_subs->in_strategy & SUBS_MATERIALIZATION && - in_subs->setup_mat_engine()) - in_subs->in_strategy= SUBS_IN_TO_EXISTS; - if (in_subs->in_strategy & SUBS_IN_TO_EXISTS) - { - if (in_subs->create_in_to_exists_cond(this)) - DBUG_RETURN(1); - if (in_subs->inject_in_to_exists_cond(this)) - DBUG_RETURN(1); - tmp_having= having; - } - } - DBUG_RETURN(0); + choose_tableless_subquery_plan(); + goto setup_subq_exit; } error= -1; // Error is sent to client sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables); diff --git a/sql/sql_select.h b/sql/sql_select.h index 5f1abcce87f..0bb8c9e9285 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1383,6 +1383,8 @@ protected: void restore_query_plan(DYNAMIC_ARRAY *save_keyuse, POSITION *save_positions, KEYUSE **save_join_tab_keyuse, key_map *save_join_tab_checked_keys); + /* Choose a subquery plan for a table-less subquery. */ + bool choose_tableless_subquery_plan(); public: JOIN_TAB *join_tab,**best_ref;