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:
parent
a0a7b1c128
commit
02e38e2ece
@ -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
|
||||
|
87
mysql-test/main/name_const_replacement.result
Normal file
87
mysql-test/main/name_const_replacement.result
Normal 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;
|
38
mysql-test/main/name_const_replacement.test
Normal file
38
mysql-test/main/name_const_replacement.test
Normal 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;
|
@ -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;
|
||||
*
|
||||
|
@ -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
|
||||
|
44
sql/item.cc
44
sql/item.cc
@ -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(). */
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -12520,7 +12520,7 @@ opt_order_clause:
|
||||
order_clause:
|
||||
ORDER_SYM BY
|
||||
{
|
||||
thd->where= "ORDER clause";
|
||||
thd->where= THD_WHERE::ORDER_CLAUSE;
|
||||
}
|
||||
order_list
|
||||
{
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user