diff --git a/sql/comp_creator.h b/sql/comp_creator.h new file mode 100644 index 000000000000..fa16f754e96c --- /dev/null +++ b/sql/comp_creator.h @@ -0,0 +1,40 @@ +#ifndef COMP_CREATOR_INCLUDED +#define COMP_CREATOR_INCLUDED + +/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +// Declaration of chooser_compare_func_creator, in a separate file +// to make sure that parser_yystype.h does not need to depend on +// item_subselect.h. + +class Comp_creator; + +/** + Convenience typedef for a function that returns factories for Item comparators + (ie., returns Comp_creator). + + @retval nullptr In case of semantic errors. +*/ +using chooser_compare_func_creator = Comp_creator *(*)(bool invert); + +#endif // COMP_CREATOR_INCLUDED diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8c7a89af57e3..4bdb7499643f 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -376,7 +376,8 @@ bool Item_in_subselect::mark_as_outer(Item *left_row, size_t col) { bool Item_in_subselect::finalize_exists_transform(THD *thd, SELECT_LEX *select_lex) { - DBUG_ASSERT(exec_method == EXEC_EXISTS_OR_MAT || exec_method == EXEC_EXISTS); + DBUG_ASSERT(exec_method == SubqueryExecMethod::EXEC_EXISTS_OR_MAT || + exec_method == SubqueryExecMethod::EXEC_EXISTS); /* Change SELECT expr1, expr2 @@ -419,7 +420,7 @@ bool Item_in_subselect::finalize_exists_transform(THD *thd, return true; /* purecov: inspected */ select_lex->join->allow_outer_refs = true; // for JOIN::set_prefix_tables() - exec_method = EXEC_EXISTS; + exec_method = SubqueryExecMethod::EXEC_EXISTS; return false; } @@ -463,7 +464,7 @@ Item *Item_in_subselect::remove_in2exists_conds(Item *conds) { bool Item_in_subselect::finalize_materialization_transform(THD *thd, JOIN *join) { - DBUG_ASSERT(exec_method == EXEC_EXISTS_OR_MAT); + DBUG_ASSERT(exec_method == SubqueryExecMethod::EXEC_EXISTS_OR_MAT); DBUG_ASSERT(join == subquery->single_select_lex()->join); // No UNION in materialized subquery so this holds: @@ -471,7 +472,7 @@ bool Item_in_subselect::finalize_materialization_transform(THD *thd, DBUG_ASSERT(join->unit == unit); DBUG_ASSERT(unit->global_parameters()->select_limit == nullptr); - exec_method = EXEC_MATERIALIZATION; + exec_method = SubqueryExecMethod::EXEC_MATERIALIZATION; /* We need to undo several changes which IN->EXISTS had done. But we first @@ -527,19 +528,19 @@ void Item_in_subselect::cleanup() { need_expr_cache = true; switch (exec_method) { - case EXEC_MATERIALIZATION: + case SubqueryExecMethod::EXEC_MATERIALIZATION: if (in2exists_info->dependent_after) { unit->first_select()->uncacheable |= UNCACHEABLE_DEPENDENT; unit->uncacheable |= UNCACHEABLE_DEPENDENT; } // fall through - case EXEC_EXISTS: + case SubqueryExecMethod::EXEC_EXISTS: /* Back to EXISTS_OR_MAT, so that next execution of this statement can choose between the two. */ unit->global_parameters()->select_limit = nullptr; - exec_method = EXEC_EXISTS_OR_MAT; + exec_method = SubqueryExecMethod::EXEC_EXISTS_OR_MAT; break; default: break; @@ -552,7 +553,7 @@ RowIterator *Item_in_subselect::root_iterator() const { // Only subselect_hash_sj_engine owns its own iterator; // for subselect_indexsubquery_engine, the unit still has it, since it's a // normally executed query block. Thus, we should never get called otherwise. - DBUG_ASSERT(exec_method == EXEC_MATERIALIZATION && + DBUG_ASSERT(exec_method == SubqueryExecMethod::EXEC_MATERIALIZATION && indexsubquery_engine->engine_type() == subselect_indexsubquery_engine::HASH_SJ_ENGINE); return down_cast(indexsubquery_engine) @@ -723,8 +724,8 @@ bool Item_in_subselect::walk(Item_processor processor, enum_walk walk, bool Item_in_subselect::exec(THD *thd) { DBUG_TRACE; - DBUG_ASSERT(exec_method != EXEC_MATERIALIZATION || - (exec_method == EXEC_MATERIALIZATION && + DBUG_ASSERT(exec_method != SubqueryExecMethod::EXEC_MATERIALIZATION || + (exec_method == SubqueryExecMethod::EXEC_MATERIALIZATION && indexsubquery_engine->engine_type() == subselect_indexsubquery_engine::HASH_SJ_ENGINE)); /* @@ -741,7 +742,8 @@ bool Item_in_subselect::exec(THD *thd) { lookup, the cache hit rate, and the savings per cache hit. */ if (need_expr_cache && !left_expr_cache && - exec_method == EXEC_MATERIALIZATION && init_left_expr_cache(thd)) + exec_method == SubqueryExecMethod::EXEC_MATERIALIZATION && + init_left_expr_cache(thd)) return true; if (left_expr_cache != nullptr) { @@ -1286,11 +1288,7 @@ bool Query_result_exists_subquery::send_data(THD *, List &) { } Item_exists_subselect::Item_exists_subselect(SELECT_LEX *select) - : Item_subselect(), - value(false), - exec_method(EXEC_UNSPECIFIED), - sj_convert_priority(0), - embedding_join_nest(nullptr) { + : Item_subselect() { DBUG_TRACE; init(select, new (*THR_MALLOC) Query_result_exists_subquery(this)); max_columns = UINT_MAX; @@ -1466,7 +1464,7 @@ bool Item_exists_subselect::resolve_type(THD *thd) { set_data_type_longlong(); max_length = 1; max_columns = unit_cols(); - if (exec_method == EXEC_EXISTS) { + if (exec_method == SubqueryExecMethod::EXEC_EXISTS) { Prepared_stmt_arena_holder ps_arena_holder(thd); /* We need only 1 row to determine existence. @@ -2459,7 +2457,8 @@ Item_subselect::trans_res Item_in_subselect::select_in_like_transformer( If we didn't choose an execution method up to this point, we choose the IN=>EXISTS transformation, at least temporarily. */ - if (exec_method == EXEC_UNSPECIFIED) exec_method = EXEC_EXISTS_OR_MAT; + if (exec_method == SubqueryExecMethod::EXEC_UNSPECIFIED) + exec_method = SubqueryExecMethod::EXEC_EXISTS_OR_MAT; /* Both transformers call fix_fields() only for Items created inside them, @@ -2494,7 +2493,8 @@ void Item_in_subselect::print(const THD *thd, String *str, const char *tail = Item_bool_func::bool_transform_names[value_transform]; if (implicit_is_op) tail = ""; bool paren = false; - if (exec_method == EXEC_EXISTS_OR_MAT || exec_method == EXEC_EXISTS) { + if (exec_method == SubqueryExecMethod::EXEC_EXISTS_OR_MAT || + exec_method == SubqueryExecMethod::EXEC_EXISTS) { if (value_transform == BOOL_NEGATED) { // NOT has low associativity, but // we're inside Item_in_optimizer, // so () are needed only if IS TRUE/FALSE is coming. @@ -2524,7 +2524,8 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) { abort_on_null = value_transform == BOOL_IS_TRUE || value_transform == BOOL_NOT_TRUE; - if (exec_method == EXEC_SEMI_JOIN) return !((*ref) = new Item_func_true()); + if (exec_method == SubqueryExecMethod::EXEC_SEMI_JOIN) + return !((*ref) = new Item_func_true()); if ((thd_arg->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) && left_expr && !left_expr->fixed) { @@ -2686,7 +2687,8 @@ bool Item_subselect::is_evaluated() const { return unit->is_executed(); } void Item_allany_subselect::print(const THD *thd, String *str, enum_query_type query_type) const { - if (exec_method == EXEC_EXISTS_OR_MAT || exec_method == EXEC_EXISTS) + if (exec_method == SubqueryExecMethod::EXEC_EXISTS_OR_MAT || + exec_method == SubqueryExecMethod::EXEC_EXISTS) str->append(STRING_WITH_LEN("")); else { left_expr->print(thd, str, query_type); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index e75b08cb5e75..1a318ea8b7a7 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -35,6 +35,7 @@ #include "my_time.h" #include "mysql/udf_registration_types.h" #include "mysql_time.h" +#include "sql/comp_creator.h" #include "sql/enum_query_type.h" #include "sql/item.h" // Item_result_field #include "sql/parse_tree_node_base.h" @@ -42,7 +43,6 @@ #include "sql/sql_const.h" #include "template_utils.h" -class Comp_creator; class Field; class Item_func_not_all; class Item_in_optimizer; @@ -64,14 +64,6 @@ struct TABLE_LIST; template class List; -/** - Convenience typedef used in this file, and further used by any files - including this file. - - @retval NULL In case of semantic errors. -*/ -typedef Comp_creator *(*chooser_compare_func_creator)(bool invert); - /* base class for subselects */ class Item_subselect : public Item_result_field { @@ -343,6 +335,22 @@ class Item_maxmin_subselect final : public Item_singlerow_subselect { /* exists subselect */ +enum class SubqueryExecMethod : int { + EXEC_UNSPECIFIED, ///< No execution method specified yet. + EXEC_SEMI_JOIN, ///< Predicate is converted to semi-join nest. + /// IN was converted to correlated EXISTS, and this is a final decision. + EXEC_EXISTS, + /** + Decision between EXISTS and MATERIALIZATION is not yet taken. + IN was temporarily converted to correlated EXISTS. + All descendants of Item_in_subselect must go through this method + before they can reach EXISTS. + */ + EXEC_EXISTS_OR_MAT, + /// Predicate executed via materialization, and this is a final decision. + EXEC_MATERIALIZATION +}; + class Item_exists_subselect : public Item_subselect { typedef Item_subselect super; @@ -355,24 +363,9 @@ class Item_exists_subselect : public Item_subselect { The method chosen to execute the predicate, currently used for IN, =ANY and EXISTS predicates. */ - enum enum_exec_method { - EXEC_UNSPECIFIED, ///< No execution method specified yet. - EXEC_SEMI_JOIN, ///< Predicate is converted to semi-join nest. - /// IN was converted to correlated EXISTS, and this is a final decision. - EXEC_EXISTS, - /** - Decision between EXEC_EXISTS and EXEC_MATERIALIZATION is not yet taken. - IN was temporarily converted to correlated EXISTS. - All descendants of Item_in_subselect must go through this method - before they can reach EXEC_EXISTS. - */ - EXEC_EXISTS_OR_MAT, - /// Predicate executed via materialization, and this is a final decision. - EXEC_MATERIALIZATION - }; - enum_exec_method exec_method; + SubqueryExecMethod exec_method{SubqueryExecMethod::EXEC_UNSPECIFIED}; /// Priority of this predicate in the convert-to-semi-join-nest process. - int sj_convert_priority; + int sj_convert_priority{0}; /// Decision on whether predicate is selected for semi-join transformation enum enum_sj_selection { /// Not selected for semi-join, evaluate as subquery predicate, or @@ -394,26 +387,16 @@ class Item_exists_subselect : public Item_subselect { predicate is not a candidate for transformation. See also THD::emb_on_expr_nest. */ - TABLE_LIST *embedding_join_nest; + TABLE_LIST *embedding_join_nest{nullptr}; Item_exists_subselect(SELECT_LEX *select); - Item_exists_subselect() - : Item_subselect(), - value(false), - exec_method(EXEC_UNSPECIFIED), - sj_convert_priority(0), - embedding_join_nest(nullptr) {} + Item_exists_subselect() : Item_subselect() {} - explicit Item_exists_subselect(const POS &pos) - : super(pos), - value(false), - exec_method(EXEC_UNSPECIFIED), - sj_convert_priority(0), - embedding_join_nest(nullptr) {} + explicit Item_exists_subselect(const POS &pos) : super(pos) {} trans_res select_transformer(THD *, SELECT_LEX *) override { - exec_method = EXEC_EXISTS; + exec_method = SubqueryExecMethod::EXEC_EXISTS; return RES_OK; } subs_type substype() const override { return EXISTS_SUBS; } @@ -852,4 +835,5 @@ class subselect_hash_sj_engine final : public subselect_indexsubquery_engine { RowIterator *root_iterator() const { return m_iterator.get(); } void create_iterators(THD *thd) override; }; + #endif /* ITEM_SUBSELECT_INCLUDED */ diff --git a/sql/opt_hints.cc b/sql/opt_hints.cc index 204aff077bf1..677198db163c 100644 --- a/sql/opt_hints.cc +++ b/sql/opt_hints.cc @@ -34,6 +34,7 @@ #include "sql/derror.h" // ER_THD #include "sql/error_handler.h" #include "sql/item.h" +#include "sql/item_subselect.h" #include "sql/key.h" #include "sql/mysqld.h" // table_alias_charset #include "sql/nested_join.h" @@ -260,13 +261,11 @@ uint Opt_hints_qb::sj_enabled_strategies(uint opt_switches) const { return opt_switches; } -Item_exists_subselect::enum_exec_method Opt_hints_qb::subquery_strategy() - const { +SubqueryExecMethod Opt_hints_qb::subquery_strategy() const { if (subquery_hint) - return static_cast( - subquery_hint->get_args()); + return static_cast(subquery_hint->get_args()); - return Item_exists_subselect::EXEC_UNSPECIFIED; + return SubqueryExecMethod::EXEC_UNSPECIFIED; } void Opt_hints_qb::print_irregular_hints(const THD *thd, String *str) { diff --git a/sql/opt_hints.h b/sql/opt_hints.h index 7cc9129103e4..d3f6f26b8476 100644 --- a/sql/opt_hints.h +++ b/sql/opt_hints.h @@ -37,12 +37,12 @@ #include "my_dbug.h" #include "my_inttypes.h" #include "sql/enum_query_type.h" -#include "sql/item_subselect.h" // Item_exists_subselect #include "sql/mem_root_array.h" // Mem_root_array #include "sql/sql_bitmap.h" // Bitmap #include "sql/sql_show.h" // append_identifier #include "sql_string.h" // String +enum class SubqueryExecMethod : int; class Item; class JOIN; class Opt_hints_table; @@ -462,7 +462,7 @@ class Opt_hints_qb : public Opt_hints { @retval EXEC_EXISTS In-to-exists execution should be used @retval EXEC_UNSPECIFIED No SUBQUERY hint for this query block */ - Item_exists_subselect::enum_exec_method subquery_strategy() const; + SubqueryExecMethod subquery_strategy() const; void print_irregular_hints(const THD *thd, String *str) override; diff --git a/sql/parse_tree_hints.cc b/sql/parse_tree_hints.cc index b76ba9a34d60..fb58f469f4b7 100644 --- a/sql/parse_tree_hints.cc +++ b/sql/parse_tree_hints.cc @@ -284,11 +284,11 @@ void PT_qb_level_hint::append_args(const THD *thd, String *str) const { break; } case SUBQUERY_HINT_ENUM: - switch (args) { - case Item_exists_subselect::EXEC_MATERIALIZATION: + switch (static_cast(args)) { + case SubqueryExecMethod::EXEC_MATERIALIZATION: str->append(STRING_WITH_LEN(" MATERIALIZATION")); break; - case Item_exists_subselect::EXEC_EXISTS: + case SubqueryExecMethod::EXEC_EXISTS: str->append(STRING_WITH_LEN(" INTOEXISTS")); break; default: // Exactly one of above strategies should always be specified diff --git a/sql/parser_yystype.h b/sql/parser_yystype.h index d32e6adcf776..a716e7c4c3e7 100644 --- a/sql/parser_yystype.h +++ b/sql/parser_yystype.h @@ -25,6 +25,7 @@ #include "my_base.h" #include "my_time.h" // interval_type +#include "sql/comp_creator.h" #include "sql/handler.h" #include "sql/item_create.h" // Cast_target #include "sql/key_spec.h" // keytype, fk_option diff --git a/sql/sql_hints.yy b/sql/sql_hints.yy index 9152e0e72744..07e6be8ef5bb 100644 --- a/sql/sql_hints.yy +++ b/sql/sql_hints.yy @@ -28,6 +28,7 @@ %{ #include "my_inttypes.h" #include "sql/derror.h" +#include "sql/item_subselect.h" #include "sql/parse_tree_helpers.h" // check_resource_group_name_len #include "sql/parse_tree_hints.h" #include "sql/parser_yystype.h" @@ -403,8 +404,8 @@ semijoin_strategy: subquery_strategy: MATERIALIZATION_HINT { $$= - Item_exists_subselect::EXEC_MATERIALIZATION; } - | INTOEXISTS_HINT { $$= Item_exists_subselect::EXEC_EXISTS; } + static_cast(SubqueryExecMethod::EXEC_MATERIALIZATION); } + | INTOEXISTS_HINT { $$= static_cast(SubqueryExecMethod::EXEC_EXISTS); } ; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f1ec78457c34..a0652922a939 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -41,6 +41,7 @@ #include "sql/current_thd.h" #include "sql/derror.h" #include "sql/item_func.h" +#include "sql/item_subselect.h" #include "sql/mysqld.h" // table_alias_charset #include "sql/nested_join.h" #include "sql/parse_location.h" @@ -4383,8 +4384,7 @@ bool SELECT_LEX::get_optimizable_conditions(THD *thd, Item **new_where, return get_optimizable_join_conditions(thd, top_join_list); } -Item_exists_subselect::enum_exec_method SELECT_LEX::subquery_strategy( - THD *thd) const { +SubqueryExecMethod SELECT_LEX::subquery_strategy(THD *thd) const { if (m_windows.elements > 0) /* A window function is in the SELECT list. @@ -4394,21 +4394,20 @@ Item_exists_subselect::enum_exec_method SELECT_LEX::subquery_strategy( rows over which the WF is supposed to be calculated. So, subquery materialization is imposed. Grep for (and read) WL#10431. */ - return Item_exists_subselect::EXEC_MATERIALIZATION; + return SubqueryExecMethod::EXEC_MATERIALIZATION; if (opt_hints_qb) { - Item_exists_subselect::enum_exec_method strategy = - opt_hints_qb->subquery_strategy(); - if (strategy != Item_exists_subselect::EXEC_UNSPECIFIED) return strategy; + SubqueryExecMethod strategy = opt_hints_qb->subquery_strategy(); + if (strategy != SubqueryExecMethod::EXEC_UNSPECIFIED) return strategy; } // No SUBQUERY hint given, base possible strategies on optimizer_switch if (thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MATERIALIZATION)) return thd->optimizer_switch_flag(OPTIMIZER_SWITCH_SUBQ_MAT_COST_BASED) - ? Item_exists_subselect::EXEC_EXISTS_OR_MAT - : Item_exists_subselect::EXEC_MATERIALIZATION; + ? SubqueryExecMethod::EXEC_EXISTS_OR_MAT + : SubqueryExecMethod::EXEC_MATERIALIZATION; - return Item_exists_subselect::EXEC_EXISTS; + return SubqueryExecMethod::EXEC_EXISTS; } bool SELECT_LEX::semijoin_enabled(THD *thd) const { @@ -4557,6 +4556,19 @@ static bool walk_join_condition(mem_root_deque *tables, return false; } +void SELECT_LEX_UNIT::accumulate_used_tables(table_map map) { + DBUG_ASSERT(outer_select()); + if (item) + item->accumulate_used_tables(map); + else if (m_lateral_deps) + m_lateral_deps |= map; +} + +enum_parsing_context SELECT_LEX_UNIT::place() const { + DBUG_ASSERT(outer_select()); + return item ? item->place() : CTX_DERIVED; +} + bool SELECT_LEX::walk(Item_processor processor, enum_walk walk, uchar *arg) { List_iterator li(item_list); Item *item; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 032fbd880ec2..041a6d2b662f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -64,11 +64,10 @@ #include "sql/enum_query_type.h" #include "sql/field.h" #include "sql/handler.h" -#include "sql/item.h" // Name_resolution_context -#include "sql/item_subselect.h" // chooser_compare_func_creator -#include "sql/key_spec.h" // KEY_CREATE_INFO -#include "sql/lex_symbol.h" // LEX_SYMBOL -#include "sql/lexer_yystype.h" // Lexer_yystype +#include "sql/item.h" // Name_resolution_context +#include "sql/key_spec.h" // KEY_CREATE_INFO +#include "sql/lex_symbol.h" // LEX_SYMBOL +#include "sql/lexer_yystype.h" // Lexer_yystype #include "sql/mdl.h" #include "sql/mem_root_array.h" // Mem_root_array #include "sql/opt_hints.h" @@ -96,10 +95,13 @@ #include "violite.h" // SSL_type class Item_cond; +class Item_exists_subselect; +class Item_subselect; class Item_sum; class Event_parse_data; class Item_func_match; class Parse_tree_root; +class Query_result_interceptor; class Window; class sp_pcontext; enum class enum_jt_column; @@ -939,23 +941,14 @@ class SELECT_LEX_UNIT { Item_subselect, a derived TABLE_LIST), adds to this object a map of tables of the upper level which the unit references. */ - void accumulate_used_tables(table_map map) { - DBUG_ASSERT(outer_select()); - if (item) - item->accumulate_used_tables(map); - else if (m_lateral_deps) - m_lateral_deps |= map; - } + void accumulate_used_tables(table_map map); /** If unit is a subquery, which forms an object of the upper level (an Item_subselect, a derived TABLE_LIST), returns the place of this object in the upper level query block. */ - enum_parsing_context place() const { - DBUG_ASSERT(outer_select()); - return item ? item->place() : CTX_DERIVED; - } + enum_parsing_context place() const; bool walk(Item_processor processor, enum_walk walk, uchar *arg); @@ -1965,7 +1958,7 @@ class SELECT_LEX { @retval EXEC_EXISTS In-to-exists execution should be used @retval EXEC_EXISTS_OR_MAT A cost-based decision should be made */ - Item_exists_subselect::enum_exec_method subquery_strategy(THD *thd) const; + SubqueryExecMethod subquery_strategy(THD *thd) const; /** Returns whether semi-join is enabled for this query block diff --git a/sql/sql_optimizer.cc b/sql/sql_optimizer.cc index 28019c2c5e5e..3db988360243 100644 --- a/sql/sql_optimizer.cc +++ b/sql/sql_optimizer.cc @@ -69,6 +69,7 @@ #include "sql/item_cmpfunc.h" #include "sql/item_func.h" #include "sql/item_row.h" +#include "sql/item_subselect.h" #include "sql/item_sum.h" // Item_sum #include "sql/key.h" #include "sql/key_spec.h" @@ -1217,7 +1218,7 @@ int JOIN::replace_index_subquery() { JOIN_TAB *const first_join_tab = best_ref[0]; - if (in_subs->exec_method == Item_exists_subselect::EXEC_MATERIALIZATION) { + if (in_subs->exec_method == SubqueryExecMethod::EXEC_MATERIALIZATION) { // We cannot have two engines at the same time } else if (first_join_tab->table_ref->is_view_or_derived() && first_join_tab->table_ref->derived_unit()->is_recursive()) { @@ -10584,16 +10585,16 @@ bool JOIN::decide_subquery_strategy() { Item_in_subselect *const in_pred = static_cast(unit->item); - Item_exists_subselect::enum_exec_method chosen_method = in_pred->exec_method; + SubqueryExecMethod chosen_method = in_pred->exec_method; // Materialization does not allow UNION so this can't happen: - DBUG_ASSERT(chosen_method != Item_exists_subselect::EXEC_MATERIALIZATION); + DBUG_ASSERT(chosen_method != SubqueryExecMethod::EXEC_MATERIALIZATION); - if ((chosen_method == Item_exists_subselect::EXEC_EXISTS_OR_MAT) && + if ((chosen_method == SubqueryExecMethod::EXEC_EXISTS_OR_MAT) && compare_costs_of_subquery_strategies(&chosen_method)) return true; switch (chosen_method) { - case Item_exists_subselect::EXEC_EXISTS: + case SubqueryExecMethod::EXEC_EXISTS: if (select_lex->m_windows.elements > 0) // grep for WL#10431 { my_error(ER_NOT_SUPPORTED_YET, MYF(0), @@ -10602,7 +10603,7 @@ bool JOIN::decide_subquery_strategy() { return true; } return in_pred->finalize_exists_transform(thd, select_lex); - case Item_exists_subselect::EXEC_MATERIALIZATION: + case SubqueryExecMethod::EXEC_MATERIALIZATION: return in_pred->finalize_materialization_transform(thd, this); default: DBUG_ASSERT(false); @@ -10629,12 +10630,10 @@ bool JOIN::decide_subquery_strategy() { here. @returns false if success */ -bool JOIN::compare_costs_of_subquery_strategies( - Item_exists_subselect::enum_exec_method *method) { - *method = Item_exists_subselect::EXEC_EXISTS; +bool JOIN::compare_costs_of_subquery_strategies(SubqueryExecMethod *method) { + *method = SubqueryExecMethod::EXEC_EXISTS; - Item_exists_subselect::enum_exec_method allowed_strategies = - select_lex->subquery_strategy(thd); + SubqueryExecMethod allowed_strategies = select_lex->subquery_strategy(thd); /* A non-deterministic subquery should not use materialization, unless forced. @@ -10642,15 +10641,14 @@ bool JOIN::compare_costs_of_subquery_strategies( Here, the same logic is applied also for subqueries that are not converted to semi-join. */ - if (allowed_strategies == Item_exists_subselect::EXEC_EXISTS_OR_MAT && + if (allowed_strategies == SubqueryExecMethod::EXEC_EXISTS_OR_MAT && (unit->uncacheable & UNCACHEABLE_RAND)) - allowed_strategies = Item_exists_subselect::EXEC_EXISTS; + allowed_strategies = SubqueryExecMethod::EXEC_EXISTS; - if (allowed_strategies == Item_exists_subselect::EXEC_EXISTS) return false; + if (allowed_strategies == SubqueryExecMethod::EXEC_EXISTS) return false; - DBUG_ASSERT(allowed_strategies == Item_exists_subselect::EXEC_EXISTS_OR_MAT || - allowed_strategies == - Item_exists_subselect::EXEC_MATERIALIZATION); + DBUG_ASSERT(allowed_strategies == SubqueryExecMethod::EXEC_EXISTS_OR_MAT || + allowed_strategies == SubqueryExecMethod::EXEC_MATERIALIZATION); const JOIN *parent_join = unit->outer_select()->join; if (!parent_join || !parent_join->child_subquery_can_materialize) @@ -10717,7 +10715,7 @@ bool JOIN::compare_costs_of_subquery_strategies( const double cost_mat = cost_mat_table + subq_executions * sjm.lookup_cost.total_cost(); const bool mat_chosen = - (allowed_strategies == Item_exists_subselect::EXEC_EXISTS_OR_MAT) + (allowed_strategies == SubqueryExecMethod::EXEC_EXISTS_OR_MAT) ? (cost_mat < cost_exists) : true; trace_subq_mat_decision @@ -10728,7 +10726,7 @@ bool JOIN::compare_costs_of_subquery_strategies( .add("cost_of_EXISTS", cost_exists) .add("chosen", mat_chosen); if (mat_chosen) { - *method = Item_exists_subselect::EXEC_MATERIALIZATION; + *method = SubqueryExecMethod::EXEC_MATERIALIZATION; } else { best_read = saved_best_read; best_rowcount = saved_best_rowcount; diff --git a/sql/sql_optimizer.h b/sql/sql_optimizer.h index 73cbf7869926..971223ab1b3f 100644 --- a/sql/sql_optimizer.h +++ b/sql/sql_optimizer.h @@ -48,7 +48,6 @@ #include "my_table_map.h" #include "sql/field.h" #include "sql/item.h" -#include "sql/item_subselect.h" #include "sql/mem_root_array.h" #include "sql/opt_explain_format.h" // Explain_sort_clause #include "sql/row_iterator.h" @@ -62,6 +61,7 @@ #include "sql/temp_table_param.h" class COND_EQUAL; +class Item_subselect; class Item_sum; class Opt_trace_context; class THD; @@ -967,8 +967,7 @@ class JOIN { bool add_having_as_tmp_table_cond(uint curr_tmp_table); bool make_tmp_tables_info(); void set_plan_state(enum_plan_state plan_state_arg); - bool compare_costs_of_subquery_strategies( - Item_exists_subselect::enum_exec_method *method); + bool compare_costs_of_subquery_strategies(SubqueryExecMethod *method); ORDER *remove_const(ORDER *first_order, Item *cond, bool change_list, bool *simple_order, bool group_by); diff --git a/sql/sql_resolver.cc b/sql/sql_resolver.cc index 6b4f84b51c51..ed6c0d449576 100644 --- a/sql/sql_resolver.cc +++ b/sql/sql_resolver.cc @@ -1201,7 +1201,7 @@ bool SELECT_LEX::resolve_subquery(THD *thd) { that are transformed to semijoin, but for other subqueries, this function is called for every execution. One solution is perhaps to define exec_method in class Item_subselect and exit immediately if unequal to - EXEC_UNSPECIFIED. + SubqueryExecMethod::EXEC_UNSPECIFIED. */ Item_subselect *subq_predicate = master_unit()->item; DBUG_ASSERT(subq_predicate != nullptr); @@ -1291,7 +1291,7 @@ bool SELECT_LEX::resolve_subquery(THD *thd) { outer->sj_candidates && // 7 leaf_table_count && // 8 predicate->exec_method == // 9 - Item_exists_subselect::EXEC_UNSPECIFIED && // 9 + SubqueryExecMethod::EXEC_UNSPECIFIED && // 9 outer->leaf_table_count && // 10 !((active_options() | outer->active_options()) & // 11 SELECT_STRAIGHT_JOIN) && // 11 @@ -2898,7 +2898,7 @@ bool SELECT_LEX::convert_subquery_to_semijoin( nested_join->sj_outer_exprs.empty(); nested_join->sj_inner_exprs.empty(); - subq_pred->exec_method = Item_exists_subselect::EXEC_SEMI_JOIN; + subq_pred->exec_method = SubqueryExecMethod::EXEC_SEMI_JOIN; if (subq_pred->substype() == Item_subselect::IN_SUBS) { Item_in_subselect *in_subq_pred = (Item_in_subselect *)subq_pred;