Browse Source
MDEV-33281 Implement optimizer hints
MDEV-33281 Implement optimizer hints
This commit introduces: - the infrastructure for optimizer hints; - hints for join buffering: BNL(), NO_BNL(), BKA(), NO_BKA(); - NO_ICP() hint for disabling index condition pushdown; - MRR(), MO_MRR() hint for multi-range reads control; - NO_RANGE_OPTIMIZATION() for disabling range optimization; - QB_NAME() for assigning names for query blocks.pull/3878/head
21 changed files with 1555 additions and 64 deletions
-
1libmysqld/CMakeLists.txt
-
62mysql-test/main/opt_hints.result
-
1sql/CMakeLists.txt
-
40sql/mem_root_array.h
-
23sql/multi_range_read.cc
-
726sql/opt_hints.cc
-
507sql/opt_hints.h
-
11sql/opt_hints_parser.cc
-
23sql/opt_hints_parser.h
-
4sql/opt_index_cond_pushdown.cc
-
8sql/opt_range.cc
-
6sql/share/errmsg-utf8.txt
-
10sql/sql_base.cc
-
12sql/sql_lex.cc
-
27sql/sql_lex.h
-
49sql/sql_list.h
-
47sql/sql_select.cc
-
5sql/sql_string.h
-
18sql/sql_yacc.yy
-
7sql/table.h
-
28tests/mysql_client_test.c
@ -0,0 +1,726 @@ |
|||||
|
/* Copyright (c) 2015, 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 as published by |
||||
|
the Free Software Foundation; version 2 of the License. |
||||
|
|
||||
|
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 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 */ |
||||
|
|
||||
|
#include "my_global.h"
|
||||
|
#include "sql_class.h"
|
||||
|
#include "sql_lex.h"
|
||||
|
#include "sql_select.h"
|
||||
|
#include "opt_hints.h"
|
||||
|
|
||||
|
/**
|
||||
|
Information about hints. Sould be |
||||
|
synchronized with opt_hints_enum enum. |
||||
|
|
||||
|
Note: Hint name depends on hint state. 'NO_' prefix is added |
||||
|
if appropriate hint state bit(see Opt_hints_map::hints) is not |
||||
|
set. Depending on 'switch_state_arg' argument in 'parse tree |
||||
|
object' constructors(see parse_tree_h../cnm ints.[h,cc]) implementor |
||||
|
can control wishful form of the hint name. |
||||
|
*/ |
||||
|
|
||||
|
struct st_opt_hint_info opt_hint_info[]= |
||||
|
{ |
||||
|
{"BKA", true, true}, |
||||
|
{"BNL", true, true}, |
||||
|
{"ICP", true, true}, |
||||
|
{"MRR", true, true}, |
||||
|
{"NO_RANGE_OPTIMIZATION", true, true}, |
||||
|
{"QB_NAME", false, false}, |
||||
|
{0, 0, 0} |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
Prefix for system generated query block name. |
||||
|
Used in information warning in EXPLAIN oputput. |
||||
|
*/ |
||||
|
|
||||
|
const LEX_CSTRING sys_qb_prefix= {"select#", 7}; |
||||
|
|
||||
|
|
||||
|
/*
|
||||
|
Compare LEX_CSTRING objects. |
||||
|
|
||||
|
@param s Pointer to LEX_CSTRING |
||||
|
@param t Pointer to LEX_CSTRING |
||||
|
|
||||
|
@return 0 if strings are equal |
||||
|
1 if s is greater |
||||
|
-1 if t is greater |
||||
|
*/ |
||||
|
|
||||
|
static int cmp_lex_string(const LEX_CSTRING *s, |
||||
|
const LEX_CSTRING *t) |
||||
|
{ |
||||
|
return system_charset_info-> |
||||
|
coll->strnncollsp(system_charset_info, |
||||
|
(uchar *) s->str, s->length, |
||||
|
(uchar *) t->str, t->length); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type, |
||||
|
bool hint_state, |
||||
|
const LEX_CSTRING *qb_name_arg, |
||||
|
const LEX_CSTRING *table_name_arg, |
||||
|
const LEX_CSTRING *key_name_arg/*, PT_hint *hint*/) |
||||
|
{ |
||||
|
String str; |
||||
|
|
||||
|
/* Append hint name */ |
||||
|
if (!hint_state) |
||||
|
str.append(STRING_WITH_LEN("NO_")); |
||||
|
str.append(opt_hint_info[hint_type].hint_name); |
||||
|
|
||||
|
/* ER_WARN_UNKNOWN_QB_NAME with two arguments */ |
||||
|
if (err_code == ER_WARN_UNKNOWN_QB_NAME) |
||||
|
{ |
||||
|
String qb_name_str; |
||||
|
append_identifier(thd, &qb_name_str, qb_name_arg->str, qb_name_arg->length); |
||||
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, |
||||
|
err_code, ER_THD(thd, err_code), |
||||
|
qb_name_str.c_ptr_safe(), str.c_ptr_safe()); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* ER_WARN_CONFLICTING_HINT with one argument */ |
||||
|
str.append('('); |
||||
|
|
||||
|
/* Append table name */ |
||||
|
if (table_name_arg && table_name_arg->length > 0) |
||||
|
append_identifier(thd, &str, table_name_arg->str, table_name_arg->length); |
||||
|
|
||||
|
/* Append QB name */ |
||||
|
if (qb_name_arg && qb_name_arg->length > 0) |
||||
|
{ |
||||
|
str.append(STRING_WITH_LEN("@")); |
||||
|
append_identifier(thd, &str, qb_name_arg->str, qb_name_arg->length); |
||||
|
} |
||||
|
|
||||
|
/* Append key name */ |
||||
|
if (key_name_arg && key_name_arg->length > 0) |
||||
|
{ |
||||
|
str.append(' '); |
||||
|
append_identifier(thd, &str, key_name_arg->str, key_name_arg->length); |
||||
|
} |
||||
|
|
||||
|
/* Append additional hint arguments if they exist */ |
||||
|
// OLEGS: todo
|
||||
|
// if (hint)
|
||||
|
// {
|
||||
|
// if (qb_name_arg || table_name_arg || key_name_arg)
|
||||
|
// str.append(' ');
|
||||
|
|
||||
|
// hint->append_args(thd, &str);
|
||||
|
// }
|
||||
|
|
||||
|
str.append(')'); |
||||
|
|
||||
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, |
||||
|
err_code, ER_THD(thd, err_code), str.c_ptr_safe()); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
Returns a pointer to Opt_hints_global object, |
||||
|
creates Opt_hints object if not exist. |
||||
|
|
||||
|
@param pc pointer to Parse_context object |
||||
|
|
||||
|
@return pointer to Opt_hints object, |
||||
|
NULL if failed to create the object |
||||
|
*/ |
||||
|
|
||||
|
static Opt_hints_global *get_global_hints(Parse_context *pc) |
||||
|
{ |
||||
|
LEX *lex= pc->thd->lex; |
||||
|
|
||||
|
if (!lex->opt_hints_global) |
||||
|
lex->opt_hints_global= new Opt_hints_global(pc->thd->mem_root); |
||||
|
if (lex->opt_hints_global) |
||||
|
lex->opt_hints_global->set_resolved(); |
||||
|
return lex->opt_hints_global; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static Opt_hints_qb *get_qb_hints(Parse_context *pc) |
||||
|
{ |
||||
|
if (pc->select->opt_hints_qb) |
||||
|
return pc->select->opt_hints_qb; |
||||
|
|
||||
|
Opt_hints_global *global_hints= get_global_hints(pc); |
||||
|
if (global_hints == NULL) |
||||
|
return NULL; |
||||
|
|
||||
|
Opt_hints_qb *qb= new Opt_hints_qb(global_hints, pc->thd->mem_root, |
||||
|
pc->select->select_number); |
||||
|
if (qb) |
||||
|
{ |
||||
|
global_hints->register_child(qb); |
||||
|
pc->select->opt_hints_qb= qb; |
||||
|
qb->set_resolved(); |
||||
|
} |
||||
|
return qb; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
Find existing Opt_hints_qb object, print warning |
||||
|
if the query block is not found. |
||||
|
|
||||
|
@param pc pointer to Parse_context object |
||||
|
@param table_name query block name |
||||
|
@param hint processed hint // OLEGS: amend this
|
||||
|
|
||||
|
@return pointer to Opt_hints_table object if found, |
||||
|
NULL otherwise |
||||
|
*/ |
||||
|
|
||||
|
static Opt_hints_qb *find_qb_hints(Parse_context *pc, |
||||
|
const LEX_CSTRING *qb_name, |
||||
|
opt_hints_enum hint_type, |
||||
|
bool hint_state) |
||||
|
{ |
||||
|
if (qb_name->length == 0) // no QB NAME is used
|
||||
|
return pc->select->opt_hints_qb; |
||||
|
|
||||
|
Opt_hints_qb *qb= static_cast<Opt_hints_qb *> |
||||
|
(pc->thd->lex->opt_hints_global->find_by_name(qb_name)); |
||||
|
|
||||
|
if (qb == NULL) |
||||
|
{ |
||||
|
print_warn(pc->thd, ER_WARN_UNKNOWN_QB_NAME, hint_type, hint_state, |
||||
|
qb_name, NULL, NULL); |
||||
|
} |
||||
|
return qb; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
Returns pointer to Opt_hints_table object, |
||||
|
create Opt_hints_table object if not exist. |
||||
|
|
||||
|
@param pc pointer to Parse_context object |
||||
|
@param table_name pointer to Hint_param_table object |
||||
|
@param qb pointer to Opt_hints_qb object |
||||
|
|
||||
|
@return pointer to Opt_hints_table object, |
||||
|
NULL if failed to create the object |
||||
|
*/ |
||||
|
|
||||
|
static Opt_hints_table *get_table_hints(Parse_context *pc, |
||||
|
const LEX_CSTRING *table_name, |
||||
|
Opt_hints_qb *qb) |
||||
|
{ |
||||
|
Opt_hints_table *tab= |
||||
|
static_cast<Opt_hints_table *> (qb->find_by_name(table_name)); |
||||
|
if (!tab) |
||||
|
{ |
||||
|
tab= new Opt_hints_table(table_name, qb, pc->thd->mem_root); |
||||
|
qb->register_child(tab); |
||||
|
} |
||||
|
|
||||
|
return tab; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
bool Opt_hints::get_switch(opt_hints_enum type_arg) const |
||||
|
{ |
||||
|
if (is_specified(type_arg)) |
||||
|
return hints_map.switch_on(type_arg); |
||||
|
|
||||
|
if (opt_hint_info[type_arg].check_upper_lvl) |
||||
|
return parent->get_switch(type_arg); |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Opt_hints* Opt_hints::find_by_name(const LEX_CSTRING *name_arg) const |
||||
|
{ |
||||
|
for (uint i= 0; i < child_array.size(); i++) |
||||
|
{ |
||||
|
const LEX_CSTRING *name= child_array[i]->get_name(); |
||||
|
if (name && !cmp_lex_string(name, name_arg)) |
||||
|
return child_array[i]; |
||||
|
} |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Opt_hints::print(THD *thd, String *str) |
||||
|
{ |
||||
|
for (uint i= 0; i < MAX_HINT_ENUM; i++) |
||||
|
{ |
||||
|
if (is_specified(static_cast<opt_hints_enum>(i)) && is_resolved()) |
||||
|
{ |
||||
|
append_hint_type(str, static_cast<opt_hints_enum>(i)); |
||||
|
str->append(STRING_WITH_LEN("(")); |
||||
|
append_name(thd, str); |
||||
|
// OLEGS:
|
||||
|
//if (!opt_hint_info[i].switch_hint)
|
||||
|
// get_complex_hints(i)->append_args(thd, str);
|
||||
|
str->append(STRING_WITH_LEN(") ")); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (uint i= 0; i < child_array.size(); i++) |
||||
|
child_array[i]->print(thd, str); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Opt_hints::append_hint_type(String *str, opt_hints_enum type) |
||||
|
{ |
||||
|
const char* hint_name= opt_hint_info[type].hint_name; |
||||
|
if(!hints_map.switch_on(type)) |
||||
|
str->append(STRING_WITH_LEN("NO_")); |
||||
|
str->append(hint_name); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Opt_hints::print_warn_unresolved(THD *thd) |
||||
|
{ |
||||
|
String hint_name_str, hint_type_str; |
||||
|
append_name(thd, &hint_name_str); |
||||
|
|
||||
|
for (uint i= 0; i < MAX_HINT_ENUM; i++) |
||||
|
{ |
||||
|
if (is_specified(static_cast<opt_hints_enum>(i))) |
||||
|
{ |
||||
|
hint_type_str.length(0); |
||||
|
append_hint_type(&hint_type_str, static_cast<opt_hints_enum>(i)); |
||||
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, |
||||
|
get_warn_unresolved_code(), |
||||
|
ER_THD(thd, get_warn_unresolved_code()), |
||||
|
hint_name_str.c_ptr_safe(), |
||||
|
hint_type_str.c_ptr_safe()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Opt_hints::check_unresolved(THD *thd) |
||||
|
{ |
||||
|
if (!is_resolved()) |
||||
|
print_warn_unresolved(thd); |
||||
|
|
||||
|
if (!is_all_resolved()) |
||||
|
{ |
||||
|
for (uint i= 0; i < child_array.size(); i++) |
||||
|
child_array[i]->check_unresolved(thd); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
PT_hint *Opt_hints_global::get_complex_hints(uint type) |
||||
|
{ |
||||
|
DBUG_ASSERT(0); |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Opt_hints_qb::Opt_hints_qb(Opt_hints *opt_hints_arg, |
||||
|
MEM_ROOT *mem_root_arg, |
||||
|
uint select_number_arg) |
||||
|
: Opt_hints(NULL, opt_hints_arg, mem_root_arg), |
||||
|
select_number(select_number_arg) |
||||
|
{ |
||||
|
sys_name.str= buff; |
||||
|
sys_name.length= my_snprintf(buff, sizeof(buff), "%s%lx", |
||||
|
sys_qb_prefix.str, select_number); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Opt_hints_table *Opt_hints_qb::adjust_table_hints(TABLE *table, |
||||
|
const LEX_CSTRING *alias) |
||||
|
{ |
||||
|
Opt_hints_table *tab= static_cast<Opt_hints_table *>(find_by_name(alias)); |
||||
|
|
||||
|
table->pos_in_table_list->opt_hints_qb= this; |
||||
|
|
||||
|
if (!tab) // Tables not found
|
||||
|
return NULL; |
||||
|
|
||||
|
tab->adjust_key_hints(table); |
||||
|
return tab; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void Opt_hints_table::adjust_key_hints(TABLE *table) |
||||
|
{ |
||||
|
set_resolved(); |
||||
|
if (child_array_ptr()->size() == 0) // No key level hints
|
||||
|
{ |
||||
|
get_parent()->incr_resolved_children(); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* Make sure that adjustement is called only once. */ |
||||
|
DBUG_ASSERT(keyinfo_array.size() == 0); |
||||
|
keyinfo_array.resize(table->s->keys, NULL); |
||||
|
|
||||
|
for (Opt_hints** hint= child_array_ptr()->begin(); |
||||
|
hint < child_array_ptr()->end(); ++hint) |
||||
|
{ |
||||
|
KEY *key_info= table->key_info; |
||||
|
for (uint j= 0 ; j < table->s->keys ; j++, key_info++) |
||||
|
{ |
||||
|
if (!cmp_lex_string((*hint)->get_name(), &key_info->name)) |
||||
|
{ |
||||
|
(*hint)->set_resolved(); |
||||
|
keyinfo_array[j]= static_cast<Opt_hints_key *>(*hint); |
||||
|
incr_resolved_children(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
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(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
Function returns hint value depending on |
||||
|
the specfied hint level. If hint is specified |
||||
|
on current level, current level hint value is |
||||
|
returned, otherwise parent level hint is checked. |
||||
|
|
||||
|
@param hint Pointer to the hint object |
||||
|
@param parent_hint Pointer to the parent hint object, |
||||
|
should never be NULL |
||||
|
@param type_arg hint type |
||||
|
@param OUT ret_val hint value depending on |
||||
|
what hint level is used |
||||
|
|
||||
|
@return true if hint is specified, false otherwise |
||||
|
*/ |
||||
|
|
||||
|
static bool get_hint_state(Opt_hints *hint, |
||||
|
Opt_hints *parent_hint, |
||||
|
opt_hints_enum type_arg, |
||||
|
bool *ret_val) |
||||
|
{ |
||||
|
DBUG_ASSERT(parent_hint); |
||||
|
|
||||
|
if (opt_hint_info[type_arg].switch_hint) |
||||
|
{ |
||||
|
if (hint && hint->is_specified(type_arg)) |
||||
|
{ |
||||
|
*ret_val= hint->get_switch(type_arg); |
||||
|
return true; |
||||
|
} |
||||
|
else if (opt_hint_info[type_arg].check_upper_lvl && |
||||
|
parent_hint->is_specified(type_arg)) |
||||
|
{ |
||||
|
*ret_val= parent_hint->get_switch(type_arg); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
/* Complex hint, not implemented atm */ |
||||
|
DBUG_ASSERT(0); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool hint_key_state(const THD *thd, const TABLE *table, |
||||
|
uint keyno, opt_hints_enum type_arg, |
||||
|
uint optimizer_switch) |
||||
|
{ |
||||
|
Opt_hints_table *table_hints= table->pos_in_table_list->opt_hints_table; |
||||
|
|
||||
|
/* Parent should always be initialized */ |
||||
|
if (table_hints && keyno != MAX_KEY) |
||||
|
{ |
||||
|
Opt_hints_key *key_hints= table_hints->keyinfo_array.size() > 0 ? |
||||
|
table_hints->keyinfo_array[keyno] : NULL; |
||||
|
bool ret_val= false; |
||||
|
if (get_hint_state(key_hints, table_hints, type_arg, &ret_val)) |
||||
|
return ret_val; |
||||
|
} |
||||
|
|
||||
|
return optimizer_flag(thd, optimizer_switch); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool hint_table_state(const THD *thd, const TABLE *table, |
||||
|
opt_hints_enum type_arg, |
||||
|
uint optimizer_switch) |
||||
|
{ |
||||
|
TABLE_LIST *table_list= table->pos_in_table_list; |
||||
|
if (table_list->opt_hints_qb) |
||||
|
{ |
||||
|
bool ret_val= false; |
||||
|
if (get_hint_state(table_list->opt_hints_table, |
||||
|
table_list->opt_hints_qb, |
||||
|
type_arg, &ret_val)) |
||||
|
return ret_val; |
||||
|
} |
||||
|
|
||||
|
return optimizer_flag(thd, optimizer_switch); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool hint_table_state_or_fallback(const THD *thd, const TABLE *table, |
||||
|
opt_hints_enum type_arg, |
||||
|
bool fallback_value) |
||||
|
{ |
||||
|
TABLE_LIST *table_list= table->pos_in_table_list; |
||||
|
if (table_list->opt_hints_qb) |
||||
|
{ |
||||
|
bool ret_val= false; |
||||
|
if (get_hint_state(table_list->opt_hints_table, |
||||
|
table_list->opt_hints_qb, |
||||
|
type_arg, &ret_val)) |
||||
|
return ret_val; |
||||
|
} |
||||
|
|
||||
|
return fallback_value; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const |
||||
|
{ |
||||
|
const Table_level_hint_type &table_level_hint_type= *this; |
||||
|
opt_hints_enum hint_type; |
||||
|
bool hint_state; // ON or OFF
|
||||
|
|
||||
|
switch (table_level_hint_type.id()) |
||||
|
{ |
||||
|
case TokenID::keyword_BNL: |
||||
|
hint_type= BNL_HINT_ENUM; |
||||
|
hint_state= true; |
||||
|
break; |
||||
|
case TokenID::keyword_NO_BNL: |
||||
|
hint_type= BNL_HINT_ENUM; |
||||
|
hint_state= false; |
||||
|
break; |
||||
|
case TokenID::keyword_BKA: |
||||
|
hint_type= BKA_HINT_ENUM; |
||||
|
hint_state= true; |
||||
|
break; |
||||
|
case TokenID::keyword_NO_BKA: |
||||
|
hint_type= BKA_HINT_ENUM; |
||||
|
hint_state= false; |
||||
|
break; |
||||
|
default: |
||||
|
DBUG_ASSERT(0); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
if (const At_query_block_name_opt_table_name_list & |
||||
|
at_query_block_name_opt_table_name_list= *this) |
||||
|
{ |
||||
|
// this is @ query_block_name opt_table_name_list
|
||||
|
const Query_block_name &qb_name= *this; |
||||
|
Opt_hints_qb *qb= find_qb_hints(pc, &qb_name, hint_type, hint_state); |
||||
|
if (qb == NULL) |
||||
|
return false; |
||||
|
if (at_query_block_name_opt_table_name_list.is_empty()) |
||||
|
{ |
||||
|
// e.g. BKA(@qb1)
|
||||
|
if (qb->set_switch(hint_state, hint_type, false)) |
||||
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, |
||||
|
&qb_name, NULL, NULL/*, this*/); |
||||
|
return false; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// e.g. BKA(@qb1 t1, t2, t3)
|
||||
|
const Opt_table_name_list &opt_table_name_list= *this; |
||||
|
for (const Table_name &table : opt_table_name_list) |
||||
|
{ |
||||
|
Opt_hints_table *tab= get_table_hints(pc, &table, qb); |
||||
|
if (!tab) |
||||
|
return true; // OLEGS: why no warning?
|
||||
|
if (tab->set_switch(hint_state, hint_type, true)) |
||||
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, |
||||
|
&qb_name, &table, NULL/*, this*/); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// this is opt_hint_param_table_list
|
||||
|
const Opt_table_name_list &table_name_list= *this; |
||||
|
const Opt_hint_param_table_list &opt_hint_param_table_list= *this; |
||||
|
Opt_hints_qb *qb= find_qb_hints(pc, &null_clex_str, hint_type, hint_state); |
||||
|
if (qb == NULL) |
||||
|
return false; |
||||
|
if (table_name_list.is_empty() && opt_hint_param_table_list.is_empty()) |
||||
|
{ |
||||
|
// e.g. BKA()
|
||||
|
if (qb->set_switch(hint_state, hint_type, false)) |
||||
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, |
||||
|
&null_clex_str, NULL, NULL/*, this*/); |
||||
|
return false; |
||||
|
} |
||||
|
for (const Table_name &table : table_name_list) |
||||
|
{ |
||||
|
// e.g. BKA(t1, t2)
|
||||
|
Opt_hints_table *tab= get_table_hints(pc, &table, qb); |
||||
|
if (!tab) |
||||
|
return true; // OLEGS: no warning?
|
||||
|
if (tab->set_switch(hint_state, hint_type, true)) |
||||
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, |
||||
|
&null_clex_str, &table, NULL/*, this*/); |
||||
|
} |
||||
|
|
||||
|
for (const Hint_param_table &table : opt_hint_param_table_list) |
||||
|
{ |
||||
|
// e.g. BKA(t1@qb1, t2@qb2)
|
||||
|
const Query_block_name &qb_name= table; |
||||
|
const Table_name &table_name= table; |
||||
|
Opt_hints_qb *qb= find_qb_hints(pc, &qb_name, hint_type, hint_state); |
||||
|
if (qb == NULL) |
||||
|
return false; |
||||
|
// OLEGS: todo
|
||||
|
Opt_hints_table *tab= get_table_hints(pc, &table_name, qb); |
||||
|
if (!tab) |
||||
|
return true; // OLEGS: why no warning?
|
||||
|
|
||||
|
if (tab->set_switch(hint_state, hint_type, true)) |
||||
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, |
||||
|
&qb_name, &table_name, NULL/*, this*/); |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool Optimizer_hint_parser::Index_level_hint::resolve(Parse_context *pc) const |
||||
|
{ |
||||
|
const Index_level_hint_type &index_level_hint_type= *this; |
||||
|
opt_hints_enum hint_type; |
||||
|
bool hint_state; // ON or OFF
|
||||
|
|
||||
|
switch (index_level_hint_type.id()) |
||||
|
{ |
||||
|
case TokenID::keyword_NO_ICP: |
||||
|
hint_type= ICP_HINT_ENUM; |
||||
|
hint_state= false; |
||||
|
break; |
||||
|
case TokenID::keyword_MRR: |
||||
|
hint_type= MRR_HINT_ENUM; |
||||
|
hint_state= true; |
||||
|
break; |
||||
|
case TokenID::keyword_NO_MRR: |
||||
|
hint_type= MRR_HINT_ENUM; |
||||
|
hint_state= false; |
||||
|
break; |
||||
|
case TokenID::keyword_NO_RANGE_OPTIMIZATION: |
||||
|
hint_type= NO_RANGE_HINT_ENUM; |
||||
|
hint_state= true; |
||||
|
break; |
||||
|
default: |
||||
|
DBUG_ASSERT(0); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
const Hint_param_table_ext &table_ext= *this; |
||||
|
const Query_block_name &qb_name= table_ext; |
||||
|
const Table_name &table_name= table_ext; |
||||
|
|
||||
|
Opt_hints_qb *qb= find_qb_hints(pc, &qb_name, hint_type, hint_state); |
||||
|
if (qb == NULL) |
||||
|
return false; |
||||
|
|
||||
|
Opt_hints_table *tab= get_table_hints(pc, &table_name, qb); |
||||
|
if (!tab) |
||||
|
return true; // OLEGS: why no warning?
|
||||
|
|
||||
|
if (is_empty()) // Table level hint
|
||||
|
{ |
||||
|
if (tab->set_switch(hint_state, hint_type, false)) |
||||
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, |
||||
|
&qb_name, &table_name, NULL/*, this*/); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
for (const Hint_param_index &index_name : *this) |
||||
|
{ |
||||
|
Opt_hints_key *idx= (Opt_hints_key *)tab->find_by_name(&index_name); |
||||
|
if (!idx) |
||||
|
{ |
||||
|
idx= new Opt_hints_key(&index_name, tab, pc->thd->mem_root); |
||||
|
tab->register_child(idx); |
||||
|
} |
||||
|
|
||||
|
if (idx->set_switch(hint_state, hint_type, true)) |
||||
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state, |
||||
|
&qb_name, &table_name, &index_name/*, this*/); |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool Optimizer_hint_parser::Qb_name_hint::resolve(Parse_context *pc) const |
||||
|
{ |
||||
|
Opt_hints_qb *qb= pc->select->opt_hints_qb; |
||||
|
|
||||
|
DBUG_ASSERT(qb); |
||||
|
|
||||
|
const Query_block_name &qb_name= *this; |
||||
|
|
||||
|
if (qb->get_name() || // QB name is already set
|
||||
|
qb->get_parent()->find_by_name(&qb_name)) // Name is already used
|
||||
|
{ |
||||
|
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, QB_NAME_HINT_ENUM, false, |
||||
|
NULL, NULL, NULL/*, this*/); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
qb->set_name(&qb_name); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool Optimizer_hint_parser::Hint_list::resolve(Parse_context *pc) |
||||
|
{ |
||||
|
if (!get_qb_hints(pc)) |
||||
|
return true; |
||||
|
|
||||
|
List_iterator_fast<Optimizer_hint_parser::Hint> li(*this); |
||||
|
while(Optimizer_hint_parser::Hint *hint= li++) |
||||
|
{ |
||||
|
if (const Table_level_hint &table_hint= |
||||
|
static_cast<const Table_level_hint &>(*hint)) |
||||
|
{ |
||||
|
if (table_hint.resolve(pc)) |
||||
|
return true; |
||||
|
} |
||||
|
else if (const Index_level_hint &index_hint= |
||||
|
static_cast<const Index_level_hint &>(*hint)) |
||||
|
{ |
||||
|
if (index_hint.resolve(pc)) |
||||
|
return true; |
||||
|
} |
||||
|
else if (const Qb_name_hint &qb_hint= |
||||
|
static_cast<const Qb_name_hint &>(*hint)) |
||||
|
{ |
||||
|
if (qb_hint.resolve(pc)) |
||||
|
return true; // OLEGS: check this result
|
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
@ -0,0 +1,507 @@ |
|||||
|
/* Copyright (c) 2015, 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 as published by |
||||
|
the Free Software Foundation; version 2 of the License. |
||||
|
|
||||
|
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 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 */ |
||||
|
|
||||
|
/* |
||||
|
Parse tree node classes for optimizer hint syntax |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
#ifndef OPT_HINTS_INCLUDED |
||||
|
#define OPT_HINTS_INCLUDED |
||||
|
|
||||
|
#include "my_config.h" |
||||
|
#include "sql_alloc.h" |
||||
|
#include "sql_list.h" |
||||
|
#include "mem_root_array.h" |
||||
|
#include "sql_string.h" |
||||
|
#include "sql_bitmap.h" |
||||
|
#include "sql_show.h" |
||||
|
#include "mysqld_error.h" |
||||
|
|
||||
|
|
||||
|
struct LEX; |
||||
|
struct TABLE; |
||||
|
|
||||
|
/** |
||||
|
Hint types, MAX_HINT_ENUM should be always last. |
||||
|
This enum should be synchronized with opt_hint_info |
||||
|
array(see opt_hints.cc). |
||||
|
*/ |
||||
|
enum opt_hints_enum |
||||
|
{ |
||||
|
BKA_HINT_ENUM= 0, |
||||
|
BNL_HINT_ENUM, |
||||
|
ICP_HINT_ENUM, |
||||
|
MRR_HINT_ENUM, |
||||
|
NO_RANGE_HINT_ENUM, |
||||
|
QB_NAME_HINT_ENUM, |
||||
|
MAX_HINT_ENUM |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
struct st_opt_hint_info |
||||
|
{ |
||||
|
const char* hint_name; // Hint name. |
||||
|
bool check_upper_lvl; // true if upper level hint check is needed (for hints |
||||
|
// which can be specified on more than one level). |
||||
|
bool switch_hint; // true if hint is not complex. |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
Opt_hints_map contains information |
||||
|
about hint state(specified or not, hint value). |
||||
|
*/ |
||||
|
|
||||
|
class Opt_hints_map : public Sql_alloc |
||||
|
{ |
||||
|
Bitmap<64> hints; // hint state |
||||
|
Bitmap<64> hints_specified; // true if hint is specified |
||||
|
|
||||
|
public: |
||||
|
Opt_hints_map() |
||||
|
{ |
||||
|
hints.clear_all(); |
||||
|
hints_specified.clear_all(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
Check if hint is specified. |
||||
|
|
||||
|
@param type_arg hint type |
||||
|
|
||||
|
@return true if hint is specified, |
||||
|
false otherwise |
||||
|
*/ |
||||
|
my_bool is_specified(opt_hints_enum type_arg) const |
||||
|
{ |
||||
|
return hints_specified.is_set(type_arg); |
||||
|
} |
||||
|
/** |
||||
|
Set switch value and set hint into specified state. |
||||
|
|
||||
|
@param type_arg hint type |
||||
|
@param switch_state_arg switch value |
||||
|
*/ |
||||
|
void set_switch(opt_hints_enum type_arg, |
||||
|
bool switch_state_arg) |
||||
|
{ |
||||
|
if (switch_state_arg) |
||||
|
hints.set_bit(type_arg); |
||||
|
else |
||||
|
hints.clear_bit(type_arg); |
||||
|
hints_specified.set_bit(type_arg); |
||||
|
} |
||||
|
/** |
||||
|
Get switch value. |
||||
|
|
||||
|
@param type_arg hint type |
||||
|
|
||||
|
@return switch value. |
||||
|
*/ |
||||
|
bool switch_on(opt_hints_enum type_arg) const |
||||
|
{ |
||||
|
return hints.is_set(type_arg); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
class PT_hint; |
||||
|
class PT_hint_max_execution_time; |
||||
|
class Opt_hints_key; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
Opt_hints class is used as ancestor for Opt_hints_global, |
||||
|
Opt_hints_qb, Opt_hints_table, Opt_hints_key classes. |
||||
|
|
||||
|
Opt_hints_global class is hierarchical structure. |
||||
|
It contains information about global hints and also |
||||
|
conains array of QUERY BLOCK level objects (Opt_hints_qb class). |
||||
|
Each QUERY BLOCK level object contains array of TABLE level hints |
||||
|
(class Opt_hints_table). Each TABLE level hint contains array of |
||||
|
KEY lelev hints (Opt_hints_key class). |
||||
|
Hint information(specified, on|off state) is stored in hints_map object. |
||||
|
*/ |
||||
|
|
||||
|
class Opt_hints : public Sql_alloc |
||||
|
{ |
||||
|
/* |
||||
|
Name of object referred by the hint. |
||||
|
This name is empty for global level, |
||||
|
query block name for query block level, |
||||
|
table name for table level and key name |
||||
|
for key level. |
||||
|
*/ |
||||
|
const LEX_CSTRING *name; |
||||
|
/* |
||||
|
Parent object. There is no parent for global level, |
||||
|
for query block level parent is Opt_hints_global object, |
||||
|
for table level parent is Opt_hints_qb object, |
||||
|
for key level parent is Opt_hints_key object. |
||||
|
*/ |
||||
|
Opt_hints *parent; |
||||
|
|
||||
|
Opt_hints_map hints_map; // Hint map |
||||
|
|
||||
|
/* Array of child objects. i.e. array of the lower level objects */ |
||||
|
Mem_root_array<Opt_hints*, true> child_array; |
||||
|
/* true if hint is connected to the real object */ |
||||
|
bool resolved; |
||||
|
/* Number of resolved children */ |
||||
|
uint resolved_children; |
||||
|
|
||||
|
public: |
||||
|
|
||||
|
Opt_hints(const LEX_CSTRING *name_arg, |
||||
|
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) |
||||
|
{ } |
||||
|
|
||||
|
bool is_specified(opt_hints_enum type_arg) const |
||||
|
{ |
||||
|
return hints_map.is_specified(type_arg); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
Function sets switch hint state. |
||||
|
|
||||
|
@param switch_state_arg switch hint state |
||||
|
@param type_arg hint type |
||||
|
@param check_parent true if hint can be on parent level |
||||
|
|
||||
|
@return true if hint is already specified, |
||||
|
false otherwise |
||||
|
*/ |
||||
|
bool set_switch(bool switch_state_arg, |
||||
|
opt_hints_enum type_arg, |
||||
|
bool check_parent) |
||||
|
{ |
||||
|
if (is_specified(type_arg) || |
||||
|
(check_parent && parent->is_specified(type_arg))) |
||||
|
return true; |
||||
|
|
||||
|
hints_map.set_switch(type_arg, switch_state_arg); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
Function returns switch hint state. |
||||
|
|
||||
|
@param type_arg hint type |
||||
|
|
||||
|
@return hint value if hint is specified, |
||||
|
false otherwise |
||||
|
*/ |
||||
|
bool get_switch(opt_hints_enum type_arg) const; |
||||
|
|
||||
|
virtual const LEX_CSTRING *get_name() const { return name; } |
||||
|
void set_name(const LEX_CSTRING *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++; } |
||||
|
Mem_root_array<Opt_hints*, true> *child_array_ptr() { return &child_array; } |
||||
|
|
||||
|
bool is_all_resolved() const |
||||
|
{ |
||||
|
return child_array.size() == resolved_children; |
||||
|
} |
||||
|
|
||||
|
void register_child(Opt_hints* hint_arg) |
||||
|
{ |
||||
|
child_array.push_back(hint_arg); |
||||
|
} |
||||
|
|
||||
|
// OLEGS: remove it if not used |
||||
|
/** |
||||
|
Returns pointer to complex hint for a given type |
||||
|
|
||||
|
@param type hint type |
||||
|
|
||||
|
@return pointer to complex hint for a given type. |
||||
|
*/ |
||||
|
// virtual PT_hint *get_complex_hints(uint type) |
||||
|
// { |
||||
|
// DBUG_ASSERT(0); |
||||
|
// return NULL; /* error C4716: must return a value*/ |
||||
|
// }; |
||||
|
|
||||
|
/** |
||||
|
Find hint among lower-level hint objects. |
||||
|
|
||||
|
@param name_arg hint name |
||||
|
|
||||
|
@return hint if found, |
||||
|
NULL otherwise |
||||
|
*/ |
||||
|
Opt_hints *find_by_name(const LEX_CSTRING *name_arg) const; |
||||
|
/** |
||||
|
Print all hints except of QB_NAME hint. |
||||
|
|
||||
|
@param thd Pointer to THD object |
||||
|
@param str Pointer to String object |
||||
|
*/ |
||||
|
void print(THD *thd, String *str); |
||||
|
/** |
||||
|
Check if there are any unresolved hint objects and |
||||
|
print warnings for them. |
||||
|
|
||||
|
@param thd Pointer to THD object |
||||
|
*/ |
||||
|
void check_unresolved(THD *thd); |
||||
|
virtual void append_name(THD *thd, String *str)= 0; |
||||
|
|
||||
|
virtual ~Opt_hints() {} |
||||
|
|
||||
|
private: |
||||
|
/** |
||||
|
Append hint type. |
||||
|
|
||||
|
@param str Pointer to String object |
||||
|
@param type Hint type |
||||
|
*/ |
||||
|
void append_hint_type(String *str, opt_hints_enum type); |
||||
|
/** |
||||
|
Print warning for unresolved hint name. |
||||
|
|
||||
|
@param thd Pointer to THD object |
||||
|
*/ |
||||
|
void print_warn_unresolved(THD *thd); |
||||
|
|
||||
|
protected: |
||||
|
/** |
||||
|
Override this function in descendants so that print_warn_unresolved() |
||||
|
prints the proper warning text for table/index level unresolved hints |
||||
|
*/ |
||||
|
virtual uint get_warn_unresolved_code() const { return 0; } |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
Global level hints. |
||||
|
*/ |
||||
|
|
||||
|
class Opt_hints_global : public Opt_hints |
||||
|
{ |
||||
|
|
||||
|
public: |
||||
|
PT_hint_max_execution_time *max_exec_time; |
||||
|
|
||||
|
Opt_hints_global(MEM_ROOT *mem_root_arg) |
||||
|
: Opt_hints(NULL, NULL, mem_root_arg) |
||||
|
{ |
||||
|
max_exec_time= NULL; |
||||
|
} |
||||
|
|
||||
|
virtual void append_name(THD *thd, String *str) {} |
||||
|
virtual PT_hint *get_complex_hints(uint type); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
class Opt_hints_table; |
||||
|
|
||||
|
/** |
||||
|
Query block level hints. |
||||
|
*/ |
||||
|
|
||||
|
class Opt_hints_qb : public Opt_hints |
||||
|
{ |
||||
|
uint select_number; // SELECT_LEX number |
||||
|
LEX_CSTRING sys_name; // System QB name |
||||
|
char buff[32]; // Buffer to hold sys name |
||||
|
|
||||
|
public: |
||||
|
|
||||
|
Opt_hints_qb(Opt_hints *opt_hints_arg, |
||||
|
MEM_ROOT *mem_root_arg, |
||||
|
uint select_number_arg); |
||||
|
|
||||
|
const LEX_CSTRING *get_print_name() |
||||
|
{ |
||||
|
const LEX_CSTRING *str= Opt_hints::get_name(); |
||||
|
return str ? str : &sys_name; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
Append query block hint. |
||||
|
|
||||
|
@param thd pointer to THD object |
||||
|
@param str pointer to String object |
||||
|
*/ |
||||
|
void append_qb_hint(THD *thd, String *str) |
||||
|
{ |
||||
|
if (get_name()) |
||||
|
{ |
||||
|
str->append(STRING_WITH_LEN("QB_NAME(")); |
||||
|
append_identifier(thd, str, get_name()->str, get_name()->length); |
||||
|
str->append(STRING_WITH_LEN(") ")); |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
Append query block name. |
||||
|
|
||||
|
@param thd pointer to THD object |
||||
|
@param str pointer to String object |
||||
|
*/ |
||||
|
virtual void append_name(THD *thd, String *str) |
||||
|
{ |
||||
|
str->append(STRING_WITH_LEN("@")); |
||||
|
append_identifier(thd, str, get_print_name()->str, get_print_name()->length); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
Function finds Opt_hints_table object corresponding to |
||||
|
table alias in the query block and attaches corresponding |
||||
|
key hint objects to appropriate KEY structures. |
||||
|
|
||||
|
@param table Pointer to TABLE object |
||||
|
@param alias Table alias |
||||
|
|
||||
|
@return pointer Opt_hints_table object if this object is found, |
||||
|
NULL otherwise. |
||||
|
*/ |
||||
|
Opt_hints_table *adjust_table_hints(TABLE *table, const LEX_CSTRING *alias); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
Table level hints. |
||||
|
*/ |
||||
|
|
||||
|
class Opt_hints_table : public Opt_hints |
||||
|
{ |
||||
|
public: |
||||
|
Mem_root_array<Opt_hints_key*, true> keyinfo_array; |
||||
|
|
||||
|
Opt_hints_table(const LEX_CSTRING *table_name_arg, |
||||
|
Opt_hints_qb *qb_hints_arg, |
||||
|
MEM_ROOT *mem_root_arg) |
||||
|
: Opt_hints(table_name_arg, qb_hints_arg, mem_root_arg), |
||||
|
keyinfo_array(mem_root_arg) |
||||
|
{ } |
||||
|
|
||||
|
/** |
||||
|
Append table name. |
||||
|
|
||||
|
@param thd pointer to THD object |
||||
|
@param str pointer to String object |
||||
|
*/ |
||||
|
virtual void append_name(THD *thd, String *str) |
||||
|
{ |
||||
|
append_identifier(thd, str, get_name()->str, get_name()->length); |
||||
|
get_parent()->append_name(thd, str); |
||||
|
} |
||||
|
/** |
||||
|
Function sets correlation between key hint objects and |
||||
|
appropriate KEY structures. |
||||
|
|
||||
|
@param table Pointer to TABLE object |
||||
|
*/ |
||||
|
void adjust_key_hints(TABLE *table); |
||||
|
|
||||
|
virtual uint get_warn_unresolved_code() const override |
||||
|
{ |
||||
|
return ER_UNRESOLVED_TABLE_HINT_NAME; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
Key level hints. |
||||
|
*/ |
||||
|
|
||||
|
class Opt_hints_key : public Opt_hints |
||||
|
{ |
||||
|
public: |
||||
|
|
||||
|
Opt_hints_key(const LEX_CSTRING *key_name_arg, |
||||
|
Opt_hints_table *table_hints_arg, |
||||
|
MEM_ROOT *mem_root_arg) |
||||
|
: Opt_hints(key_name_arg, table_hints_arg, mem_root_arg) |
||||
|
{ } |
||||
|
|
||||
|
/** |
||||
|
Append key name. |
||||
|
|
||||
|
@param thd pointer to THD object |
||||
|
@param str pointer to String object |
||||
|
*/ |
||||
|
virtual void append_name(THD *thd, String *str) |
||||
|
{ |
||||
|
get_parent()->append_name(thd, str); |
||||
|
str->append(' '); |
||||
|
append_identifier(thd, str, get_name()->str, get_name()->length); |
||||
|
} |
||||
|
|
||||
|
virtual uint get_warn_unresolved_code() const override |
||||
|
{ |
||||
|
return ER_UNRESOLVED_INDEX_HINT_NAME; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
Returns key hint value if hint is specified, returns |
||||
|
optimizer switch value if hint is not specified. |
||||
|
|
||||
|
@param thd Pointer to THD object |
||||
|
@param tab Pointer to TABLE object |
||||
|
@param keyno Key number |
||||
|
@param type_arg Hint type |
||||
|
@param optimizer_switch Optimizer switch flag |
||||
|
|
||||
|
@return key hint value if hint is specified, |
||||
|
otherwise optimizer switch value. |
||||
|
*/ |
||||
|
bool hint_key_state(const THD *thd, const TABLE *table, |
||||
|
uint keyno, opt_hints_enum type_arg, |
||||
|
uint optimizer_switch); |
||||
|
|
||||
|
/** |
||||
|
Returns table hint value if hint is specified, returns |
||||
|
optimizer switch value if hint is not specified. |
||||
|
|
||||
|
@param thd Pointer to THD object |
||||
|
@param tab Pointer to TABLE object |
||||
|
@param type_arg Hint type |
||||
|
@param optimizer_switch Optimizer switch flag |
||||
|
|
||||
|
@return table hint value if hint is specified, |
||||
|
otherwise optimizer switch value. |
||||
|
*/ |
||||
|
bool hint_table_state(const THD *thd, const TABLE *table, |
||||
|
opt_hints_enum type_arg, |
||||
|
uint optimizer_switch); |
||||
|
|
||||
|
/** |
||||
|
Returns table hint value if hint is specified, returns |
||||
|
fallback value if hint is not specified. |
||||
|
|
||||
|
@param thd Pointer to THD object |
||||
|
@param tab Pointer to TABLE object |
||||
|
@param type_arg Hint type |
||||
|
@param fallback_value Value to be returned if the hint is not set |
||||
|
|
||||
|
@return table hint value if hint is specified, |
||||
|
otherwise fallback value. |
||||
|
*/ |
||||
|
bool hint_table_state_or_fallback(const THD *thd, const TABLE *table, |
||||
|
opt_hints_enum type_arg, |
||||
|
bool fallback_value); |
||||
|
|
||||
|
#endif /* OPT_HINTS_INCLUDED */ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue