diff --git a/sql/opt_hints.cc b/sql/opt_hints.cc index 0f65802ad00..fec57fc1d82 100644 --- a/sql/opt_hints.cc +++ b/sql/opt_hints.cc @@ -21,8 +21,7 @@ #include "opt_hints.h" /** - Information about hints. Sould be - synchronized with opt_hints_enum enum. + Information about hints. Must be in sync with opt_hints_enum. Note: Hint name depends on hint state. 'NO_' prefix is added if appropriate hint state bit(see Opt_hints_map::hints) is not @@ -176,7 +175,12 @@ static Opt_hints_qb *get_qb_hints(Parse_context *pc) { global_hints->register_child(qb); pc->select->opt_hints_qb= qb; - qb->set_resolved(); + /* + Mark the query block as resolved as we know which SELECT_LEX it is + attached to. + Note that children (indexes, tables) are probably not resolved, yet. + */ + qb->set_fixed(); } return qb; } @@ -272,7 +276,7 @@ void Opt_hints::print(THD *thd, String *str) { for (uint i= 0; i < MAX_HINT_ENUM; i++) { - if (is_specified(static_cast(i)) && is_resolved()) + if (is_specified(static_cast(i)) && is_fixed()) { append_hint_type(str, static_cast(i)); str->append(STRING_WITH_LEN("(")); @@ -308,7 +312,7 @@ void Opt_hints::append_hint_type(String *str, opt_hints_enum type) } -void Opt_hints::print_warn_unresolved(THD *thd) +void Opt_hints::print_unfixed_warnings(THD *thd) { String hint_name_str, hint_type_str; append_name(thd, &hint_name_str); @@ -320,24 +324,29 @@ void Opt_hints::print_warn_unresolved(THD *thd) hint_type_str.length(0); append_hint_type(&hint_type_str, static_cast(i)); push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - get_warn_unresolved_code(), - ER_THD(thd, get_warn_unresolved_code()), + get_unfixed_warning_code(), + ER_THD(thd, get_unfixed_warning_code()), hint_name_str.c_ptr_safe(), hint_type_str.c_ptr_safe()); } } } +/* + @brief + Recursively walk the descendant hints and emit warnings for any + unresolved hints +*/ -void Opt_hints::check_unresolved(THD *thd) +void Opt_hints::check_unfixed(THD *thd) { - if (!is_resolved()) - print_warn_unresolved(thd); + if (!is_fixed()) + print_unfixed_warnings(thd); - if (!is_all_resolved()) + if (!are_children_fully_fixed()) { for (uint i= 0; i < child_array.size(); i++) - child_array[i]->check_unresolved(thd); + child_array[i]->check_unfixed(thd); } } @@ -354,8 +363,8 @@ Opt_hints_qb::Opt_hints_qb(Opt_hints *opt_hints_arg, } -Opt_hints_table *Opt_hints_qb::adjust_hints_for_table(TABLE *table, - const Lex_ident_table &alias) +Opt_hints_table *Opt_hints_qb::fix_hints_for_table(TABLE *table, + const Lex_ident_table &alias) { Opt_hints_table *tab= static_cast(find_by_name(alias)); @@ -364,7 +373,9 @@ Opt_hints_table *Opt_hints_qb::adjust_hints_for_table(TABLE *table, if (!tab) // Tables not found return NULL; - tab->adjust_key_hints(table); + if (!tab->fix_hint(table)) + incr_fully_fixed_children(); + return tab; } @@ -411,16 +422,18 @@ uint Opt_hints_qb::sj_enabled_strategies(uint opt_switches) const /* @brief For each index IDX, put its hints into keyinfo_array[IDX] - */ -void Opt_hints_table::adjust_key_hints(TABLE *table) + +bool Opt_hints_table::fix_hint(TABLE *table) { - set_resolved(); + /* + Ok, there's a table we attach to. Mark this hint as fixed and proceed to + fixing the child objects. + */ + set_fixed(); + if (child_array_ptr()->size() == 0) // No key level hints - { - get_parent()->incr_resolved_children(); - return; - } + return false; // Ok, fully fixed /* Make sure that adjustment is called only once. */ DBUG_ASSERT(keyinfo_array.size() == 0); @@ -434,20 +447,18 @@ void Opt_hints_table::adjust_key_hints(TABLE *table) { if (key_info->name.streq((*hint)->get_name())) { - (*hint)->set_resolved(); + (*hint)->set_fixed(); keyinfo_array[j]= static_cast(*hint); - incr_resolved_children(); + incr_fully_fixed_children(); + break; } } } - /* - Do not increase number of resolved tables - if there are unresolved key objects. It's - important for check_unresolved() function. - */ - if (is_all_resolved()) - get_parent()->incr_resolved_children(); + if (are_children_fully_fixed()) + return false; + + return true; // Some children are not fully fixed } @@ -1105,7 +1116,12 @@ ulonglong Parser::Max_execution_time_hint::get_milliseconds() const } -bool Opt_hints_global::resolve(THD *thd) +/* + @brief + Fix global-level hints (and only them) +*/ + +bool Opt_hints_global::fix_hint(THD *thd) { if (thd->lex->is_ps_or_view_context_analysis()) return false; @@ -1113,7 +1129,7 @@ bool Opt_hints_global::resolve(THD *thd) if (!max_exec_time_hint) { /* No possible errors */ - set_resolved(); + set_fixed(); return false; } @@ -1136,7 +1152,7 @@ bool Opt_hints_global::resolve(THD *thd) thd->reset_query_timer(); thd->set_query_timer_force(max_exec_time_hint->get_milliseconds() * 1000); } - set_resolved(); + set_fixed(); return false; } diff --git a/sql/opt_hints.h b/sql/opt_hints.h index b7eae34581b..5737a5e9f5e 100644 --- a/sql/opt_hints.h +++ b/sql/opt_hints.h @@ -32,31 +32,39 @@ This process - Creates interpreted hint structures: Opt_hints_global, Opt_hints_qb, Opt_hints_table, Opt_hints_key. - - Interprets QB_NAME hints and assigns Query Block names. + - Interprets QB_NAME hints and assigns Opt_hints_qb objects their names. - Table-level hints are put into their Query Block's Opt_hints_qb object. - Index-level hints are put into their table's Opt_hints_table object. - == Hint "adjustment" == + Currently, this process is done at the parser stage. (This is one of the + causes why hints do not work across VIEW bounds, here or in MySQL). - During Name Resolution, setup_tables() calls adjust_hints_for_table() for - each table and sets TABLE_LIST::opt_hints_table to point to its - Opt_hints_table. + == Hint "fixing" == + + During Name Resolution, hints are attached the real objects they control: + - table-level hints find their tables, + - index-level hints find their indexes. + + This is done in setup_tables() which calls fix_hints_for_table() for + each table, as a result TABLE_LIST::opt_hints_table points to the table's + hints. == Hint hierarchy == - Hints have this hierarchy, parent to child: + Hints have this hierarchy, less specific to more specific: Opt_hints_global Opt_hints_qb Opt_hints_table Opt_hints_key - For some hints, one needs to check the hint's base object and its parent. For - example, MRR can be disabled on a per-index or a per-table basis. + Some hints can be specified at a specific level (e.g. per-index) or at a + more general level (e.g. per-table). When checking the hint, we need + to check for per-index commands and then maybe per-table command. - == How the optimizer checks hints == + == API for checking hints == - The optimizer checks what hints specify using these calls: + The optimizer checks hints' instructions using these calls: hint_table_state() hint_table_state_or_fallback() hint_key_state() @@ -212,9 +220,13 @@ private: Mem_root_array child_array; /* true if hint is connected to the real object */ - bool resolved; - /* Number of resolved children */ - uint resolved_children; + bool fixed; + + /* + Number of child hints that are fully fixed, that is, fixed and + have all their children also fully fixed. + */ + uint n_fully_fixed_children; public: @@ -222,7 +234,7 @@ public: Opt_hints *parent_arg, MEM_ROOT *mem_root_arg) : name(name_arg), parent(parent_arg), child_array(mem_root_arg), - resolved(false), resolved_children(0) + fixed(false), n_fully_fixed_children(0) { } bool is_specified(opt_hints_enum type_arg) const @@ -274,14 +286,14 @@ public: } void set_name(const Lex_ident_sys &name_arg) { name= name_arg; } Opt_hints *get_parent() const { return parent; } - void set_resolved() { resolved= true; } - bool is_resolved() const { return resolved; } - void incr_resolved_children() { resolved_children++; } + void set_fixed() { fixed= true; } + bool is_fixed() const { return fixed; } + void incr_fully_fixed_children() { n_fully_fixed_children++; } Mem_root_array *child_array_ptr() { return &child_array; } - bool is_all_resolved() const + bool are_children_fully_fixed() const { - return child_array.size() == resolved_children; + return child_array.size() == n_fully_fixed_children; } void register_child(Opt_hints* hint_arg) @@ -306,12 +318,12 @@ public: */ void print(THD *thd, String *str); /** - Check if there are any unresolved hint objects and + Check if there are any unfixed hint objects and print warnings for them. @param thd Pointer to THD object */ - void check_unresolved(THD *thd); + void check_unfixed(THD *thd); virtual void append_name(THD *thd, String *str)= 0; /** @@ -335,18 +347,18 @@ private: */ void append_hint_type(String *str, opt_hints_enum type); /** - Print warning for unresolved hint name. + Print warnings abount unfixed hints in this hint collection @param thd Pointer to THD object */ - void print_warn_unresolved(THD *thd); + void print_unfixed_warnings(THD *thd); protected: /** - Override this function in descendants so that print_warn_unresolved() - prints the proper warning text for table/index level unresolved hints + Override this function in descendants so that print_unfixed_warnings() + prints the proper warning text for table/index level unfixed hints */ - virtual uint get_warn_unresolved_code() const + virtual uint get_unfixed_warning_code() const { DBUG_ASSERT(0); return 0; @@ -384,7 +396,7 @@ public: max_exec_time_hint, _1, _2); } - bool resolve(THD *thd); + bool fix_hint(THD *thd); }; @@ -466,8 +478,8 @@ public: @return pointer Opt_hints_table object if this object is found, NULL otherwise. */ - Opt_hints_table *adjust_hints_for_table(TABLE *table, - const Lex_ident_table &alias); + Opt_hints_table *fix_hints_for_table(TABLE *table, + const Lex_ident_table &alias); /** Returns whether semi-join is enabled for this query block @@ -548,9 +560,9 @@ public: @param table Pointer to TABLE object */ - void adjust_key_hints(TABLE *table); + bool fix_hint(TABLE *table); - virtual uint get_warn_unresolved_code() const override + virtual uint get_unfixed_warning_code() const override { return ER_UNRESOLVED_TABLE_HINT_NAME; } @@ -584,7 +596,7 @@ public: append_identifier(thd, str, &name); } - virtual uint get_warn_unresolved_code() const override + virtual uint get_unfixed_warning_code() const override { return ER_UNRESOLVED_INDEX_HINT_NAME; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f2c0099085e..4fa5675c479 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8325,7 +8325,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context, !table_list->opt_hints_table) // Table hints are not adjusted yet { table_list->opt_hints_table= - qb_hints->adjust_table_hints(table_list->table, table_list->alias); + qb_hints->fix_hints_for_table(table_list->table, + table_list->alias); } } if (select_insert && !is_insert_tables_num_set) @@ -8398,9 +8399,15 @@ bool setup_tables(THD *thd, Name_resolution_context *context, if (resolve_opt_hints) { if (thd->lex->opt_hints_global && select_lex->select_number == 1) - thd->lex->opt_hints_global->resolve(thd); + { + thd->lex->opt_hints_global->fix_hint(thd); + /* + There's no need to call opt_hints_global->check_unresolved(), + this is done for each query block individually + */ + } if (qb_hints) - qb_hints->check_unresolved(thd); + qb_hints->check_unfixed(thd); } DBUG_RETURN(0); }