MDEV-33971 NAME_CONST in WHERE clause replaced by inner item

Improve performance of queries like
  SELECT * FROM t1 WHERE field = NAME_CONST('a', 4);
by, in this example, replacing the WHERE clause with field = 4
in the case of ref access.

The rewrite is done during fix_fields and we disambiguate this
case from other cases of NAME_CONST by inspecting where we are
in parsing.  We rely on THD::where to accomplish this.  To
improve performance there, we change the type of THD::where to
be an enumeration, so we can avoid string comparisons during
Item_name_const::fix_fields.  Consequently, this patch also
changes all usages of THD::where to conform likewise.
This commit is contained in:
Dave Gosselin 2024-04-26 12:13:31 -04:00 committed by Dave Gosselin
parent a0a7b1c128
commit 02e38e2ece
20 changed files with 310 additions and 75 deletions

View File

@ -126,7 +126,7 @@ group by
a.text, b.id, b.betreff
order by
match(b.betreff) against ('+abc' in boolean mode) desc;
ERROR 42000: Table 'b' from one of the SELECTs cannot be used in ORDER clause
ERROR 42000: Table 'b' from one of the SELECTs cannot be used in order clause
select a.text, b.id, b.betreff
from
t2 a inner join t3 b on a.id = b.forum inner join
@ -142,7 +142,7 @@ where
match(c.beitrag) against ('+abc' in boolean mode)
order by
match(b.betreff) against ('+abc' in boolean mode) desc;
ERROR 42000: Table 'b' from one of the SELECTs cannot be used in ORDER clause
ERROR 42000: Table 'b' from one of the SELECTs cannot be used in order clause
select a.text, b.id, b.betreff
from
t2 a inner join t3 b on a.id = b.forum inner join

View File

@ -0,0 +1,87 @@
create table t1 (a int, b int);
insert into t1 values (1,1),(2,2);
explain format=json
select * from t1 where a=name_const('varname',1);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100,
"attached_condition": "t1.a = 1"
}
}
}
explain format=json
select * from t1 left join t1 as t2 on t1.a=name_const('varname',1) and t1.b=t2.b;
EXPLAIN
{
"query_block": {
"select_id": 1,
"const_condition": "1",
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100
},
"block-nl-join": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 2,
"filtered": 100
},
"buffer_type": "flat",
"buffer_size": "141",
"join_type": "BNL",
"attached_condition": "trigcond(t2.b = t1.b and trigcond(t1.a = 1))"
}
}
}
create table t2 (
a varchar(100) collate utf8_unicode_ci,
b int
);
insert into t2 values ('foo', 1),('bar', 1);
create procedure p1(var1 varchar(10))
update t2 set b=b+1 where a=var1;
call p1('foo');
call p1('foo');
call p1('foo');
select * from t2;
a b
foo 4
bar 1
create table t3 (
a varchar(100) collate utf8_unicode_ci,
b int
);
insert into t3 values ('foo', 1),('bar', 1);
select * from t3;
a b
foo 1
bar 1
explain format=json
update t3 set b=b+1 where a= NAME_CONST('var1',_latin1'foo' COLLATE 'latin1_swedish_ci');
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"update": 1,
"table_name": "t3",
"access_type": "ALL",
"rows": 2,
"attached_condition": "t3.a = convert(_latin1'foo' collate latin1_swedish_ci using utf8mb3)"
}
}
}
select * from t3 where a= NAME_CONST('var1',_latin1'foo' COLLATE 'latin1_swedish_ci');
a b
foo 1
drop procedure p1;
drop table t1, t2, t3;

View File

@ -0,0 +1,38 @@
#
# MDEV-33971 Using NAME_CONST() changes the plan
#
create table t1 (a int, b int);
insert into t1 values (1,1),(2,2);
explain format=json
select * from t1 where a=name_const('varname',1);
explain format=json
select * from t1 left join t1 as t2 on t1.a=name_const('varname',1) and t1.b=t2.b;
create table t2 (
a varchar(100) collate utf8_unicode_ci,
b int
);
insert into t2 values ('foo', 1),('bar', 1);
create procedure p1(var1 varchar(10))
update t2 set b=b+1 where a=var1;
call p1('foo');
call p1('foo');
call p1('foo');
select * from t2;
create table t3 (
a varchar(100) collate utf8_unicode_ci,
b int
);
insert into t3 values ('foo', 1),('bar', 1);
select * from t3;
explain format=json
update t3 set b=b+1 where a= NAME_CONST('var1',_latin1'foo' COLLATE 'latin1_swedish_ci');
select * from t3 where a= NAME_CONST('var1',_latin1'foo' COLLATE 'latin1_swedish_ci');
drop procedure p1;
drop table t1, t2, t3;

