1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

MDEV-25969: Condition pushdown into derived table doesn't work if select list uses SP

Consider a query of the form:

  select ... from (select item2 as COL1) as T where COL1=123

Condition pushdown into derived table will try to push "COL1=123" condition
down into table T.
The process of pushdown involves "substituting" the item, that is,
replacing Item_field("T.COL1") with its "producing item" item2.
In order to use item2, one needs to clone it (call Item::build_clone).

If the item is not cloneable (e.g. Item_func_sp is not), the pushdown
process will fail and nothing at all will be pushed.

Fixed by introducing transform_condition_or_part() which will try to apply
the transformation for as many parts of condition as possible. The parts of
condition that couldn't be transformed are dropped.
This commit is contained in:
Sergei Petrunia
2021-06-29 16:31:28 +03:00
parent 768c51880a
commit eb20c91b55
3 changed files with 289 additions and 6 deletions

View File

@ -1192,6 +1192,68 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived)
}
/*
@brief
Given condition cond and transformer+argument, try transforming as many
conjuncts as possible.
@detail
The motivation of this function is to convert the condition that's being
pushed into a WHERE clause with derived_field_transformer_for_where or
with derived_grouping_field_transformer_for_where.
The transformer may fail for some sub-condition, in this case we want to
convert the most restrictive part of the condition that can be pushed.
This function only does it for top-level AND: conjuncts that could not be
converted are dropped.
@return
Converted condition, or NULL if nothing could be converted
*/
static
Item *transform_condition_or_part(THD *thd,
Item *cond,
Item_transformer transformer,
uchar *arg)
{
if (cond->type() != Item::COND_ITEM ||
((Item_cond*) cond)->functype() != Item_func::COND_AND_FUNC)
{
Item *new_item= cond->transform(thd, transformer, arg);
// Indicate that the condition is not pushable
if (!new_item)
cond->clear_extraction_flag();
return new_item;
}
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
Item *item;
while ((item=li++))
{
Item *new_item= item->transform(thd, transformer, arg);
if (!new_item)
{
// Indicate that the condition is not pushable
item->clear_extraction_flag();
li.remove();
}
else
li.replace(new_item);
}
switch (((Item_cond*) cond)->argument_list()->elements)
{
case 0:
return NULL;
case 1:
return ((Item_cond*) cond)->argument_list()->head();
default:
return cond;
}
}
/**
@brief
Extract the condition depended on derived table/view and pushed it there
@ -1287,9 +1349,11 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
if (!sl->join->group_list && !sl->with_sum_func)
{
/* extracted_cond_copy is pushed into where of sl */
extracted_cond_copy= extracted_cond_copy->transform(thd,
&Item::derived_field_transformer_for_where,
(uchar*) sl);
extracted_cond_copy=
transform_condition_or_part(thd,
extracted_cond_copy,
&Item::derived_field_transformer_for_where,
(uchar*)sl);
if (extracted_cond_copy)
{
extracted_cond_copy->walk(
@ -1316,9 +1380,12 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
pushed into the where clause of sl to make them usable in the new context
*/
if (cond_over_grouping_fields)
cond_over_grouping_fields= cond_over_grouping_fields->transform(thd,
&Item::derived_grouping_field_transformer_for_where,
(uchar*) sl);
{
cond_over_grouping_fields=
transform_condition_or_part(thd, cond_over_grouping_fields,
&Item::derived_grouping_field_transformer_for_where,
(uchar*) sl);
}
if (cond_over_grouping_fields)
{