Skip to content

Commit

Permalink
MDEV-33971 NAME_CONST in WHERE clause replaced by inner item
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
DaveGosselin-MariaDB committed Apr 30, 2024
1 parent 814dc46 commit 8d48689
Show file tree
Hide file tree
Showing 18 changed files with 159 additions and 75 deletions.
4 changes: 2 additions & 2 deletions mysql-test/main/fulltext_order_by.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/main/union.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
*
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/suite/innodb_fts/r/fulltext_order_by.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
19 changes: 12 additions & 7 deletions sql/item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2176,6 +2176,11 @@ Item::Type Item_name_const::type() const

bool Item_name_const::fix_fields(THD *thd, Item **ref)
{
if (thd->where == THD_WHERE::WHERE_CLAUSE) {
value_item->fix_fields_if_needed(thd, &value_item);
thd->change_item_tree(ref, value_item);
return FALSE;
}
if (value_item->fix_fields_if_needed(thd, &value_item) ||
name_item->fix_fields_if_needed(thd, &name_item) ||
!value_item->const_item() ||
Expand Down Expand Up @@ -5528,7 +5533,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;
}
}
Expand Down Expand Up @@ -5613,7 +5618,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));

}
}
Expand Down Expand Up @@ -5947,7 +5952,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
{
Expand Down Expand Up @@ -6174,7 +6179,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);
}

Expand Down Expand Up @@ -6219,7 +6224,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)
Expand Down Expand Up @@ -8163,7 +8168,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;
}

Expand Down Expand Up @@ -8314,7 +8319,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(). */
Expand Down
16 changes: 8 additions & 8 deletions sql/item_subselect.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion sql/json_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
4 changes: 2 additions & 2 deletions sql/opt_subselect.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions sql/partition_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand All @@ -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))
{
Expand Down
30 changes: 15 additions & 15 deletions sql/sql_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5955,7 +5955,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;
Expand Down Expand Up @@ -6602,7 +6602,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.
Expand All @@ -6615,7 +6615,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;
Expand Down Expand Up @@ -6643,13 +6643,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;
}
Expand Down Expand Up @@ -6782,7 +6782,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();
Expand Down Expand Up @@ -6813,7 +6813,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();
Expand Down Expand Up @@ -6868,7 +6868,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)
Expand All @@ -6885,7 +6885,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
Expand Down Expand Up @@ -7091,7 +7091,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)
Expand Down Expand Up @@ -7305,7 +7305,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,
Expand Down Expand Up @@ -7559,7 +7559,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. */

Expand Down Expand Up @@ -7730,7 +7730,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;

Expand Down Expand Up @@ -8489,7 +8489,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))
Expand Down Expand Up @@ -8590,7 +8590,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",
Expand Down

0 comments on commit 8d48689

Please sign in to comment.