View File

@ -80,7 +80,7 @@ a b
2 b
1 a
(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b;
ERROR 42000: Table 't1' from one of the SELECTs cannot be used in ORDER clause
ERROR 42000: Table 't1' from one of the SELECTs cannot be used in order clause
explain extended (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 4 100.00
@ -493,7 +493,7 @@ drop temporary table t1;
create table t1 select a from t1 union select a from t2;
ERROR 42S01: Table 't1' already exists
select a from t1 union select a from t2 order by t2.a;
ERROR 42000: Table 't2' from one of the SELECTs cannot be used in ORDER clause
ERROR 42000: Table 't2' from one of the SELECTs cannot be used in order clause
drop table t1,t2;
select length(version()) > 1 as `*` UNION select 2;
*

View File

@ -129,7 +129,7 @@ group by
a.text, b.id, b.betreff
order by
match(b.betreff) against ('+abc' in boolean mode) desc;
ERROR 42000: Table 'b' from one of the SELECTs cannot be used in ORDER clause
ERROR 42000: Table 'b' from one of the SELECTs cannot be used in order clause
select a.text, b.id, b.betreff
from
t2 a inner join t3 b on a.id = b.forum inner join
@ -145,7 +145,7 @@ where
match(c.beitrag) against ('+abc' in boolean mode)
order by
match(b.betreff) against ('+abc' in boolean mode) desc;
ERROR 42000: Table 'b' from one of the SELECTs cannot be used in ORDER clause
ERROR 42000: Table 'b' from one of the SELECTs cannot be used in order clause
select a.text, b.id, b.betreff
from
t2 a inner join t3 b on a.id = b.forum inner join

View File

@ -2184,6 +2184,36 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
my_error(ER_RESERVED_SYNTAX, MYF(0), "NAME_CONST");
return TRUE;
}
/*
If we have either of the following:
... WHERE foo=NAME_CONST(...)
... JOIN ... ON foo=NAME_CONST(...)
then we have an opportunity to unwrap the NAME_CONST and
use the enclosed value directly, replacing NAME_CONST in
the parse tree with the value it encloses.
*/
if ((thd->where == THD_WHERE::WHERE_CLAUSE ||
thd->where == THD_WHERE::ON_CLAUSE) &&
(value_item->type() == FUNC_ITEM ||
value_item->type() == CONST_ITEM))
{
thd->change_item_tree(ref, value_item);
/*
We're replacing NAME_CONST('name', value_item) with value_item.
Only a few constants and functions are possible as value_item, see
Create_func_name_const::create_2_arg.
Set the value_item's coercibility to be the same as NAME_CONST(...)
would have (see how it's set a few lines below).
*/
if (value_item->collation.derivation != DERIVATION_NUMERIC)
value_item->collation.set(value_item->collation.collation,
DERIVATION_IMPLICIT);
return FALSE;
}
// else, could not unwrap, fall back to default handling below.
if (value_item->collation.derivation == DERIVATION_NUMERIC)
collation= DTCollation_numeric();
else
@ -5528,7 +5558,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
is ambiguous.
*/
my_error(ER_NON_UNIQ_ERROR, MYF(0),
find_item->full_name(), current_thd->where);
find_item->full_name(), thd_where(current_thd));
return NULL;
}
}
@ -5613,7 +5643,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_NON_UNIQ_ERROR,
ER_THD(thd,ER_NON_UNIQ_ERROR), ref->full_name(),
thd->where);
thd_where(thd));
}
}
@ -5947,7 +5977,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
if (upward_lookup)
{
// We can't say exactly what absent table or field
my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where);
my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd_where(thd));
}
else
{
@ -6174,7 +6204,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
{
/* The column to which we link isn't valid. */
my_error(ER_BAD_FIELD_ERROR, MYF(0), (*res)->name.str,
thd->where);
thd_where(thd));
return(1);
}
@ -6219,7 +6249,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if (unlikely(!select))
{
my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where);
my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd_where(thd));
goto error;
}
if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
@ -8163,7 +8193,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
if (unlikely(!outer_context))
{
/* The current reference cannot be resolved in this query. */
my_error(ER_BAD_FIELD_ERROR,MYF(0), full_name(), thd->where);
my_error(ER_BAD_FIELD_ERROR,MYF(0), full_name(), thd_where(thd));
goto error;
}
@ -8314,7 +8344,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
{
/* The item was not a table field and not a reference */
my_error(ER_BAD_FIELD_ERROR, MYF(0),
this->full_name(), thd->where);
this->full_name(), thd_where(thd));
goto error;
}
/* Should be checked in resolve_ref_in_select_and_group(). */

View File

@ -241,7 +241,7 @@ Item_subselect::select_transformer(JOIN *join)
bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
{
char const *save_where= thd_param->where;
THD_WHERE save_where= thd_param->where;
uint8 uncacheable;
bool res;
@ -320,7 +320,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
if (have_to_be_excluded)
engine->exclude();
substitution= 0;
thd->where= "checking transformed subquery";
thd->where= THD_WHERE::CHECKING_TRANSFORMED_SUBQUERY;
res= (*ref)->fix_fields_if_needed(thd, ref);
goto end;
@ -3403,13 +3403,13 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
{
Query_arena *arena= 0, backup;
SELECT_LEX *current= thd->lex->current_select;
const char *save_where= thd->where;
THD_WHERE save_where= thd->where;
bool trans_res= true;
bool result;
DBUG_ENTER("Item_in_subselect::select_in_like_transformer");
DBUG_ASSERT(thd == join->thd);
thd->where= "IN/ALL/ANY subquery";
thd->where= THD_WHERE::IN_ALL_ANY_SUBQUERY;
/*
In some optimisation cases we will not need this Item_in_optimizer
@ -3496,7 +3496,7 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
{
uint outer_cols_num;
List<Item> *inner_cols;
char const *save_where= thd_arg->where;
THD_WHERE save_where= thd_arg->where;
DBUG_ENTER("Item_in_subselect::fix_fields");
thd= thd_arg;
@ -3505,7 +3505,7 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
if (test_strategy(SUBS_SEMI_JOIN))
DBUG_RETURN( !( (*ref)= new (thd->mem_root) Item_int(thd, 1)) );
thd->where= "IN/ALL/ANY subquery";
thd->where= THD_WHERE::IN_ALL_ANY_SUBQUERY;
/*
Check if the outer and inner IN operands match in those cases when we
will not perform IN=>EXISTS transformation. Currently this is when we
@ -4016,7 +4016,7 @@ int join_read_next_same_or_null(READ_RECORD *info);
int subselect_single_select_engine::exec()
{
char const *save_where= thd->where;
THD_WHERE save_where= thd->where;
SELECT_LEX *save_select= thd->lex->current_select;
thd->lex->current_select= select_lex;
DBUG_ENTER("subselect_single_select_engine::exec");
@ -4137,7 +4137,7 @@ int subselect_single_select_engine::exec()
int subselect_union_engine::exec()
{
char const *save_where= thd->where;
THD_WHERE save_where= thd->where;
int res= unit->exec();
thd->where= save_where;
return res;

View File

@ -1146,7 +1146,7 @@ bool push_table_function_arg_context(LEX *lex, MEM_ROOT *alloc)
bool Table_function_json_table::setup(THD *thd, TABLE_LIST *sql_table,
SELECT_LEX *s_lex)
{
thd->where= "JSON_TABLE argument";
thd->where= THD_WHERE::JSON_TABLE_ARGUMENT;
if (!m_context_setup_done)
{

View File

@ -638,8 +638,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
{
SELECT_LEX *current= thd->lex->current_select;
thd->lex->current_select= current->return_after_parsing();
char const *save_where= thd->where;
thd->where= "IN/ALL/ANY subquery";
THD_WHERE save_where= thd->where;
thd->where= THD_WHERE::IN_ALL_ANY_SUBQUERY;
Item **left= in_subs->left_exp_ptr();
bool failure= (*left)->fix_fields_if_needed(thd, left);

View File

@ -1824,7 +1824,7 @@ bool partition_info::add_column_list_value(THD *thd, Item *item)
part_column_list_val *col_val;
Name_resolution_context *context= &thd->lex->current_select->context;
TABLE_LIST *save_list= context->table_list;
const char *save_where= thd->where;
THD_WHERE save_where= thd->where;
DBUG_ENTER("partition_info::add_column_list_value");
if (part_type == LIST_PARTITION &&
@ -1838,9 +1838,9 @@ bool partition_info::add_column_list_value(THD *thd, Item *item)
context->table_list= 0;
if (column_list)
thd->where= "field list";
thd->where= THD_WHERE::FIELD_LIST;
else
thd->where= "partition function";
thd->where= THD_WHERE::PARTITION_FUNCTION;
if (item->walk(&Item::check_partition_func_processor, 0, NULL))
{

View File

@ -5957,7 +5957,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, si
{
if (nj_col)
{
my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd_where(thd));
DBUG_RETURN(NULL);
}
nj_col= curr_nj_col;
@ -6604,7 +6604,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
item->cached_field_index= NO_CACHED_FIELD_INDEX;
}
DBUG_ASSERT(thd->where);
DBUG_ASSERT(thd->where != THD_WHERE::NOWHERE);
/*
If we found a fully qualified field we return it directly as it can't
have duplicates.
@ -6617,7 +6617,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
if (report_error == REPORT_ALL_ERRORS ||
report_error == IGNORE_EXCEPT_NON_UNIQUE)
my_error(ER_NON_UNIQ_ERROR, MYF(0),
table_name ? item->full_name() : name, thd->where);
table_name ? item->full_name() : name, thd_where(thd));
return (Field*) 0;
}
found= cur_field;
@ -6645,13 +6645,13 @@ find_field_in_tables(THD *thd, Item_ident *item,
strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
table_name=buff;
}
my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where);
my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd_where(thd));
}
else
{
if (report_error == REPORT_ALL_ERRORS ||
report_error == REPORT_EXCEPT_NON_UNIQUE)
my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where);
my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd_where(thd));
else
found= not_found_field;
}
@ -6784,7 +6784,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
*/
if (report_error != IGNORE_ERRORS)
my_error(ER_NON_UNIQ_ERROR, MYF(0),
find->full_name(), current_thd->where);
find->full_name(), thd_where(current_thd));
return (Item**) 0;
}
found_unaliased= li.ref();
@ -6815,7 +6815,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
continue; // Same field twice
if (report_error != IGNORE_ERRORS)
my_error(ER_NON_UNIQ_ERROR, MYF(0),
find->full_name(), current_thd->where);
find->full_name(), thd_where(current_thd));
return (Item**) 0;
}
found= li.ref();
@ -6870,7 +6870,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
{
if (report_error != IGNORE_ERRORS)
my_error(ER_NON_UNIQ_ERROR, MYF(0),
find->full_name(), current_thd->where);
find->full_name(), thd_where(current_thd));
return (Item **) 0;
}
if (found_unaliased)
@ -6887,7 +6887,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
{
if (report_error == REPORT_ALL_ERRORS)
my_error(ER_BAD_FIELD_ERROR, MYF(0),
find->full_name(), current_thd->where);
find->full_name(), thd_where(current_thd));
return (Item **) 0;
}
else
@ -7093,7 +7093,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common));
if (cur_nj_col_2->is_common || found)
{
my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1->str, thd->where);
my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1->str, thd_where(thd));
goto err;
}
if ((!using_fields && !field_2_invisible) || is_using_column_1)
@ -7307,7 +7307,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
if (!(common_field= it++))
{
my_error(ER_BAD_FIELD_ERROR, MYF(0), using_field_name_ptr,
current_thd->where);
thd_where(current_thd));
goto err;
}
if (!my_strcasecmp(system_charset_info,
@ -7561,7 +7561,7 @@ static bool setup_natural_join_row_types(THD *thd,
Name_resolution_context *context)
{
DBUG_ENTER("setup_natural_join_row_types");
thd->where= "from clause";
thd->where= THD_WHERE::FROM_CLAUSE;
if (from_clause->elements == 0)
DBUG_RETURN(false); /* We come here in the case of UNIONs. */
@ -7732,7 +7732,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
thd->lex->current_select->nest_level);
if (allow_sum_func)
thd->lex->allow_sum_func.set_bit(thd->lex->current_select->nest_level);
thd->where= THD::DEFAULT_WHERE;
thd->where= THD_WHERE::DEFAULT_WHERE;
save_is_item_list_lookup= thd->lex->current_select->is_item_list_lookup;
thd->lex->current_select->is_item_list_lookup= 0;
@ -8491,7 +8491,7 @@ bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update)
embedded= embedding;
if (embedded->on_expr)
{
thd->where="on clause";
thd->where= THD_WHERE::ON_CLAUSE;
embedded->on_expr->mark_as_condition_AND_part(embedded);
if (embedded->on_expr->fix_fields_if_needed_for_bool(thd,
&embedded->on_expr))
@ -8592,7 +8592,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
if (*conds)
{
thd->where="where clause";
thd->where= THD_WHERE::WHERE_CLAUSE;
DBUG_EXECUTE("where",
print_where(*conds,
"WHERE in setup_conds",

View File

@ -83,8 +83,6 @@
char internal_table_name[2]= "*";
char empty_c_string[1]= {0}; /* used for not defined db */
const char * const THD::DEFAULT_WHERE= "field list";
/****************************************************************************
** User variables
****************************************************************************/
@ -629,6 +627,64 @@ extern "C" void thd_kill_timeout(THD* thd)
thd->awake(KILL_TIMEOUT);
}
const char *thd_where(THD *thd)
{
switch(thd->where) {
case THD_WHERE::CHECKING_TRANSFORMED_SUBQUERY:
return "checking transformed subquery";
break;
case THD_WHERE::IN_ALL_ANY_SUBQUERY:
return "IN/ALL/ANY subquery";
break;
case THD_WHERE::JSON_TABLE_ARGUMENT:
return "JSON_TABLE argument";
break;
case THD_WHERE::DEFAULT_WHERE: // same as FIELD_LIST
case THD_WHERE::FIELD_LIST:
return "field list";
break;
case THD_WHERE::PARTITION_FUNCTION:
return "partition function";
break;
case THD_WHERE::FROM_CLAUSE:
return "from clause";
break;
case THD_WHERE::ON_CLAUSE:
return "on clause";
break;
case THD_WHERE::WHERE_CLAUSE:
return "where clause";
break;
case THD_WHERE::CONVERT_CHARSET_CONST:
return "convert character set partition constant";
break;
case THD_WHERE::FOR_SYSTEM_TIME:
return "FOR SYSTEM_TIME";
break;
case THD_WHERE::ORDER_CLAUSE:
return "order clause";
break;
case THD_WHERE::HAVING_CLAUSE:
return "having clause";
break;
case THD_WHERE::GROUP_STATEMENT:
return "group statement";
break;
case THD_WHERE::PROCEDURE_LIST:
return "procedure list";
break;
case THD_WHERE::CHECK_OPTION:
return "check option";
break;
case THD_WHERE::USE_WHERE_STRING:
return thd->where_str;
default:
break; // "fall-through" to default return below
};
DBUG_ASSERT(false);
return "UNKNOWN";
}
THD::THD(my_thread_id id, bool is_wsrep_applier)
:Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
/* statement id */ 0),
@ -838,7 +894,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
/* Variables with default values */
proc_info="login";
where= THD::DEFAULT_WHERE;
where= THD_WHERE::DEFAULT_WHERE;
slave_net = 0;
m_command=COM_CONNECT;
*scramble= '\0';
@ -2328,7 +2384,7 @@ void THD::cleanup_after_query()
/* Free Items that were created during this execution */
free_items();
/* Reset where. */
where= THD::DEFAULT_WHERE;
where= THD_WHERE::DEFAULT_WHERE;
/* reset table map for multi-table update */
table_map_for_update= 0;
m_binlog_invoker= INVOKER_NONE;

View File

@ -2668,6 +2668,33 @@ struct thd_async_state
};
enum class THD_WHERE
{
NOWHERE = 0,
CHECKING_TRANSFORMED_SUBQUERY,
IN_ALL_ANY_SUBQUERY,
JSON_TABLE_ARGUMENT,
FIELD_LIST,
PARTITION_FUNCTION,
FROM_CLAUSE,
DEFAULT_WHERE,
ON_CLAUSE,
WHERE_CLAUSE,
CONVERT_CHARSET_CONST,
FOR_SYSTEM_TIME,
ORDER_CLAUSE,
HAVING_CLAUSE,
GROUP_STATEMENT,
PROCEDURE_LIST,
CHECK_OPTION,
USE_WHERE_STRING, // ugh, a compromise for vcol...
};
class THD;
const char *thd_where(THD *thd);
/**
@class THD
For each client connection we create a separate thread with THD serving as
@ -2720,13 +2747,6 @@ public:
MDL_request *backup_commit_lock;
void reset_for_next_command(bool do_clear_errors= 1);
/*
Constant for THD::where initialization in the beginning of every query.
It's needed because we do not save/restore THD::where normally during
primary (non subselect) query execution.
*/
static const char * const DEFAULT_WHERE;
#ifdef EMBEDDED_LIBRARY
struct st_mysql *mysql;
@ -2882,12 +2902,15 @@ public:
const char *get_proc_info() const
{ return proc_info; }
// Used by thd_where() when where==USE_WHERE_STRING
const char *where_str;
/*
Used in error messages to tell user in what part of MySQL we found an
error. E. g. when where= "having clause", if fix_fields() fails, user
will know that the error was in having clause.
*/
const char *where;
THD_WHERE where;
/* Needed by MariaDB semi sync replication */
Trans_binlog_info *semisync_info;

View File

@ -431,7 +431,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
derived->on_expr= expr;
derived->prep_on_expr= expr->copy_andor_structure(thd);
}
thd->where= "on clause";
thd->where= THD_WHERE::ON_CLAUSE;
if (derived->on_expr &&
derived->on_expr->fix_fields_if_needed_for_bool(thd, &derived->on_expr))
{

View File

@ -8147,7 +8147,7 @@ bool LEX::check_expr_allows_fields_or_error(THD *thd, const char *name) const
{
if (select_stack_top > 0)
return false; // OK, fields are allowed
my_error(ER_BAD_FIELD_ERROR, MYF(0), name, thd->where);
my_error(ER_BAD_FIELD_ERROR, MYF(0), name, thd_where(thd));
return true; // Error, fields are not allowed
}
@ -8170,7 +8170,7 @@ Item *LEX::create_item_ident_nospvar(THD *thd,
if (unlikely(current_select->no_table_names_allowed))
{
my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), a->str, thd->where);
my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), a->str, thd_where(thd));
return NULL;
}
@ -8385,7 +8385,7 @@ Item *LEX::create_item_ident(THD *thd,
if (current_select->no_table_names_allowed)
{
my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), b->str, thd->where);
my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), b->str, thd_where(thd));
return NULL;
}

View File

@ -142,11 +142,11 @@ Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs)
THD *thd= current_thd;
Name_resolution_context *context= &thd->lex->current_select->context;
TABLE_LIST *save_list= context->table_list;
const char *save_where= thd->where;
THD_WHERE save_where= thd->where;
item= item->safe_charset_converter(thd, cs);
context->table_list= NULL;
thd->where= "convert character set partition constant";
thd->where= THD_WHERE::CONVERT_CHARSET_CONST;
if (item && item->fix_fields_if_needed(thd, (Item**)NULL))
item= NULL;
thd->where= save_where;
@ -841,7 +841,7 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
func_expr->walk(&Item::change_context_processor, 0,
&lex.first_select_lex()->context);
thd->where= "partition function";
thd->where= THD_WHERE::PARTITION_FUNCTION;
/*
In execution we must avoid the use of thd->change_item_tree since
we might release memory before statement is completed. We do this

View File

@ -1245,7 +1245,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
if (vers_conditions.is_set() && vers_conditions.type != SYSTEM_TIME_HISTORY)
{
thd->where= "FOR SYSTEM_TIME";
thd->where= THD_WHERE::FOR_SYSTEM_TIME;
/* TODO: do resolve fix_length_and_dec(), fix_fields(). This requires
storing vers_conditions as Item and make some magic related to
vers_system_time_t/VERS_TRX_ID at stage of fix_fields()
@ -1530,7 +1530,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
{
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
thd->lex->allow_sum_func.set_bit(select_lex->nest_level);
thd->where= "order clause";
thd->where= THD_WHERE::ORDER_CLAUSE;
for (ORDER *order= select_lex->order_list.first; order; order= order->next)
{
/* Don't add the order items to all fields. Just resolve them to ensure
@ -1546,7 +1546,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
if (having)
{
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
thd->where="having clause";
thd->where= THD_WHERE::HAVING_CLAUSE;
thd->lex->allow_sum_func.set_bit(select_lex_arg->nest_level);
select_lex->having_fix_field= 1;
/*
@ -25986,7 +25986,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array,
if (!count || count > fields.elements)
{
my_error(ER_BAD_FIELD_ERROR, MYF(0),
order_item->full_name(), thd->where);
order_item->full_name(), thd_where(thd));
return TRUE;
}
thd->change_item_tree((Item **)&order->item, (Item *)&ref_pointer_array[count - 1]);
@ -26065,7 +26065,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array,
ER_NON_UNIQ_ERROR,
ER_THD(thd, ER_NON_UNIQ_ERROR),
((Item_ident*) order_item)->field_name.str,
thd->where);
thd_where(thd));
}
}
else if (from_window_spec)
@ -26135,7 +26135,7 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
SELECT_LEX *select = thd->lex->current_select;
enum_parsing_place context_analysis_place=
thd->lex->current_select->context_analysis_place;
thd->where="order clause";
thd->where= THD_WHERE::ORDER_CLAUSE;
const bool for_union= select->master_unit()->is_unit_op() &&
select == select->master_unit()->fake_select_lex;
for (uint number = 1; order; order=order->next, number++)
@ -26214,7 +26214,7 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
uint org_fields=all_fields.elements;
thd->where="group statement";
thd->where= THD_WHERE::GROUP_STATEMENT;
for (ord= order; ord; ord= ord->next)
{
if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields,
@ -26332,7 +26332,7 @@ setup_new_fields(THD *thd, List<Item> &fields,
new_field->item=item; /* Change to shared Item */
else
{
thd->where="procedure list";
thd->where= THD_WHERE::PROCEDURE_LIST;
if ((*new_field->item)->fix_fields(thd, new_field->item))
DBUG_RETURN(1); /* purecov: inspected */
all_fields.push_front(*new_field->item, thd->mem_root);

View File

@ -312,7 +312,7 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl,
(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)
*/
thd->where="order clause";
thd->where= THD_WHERE::ORDER_CLAUSE;
ORDER *order= sl->order_list.first;
for (; order; order=order->next)
{
@ -327,7 +327,7 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl,
if (!count || count > first_elem->elements)
{
my_error(ER_BAD_FIELD_ERROR, MYF(0),
order_item->full_name(), thd->where);
order_item->full_name(), thd_where(thd));
DBUG_RETURN(true);
}
order->in_field_list= 1;

View File

@ -12520,7 +12520,7 @@ opt_order_clause:
order_clause:
ORDER_SYM BY
{
thd->where= "ORDER clause";
thd->where= THD_WHERE::ORDER_CLAUSE;
}
order_list
{

View File

@ -1212,7 +1212,8 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
expr_str.length(parse_vcol_keyword.length);
expr_str.append((char*)pos, expr_length);
thd->where= vcol_type_name(static_cast<enum_vcol_info_type>(type));
thd->where= THD_WHERE::USE_WHERE_STRING;
thd->where_str= vcol_type_name(static_cast<enum_vcol_info_type>(type));
switch (type) {
case VCOL_GENERATED_VIRTUAL:
@ -6282,8 +6283,8 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
if (check_option)
{
const char *save_where= thd->where;
thd->where= "check option";
THD_WHERE save_where= thd->where;
thd->where= THD_WHERE::CHECK_OPTION;
if (check_option->fix_fields_if_needed_for_bool(thd, &check_option))
DBUG_RETURN(TRUE);
thd->where= save_where;