Fixed the bug mdev-12845.

This patch fills in a serious flaw in the
code that supports condition pushdown into
materialized views / derived tables.

If a predicate happened to contain a reference
to a mergeable view / derived table and it does
not depended directly on the target materialized
view / derived table then the predicate was not
considered as a subject to pusdown to this view
/ derived table.
This commit is contained in:
Igor Babaev 2017-06-22 00:41:44 -07:00
parent a8131e71f9
commit 9f3622191d
13 changed files with 571 additions and 150 deletions

View File

@ -554,7 +554,7 @@ EXPLAIN SELECT * FROM (SELECT * FROM t1) AS table1,
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
1 PRIMARY <derived3> ref key0 key0 5 const 0
3 DERIVED t2 ALL NULL NULL NULL NULL 2 Using temporary
3 DERIVED t2 ALL NULL NULL NULL NULL 2 Using where; Using temporary
Warnings:
Note 1249 Select 4 was reduced during optimization
DROP TABLE t1, t2;

View File

@ -7234,6 +7234,7 @@ EXPLAIN
"materialized": {
"query_block": {
"select_id": 5,
"having_condition": "s > 2",
"filesort": {
"sort_key": "t4.d",
"temporary_table": {
@ -7605,6 +7606,7 @@ EXPLAIN
"materialized": {
"query_block": {
"select_id": 3,
"having_condition": "s < 50",
"filesort": {
"sort_key": "t3.a",
"temporary_table": {
@ -7755,9 +7757,14 @@ EXPLAIN
"select_id": 4,
"table": {
"table_name": "t",
"access_type": "ALL",
"access_type": "range",
"possible_keys": ["PRIMARY"],
"key": "PRIMARY",
"key_length": "4",
"used_key_parts": ["pk"],
"rows": 2,
"filtered": 100
"filtered": 100,
"index_condition": "t.pk > 2"
}
}
}
@ -8447,3 +8454,221 @@ WHERE row <> order_number;
row order_number
14 51
DROP TABLE sales_documents;
#
# MDEV-12845: pushdown from merged derived using equalities
#
create table t1 (a int);
insert into t1 values
(4), (8), (5), (3), (10), (2), (7);
create table t2 (b int, c int);
insert into t2 values
(2,1), (5,2), (2,2), (4,1), (4,3),
(5,3), (2,4), (4,6), (2,1);
create view v1 as
select b, sum(c) as s from t2 group by b;
create view v2 as
select distinct b, c from t2;
create view v3 as
select b, max(c) as m from t2 group by b;
select b
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
where b > 2;
b
4
5
explain format=json select b
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
where b > 2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 7,
"filtered": 100,
"attached_condition": "t1.a > 2 and t1.a is not null"
},
"table": {
"table_name": "<derived3>",
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
"key_length": "5",
"used_key_parts": ["b"],
"ref": ["test.t1.a"],
"rows": 2,
"filtered": 100,
"materialized": {
"query_block": {
"select_id": 3,
"filesort": {
"sort_key": "t2.b",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 9,
"filtered": 100,
"attached_condition": "t2.b > 2"
}
}
}
}
}
}
}
}
select a
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
where a > 2;
a
4
5
explain format=json select a
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
where a > 2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 7,
"filtered": 100,
"attached_condition": "t1.a > 2 and t1.a is not null"
},
"table": {
"table_name": "<derived3>",
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
"key_length": "5",
"used_key_parts": ["b"],
"ref": ["test.t1.a"],
"rows": 2,
"filtered": 100,
"materialized": {
"query_block": {
"select_id": 3,
"filesort": {
"sort_key": "t2.b",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 9,
"filtered": 100,
"attached_condition": "t2.b > 2"
}
}
}
}
}
}
}
}
select a
from ( select t1.a, v2.b, v2.c from t1, v2 where t1.a = v2.b ) as t
where a > 2;
a
4
4
4
5
5
explain format=json select a
from ( select t1.a, v2.b, v2.c from t1, v2 where t1.a = v2.b ) as t
where a > 2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 7,
"filtered": 100,
"attached_condition": "t1.a > 2 and t1.a is not null"
},
"table": {
"table_name": "<derived3>",
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
"key_length": "5",
"used_key_parts": ["b"],
"ref": ["test.t1.a"],
"rows": 2,
"filtered": 100,
"materialized": {
"query_block": {
"select_id": 3,
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 9,
"filtered": 100,
"attached_condition": "t2.b > 2"
}
}
}
}
}
}
}
select a
from ( select t1.a, v3.b, v3.m from t1, v3 where t1.a = v3.m ) as t
where a > 2;
a
4
3
explain format=json select a
from ( select t1.a, v3.b, v3.m from t1, v3 where t1.a = v3.m ) as t
where a > 2;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 7,
"filtered": 100,
"attached_condition": "t1.a > 2 and t1.a is not null"
},
"table": {
"table_name": "<derived3>",
"access_type": "ref",
"possible_keys": ["key0"],
"key": "key0",
"key_length": "5",
"used_key_parts": ["m"],
"ref": ["test.t1.a"],
"rows": 2,
"filtered": 100,
"materialized": {
"query_block": {
"select_id": 3,
"having_condition": "m > 2",
"filesort": {
"sort_key": "t2.b",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 9,
"filtered": 100
}
}
}
}
}
}
}
}
drop view v1,v2,v3;
drop table t1,t2;

View File

@ -900,7 +900,7 @@ EXPLAIN
"access_type": "ALL",
"rows": 11,
"filtered": 100,
"attached_condition": "t1.f1 in (2,3)"
"attached_condition": "t1.f1 < 7 and t1.f1 in (2,3)"
}
}
}
@ -1107,7 +1107,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
1 PRIMARY t2 ref a a 4 const 1 Using index
1 PRIMARY <derived2> ref key0 key0 8 const,const 1
2 DERIVED t3 ALL NULL NULL NULL NULL 12 Using temporary; Using filesort
2 DERIVED t3 ALL NULL NULL NULL NULL 12 Using where; Using temporary; Using filesort
SELECT * FROM t1, t2, v1 WHERE t2.a=t1.a AND t2.a=v1.a AND t2.a=v1.b;
a a a b
c c c c

View File

@ -1452,3 +1452,60 @@ SELECT * FROM
WHERE row <> order_number;
DROP TABLE sales_documents;
--echo #
--echo # MDEV-12845: pushdown from merged derived using equalities
--echo #
create table t1 (a int);
insert into t1 values
(4), (8), (5), (3), (10), (2), (7);
create table t2 (b int, c int);
insert into t2 values
(2,1), (5,2), (2,2), (4,1), (4,3),
(5,3), (2,4), (4,6), (2,1);
create view v1 as
select b, sum(c) as s from t2 group by b;
create view v2 as
select distinct b, c from t2;
create view v3 as
select b, max(c) as m from t2 group by b;
let $q1=
select b
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
where b > 2;
eval $q1;
eval explain format=json $q1;
let $q2=
select a
from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
where a > 2;
eval $q2;
eval explain format=json $q2;
let $q3=
select a
from ( select t1.a, v2.b, v2.c from t1, v2 where t1.a = v2.b ) as t
where a > 2;
eval $q3;
eval explain format=json $q3;
let $q4=
select a
from ( select t1.a, v3.b, v3.m from t1, v3 where t1.a = v3.m ) as t
where a > 2;
eval $q4;
eval explain format=json $q4;
drop view v1,v2,v3;
drop table t1,t2;

View File

@ -7120,121 +7120,182 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
}
Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg)
static
Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel)
{
st_select_lex *sl= (st_select_lex *)arg;
table_map map= sl->master_unit()->derived->table->map;
if (!((Item_field*)this)->item_equal)
{
if (used_tables() == map)
{
Item_ref *rf=
new (thd->mem_root) Item_ref(thd, &sl->context,
NullS, NullS,
((Item_field*) this)->field_name);
if (!rf)
return 0;
return rf;
}
}
DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
(item->type() == Item::REF_ITEM &&
((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
Item_field *field_item= NULL;
table_map map= sel->master_unit()->derived->table->map;
Item_equal *item_equal= item->get_item_equal();
if (!item_equal)
field_item= (Item_field *)(item->real_item());
else
{
Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
Item_equal_fields_iterator li(*cond);
Item *item;
while ((item=li++))
Item_equal_fields_iterator li(*item_equal);
Item *equal_item;
while ((equal_item= li++))
{
if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
if (equal_item->used_tables() == map)
{
Item_ref *rf=
new (thd->mem_root) Item_ref(thd, &sl->context,
NullS, NullS,
((Item_field*) (item->real_item()))->field_name);
if (!rf)
return 0;
return rf;
field_item= (Item_field *)(equal_item->real_item());
break;
}
}
}
return this;
if (field_item)
{
Item_ref *ref= new (thd->mem_root) Item_ref(thd, &sel->context,
NullS, NullS,
field_item->field_name);
return ref;
}
DBUG_ASSERT(0);
return NULL;
}
Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg)
{
st_select_lex *sel= (st_select_lex *)arg;
table_map tab_map= sel->master_unit()->derived->table->map;
if (item_equal && !(item_equal->used_tables() & tab_map))
return this;
if (!item_equal && used_tables() != tab_map)
return this;
return get_field_item_for_having(thd, this, sel);
}
Item *Item_direct_view_ref::derived_field_transformer_for_having(THD *thd,
uchar *arg)
{
st_select_lex *sel= (st_select_lex *)arg;
table_map tab_map= sel->master_unit()->derived->table->map;
if (item_equal && !(item_equal->used_tables() & tab_map))
return this;
if (!item_equal && used_tables() != tab_map)
return this;
return get_field_item_for_having(thd, this, sel);
}
static
Item *find_producing_item(Item *item, st_select_lex *sel)
{
DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
(item->type() == Item::REF_ITEM &&
((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
Item *producing_item;
Item_field *field_item= NULL;
Item_equal *item_equal= item->get_item_equal();
table_map tab_map= sel->master_unit()->derived->table->map;
if (item->used_tables() == tab_map)
field_item= (Item_field *) (item->real_item());
if (!field_item && item_equal)
{
Item_equal_fields_iterator it(*item_equal);
Item *equal_item;
while ((equal_item= it++))
{
if (equal_item->used_tables() == tab_map)
{
field_item= (Item_field *) (equal_item->real_item());
break;
}
}
}
List_iterator_fast<Item> li(sel->item_list);
if (field_item)
{
uint field_no= field_item->field->field_index;
for (uint i= 0; i <= field_no; i++)
producing_item= li++;
return producing_item;
}
return NULL;
}
Item *Item_field::derived_field_transformer_for_where(THD *thd, uchar *arg)
{
Item *producing_item;
st_select_lex *sl= (st_select_lex *)arg;
List_iterator_fast<Item> li(sl->item_list);
table_map map= sl->master_unit()->derived->table->map;
if (used_tables() == map)
{
uint field_no= ((Item_field*) this)->field->field_index;
for (uint i= 0; i <= field_no; i++)
producing_item= li++;
st_select_lex *sel= (st_select_lex *)arg;
Item *producing_item= find_producing_item(this, sel);
if (producing_item)
return producing_item->build_clone(thd, thd->mem_root);
}
else if (((Item_field*)this)->item_equal)
return this;
}
Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd,
uchar *arg)
{
if (item_equal)
{
Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
Item_equal_fields_iterator it(*cond);
Item *item;
while ((item=it++))
{
if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
{
Item_field *field_item= (Item_field *) (item->real_item());
li.rewind();
uint field_no= field_item->field->field_index;
for (uint i= 0; i <= field_no; i++)
producing_item= li++;
return producing_item->build_clone(thd, thd->mem_root);
}
}
st_select_lex *sel= (st_select_lex *)arg;
Item *producing_item= find_producing_item(this, sel);
DBUG_ASSERT (producing_item != NULL);
return producing_item->build_clone(thd, thd->mem_root);
}
return this;
}
static
Grouping_tmp_field *find_matching_grouping_field(Item *item,
st_select_lex *sel)
{
DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
(item->type() == Item::REF_ITEM &&
((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
List_iterator<Grouping_tmp_field> li(sel->grouping_tmp_fields);
Grouping_tmp_field *gr_field;
Item_field *field_item= (Item_field *) (item->real_item());
while ((gr_field= li++))
{
if (field_item->field == gr_field->tmp_field)
return gr_field;
}
Item_equal *item_equal= item->get_item_equal();
if (item_equal)
{
Item_equal_fields_iterator it(*item_equal);
Item *equal_item;
while ((equal_item= it++))
{
field_item= (Item_field *) (equal_item->real_item());
li.rewind();
while ((gr_field= li++))
{
if (field_item->field == gr_field->tmp_field)
return gr_field;
}
}
}
return NULL;
}
Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd,
uchar *arg)
{
st_select_lex *sl= (st_select_lex *)arg;
List_iterator<Grouping_tmp_field> li(sl->grouping_tmp_fields);
Grouping_tmp_field *field;
table_map map= sl->master_unit()->derived->table->map;
if (used_tables() == map)
{
while ((field=li++))
{
if (((Item_field*) this)->field == field->tmp_field)
return field->producing_item->build_clone(thd, thd->mem_root);
}
}
else if (((Item_field*)this)->item_equal)
{
Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
Item_equal_fields_iterator it(*cond);
Item *item;
while ((item=it++))
{
if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
{
Item_field *field_item= (Item_field *) (item->real_item());
li.rewind();
while ((field=li++))
{
if (field_item->field == field->tmp_field)
{
return field->producing_item->build_clone(thd, thd->mem_root);
}
}
}
}
}
st_select_lex *sel= (st_select_lex *)arg;
Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel);
if (gr_field)
return gr_field->producing_item->build_clone(thd, thd->mem_root);
return this;
}
Item *
Item_direct_view_ref::derived_grouping_field_transformer_for_where(THD *thd,
uchar *arg)
{
if (!item_equal)
return this;
st_select_lex *sel= (st_select_lex *)arg;
Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel);
return gr_field->producing_item->build_clone(thd, thd->mem_root);
}
void Item_field::print(String *str, enum_query_type query_type)
{
if (field && field->table->const_table &&
@ -8702,6 +8763,32 @@ Item *Item_direct_view_ref::replace_equal_field(THD *thd, uchar *arg)
}
bool Item_direct_view_ref::excl_dep_on_table(table_map tab_map)
{
table_map used= used_tables();
if (used & OUTER_REF_TABLE_BIT)
return false;
if (!(used & ~tab_map))
return true;
if (item_equal)
{
DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
return item_equal->used_tables() & tab_map;
}
return (*ref)->excl_dep_on_table(tab_map);
}
bool Item_direct_view_ref::excl_dep_on_grouping_fields(st_select_lex *sel)
{
if (item_equal)
{
DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
return find_matching_grouping_field(this, sel) != NULL;
}
return (*ref)->excl_dep_on_grouping_fields(sel);
}
bool Item_default_value::eq(const Item *item, bool binary_cmp) const
{
return item->type() == DEFAULT_VALUE_ITEM &&
@ -10613,46 +10700,16 @@ const char *dbug_print_unit(SELECT_LEX_UNIT *un)
#endif /*DBUG_OFF*/
bool Item_field::exclusive_dependence_on_table_processor(void *map)
bool Item_field::excl_dep_on_table(table_map tab_map)
{
table_map tab_map= *((table_map *) map);
return !((used_tables() == tab_map ||
(item_equal && item_equal->used_tables() & tab_map)));
return used_tables() == tab_map ||
(item_equal && (item_equal->used_tables() & tab_map));
}
bool Item_field::exclusive_dependence_on_grouping_fields_processor(void *arg)
bool
Item_field::excl_dep_on_grouping_fields(st_select_lex *sel)
{
st_select_lex *sl= (st_select_lex *)arg;
List_iterator<Grouping_tmp_field> li(sl->grouping_tmp_fields);
Grouping_tmp_field *field;
table_map map= sl->master_unit()->derived->table->map;
if (used_tables() == map)
{
while ((field=li++))
{
if (((Item_field*) this)->field == field->tmp_field)
return false;
}
}
else if (((Item_field*)this)->item_equal)
{
Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
Item_equal_fields_iterator it(*cond);
Item *item;
while ((item=it++))
{
if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
{
li.rewind();
while ((field=li++))
{
if (((Item_field *)(item->real_item()))->field == field->tmp_field)
return false;
}
}
}
}
return true;
return find_matching_grouping_field(this, sel) != NULL;
}
void Item::register_in(THD *thd)

View File

@ -1580,8 +1580,20 @@ public:
virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; }
virtual bool exists2in_processor(void *arg) { return 0; }
virtual bool find_selective_predicates_list_processor(void *arg) { return 0; }
virtual bool exclusive_dependence_on_table_processor(void *arg) { return 0; }
virtual bool exclusive_dependence_on_grouping_fields_processor(void *arg) { return 0; }
/*
TRUE if the expression depends only on the table indicated by tab_map
or can be converted to such an exression using equalities.
Not to be used for AND/OR formulas.
*/
virtual bool excl_dep_on_table(table_map tab_map) { return false; }
/*
TRUE if the expression depends only on grouping fields of sel
or can be converted to such an exression using equalities.
Not to be used for AND/OR formulas.
*/
virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; }
virtual bool switch_to_nullable_fields_processor(void *arg) { return 0; }
virtual bool find_function_processor (void *arg) { return 0; }
/*
@ -2633,8 +2645,8 @@ public:
Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg);
virtual void print(String *str, enum_query_type query_type);
bool exclusive_dependence_on_table_processor(void *map);
bool exclusive_dependence_on_grouping_fields_processor(void *arg);
bool excl_dep_on_table(table_map tab_map);
bool excl_dep_on_grouping_fields(st_select_lex *sel);
bool cleanup_excluding_fields_processor(void *arg)
{ return field ? 0 : cleanup_processor(arg); }
bool cleanup_excluding_const_fields_processor(void *arg)
@ -3853,6 +3865,28 @@ protected:
}
bool transform_args(THD *thd, Item_transformer transformer, uchar *arg);
void propagate_equal_fields(THD *, const Item::Context &, COND_EQUAL *);
bool excl_dep_on_table(table_map tab_map)
{
for (uint i= 0; i < arg_count; i++)
{
if (args[i]->const_item())
continue;
if (!args[i]->excl_dep_on_table(tab_map))
return false;
}
return true;
}
bool excl_dep_on_grouping_fields(st_select_lex *sel)
{
for (uint i= 0; i < arg_count; i++)
{
if (args[i]->const_item())
continue;
if (!args[i]->excl_dep_on_grouping_fields(sel))
return false;
}
return true;
}
public:
Item_args(void)
:args(NULL), arg_count(0)
@ -4321,10 +4355,15 @@ public:
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_ref>(thd, mem_root, this); }
bool exclusive_dependence_on_table_processor(void *map)
{ return depended_from != NULL; }
bool exclusive_dependence_on_grouping_fields_processor(void *arg)
{ return depended_from != NULL; }
bool excl_dep_on_table(table_map tab_map)
{
table_map used= used_tables();
if (used & OUTER_REF_TABLE_BIT)
return false;
return (used == tab_map) || (*ref)->excl_dep_on_table(tab_map);
}
bool excl_dep_on_grouping_fields(st_select_lex *sel)
{ return (*ref)->excl_dep_on_grouping_fields(sel); }
bool cleanup_excluding_fields_processor(void *arg)
{
Item *item= real_item();
@ -4621,13 +4660,20 @@ public:
return (*ref)->walk(processor, walk_subquery, arg) ||
(this->*processor)(arg);
}
bool view_used_tables_processor(void *arg)
bool view_used_tables_processor(void *arg)
{
TABLE_LIST *view_arg= (TABLE_LIST *) arg;
if (view_arg == view)
view_arg->view_used_tables|= (*ref)->used_tables();
return 0;
}
bool excl_dep_on_table(table_map tab_map);
bool excl_dep_on_grouping_fields(st_select_lex *sel);
Item *derived_field_transformer_for_having(THD *thd, uchar *arg);
Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
Item *derived_grouping_field_transformer_for_where(THD *thd,
uchar *arg);
void save_val(Field *to)
{
if (check_null_ref())
@ -4709,6 +4755,8 @@ public:
item_equal= NULL;
Item_direct_ref::cleanup();
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_direct_view_ref>(thd, mem_root, this); }
};

View File

@ -2395,6 +2395,14 @@ public:
void set_context_field(Item_field *ctx_field) { context_field= ctx_field; }
void set_link_equal_fields(bool flag) { link_equal_fields= flag; }
Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
/*
This does not comply with the specification of the virtual method,
but Item_equal items are processed distinguishly anyway
*/
bool excl_dep_on_table(table_map tab_map)
{
return used_tables() & tab_map;
}
friend class Item_equal_fields_iterator;
bool count_sargable_conds(void *arg);
friend class Item_equal_iterator<List_iterator_fast,Item>;

View File

@ -316,6 +316,19 @@ public:
return this;
}
bool excl_dep_on_table(table_map tab_map)
{
if (used_tables() & OUTER_REF_TABLE_BIT)
return false;
return !(used_tables() & ~tab_map) ||
Item_args::excl_dep_on_table(tab_map);
}
bool excl_dep_on_grouping_fields(st_select_lex *sel)
{
return Item_args::excl_dep_on_grouping_fields(sel);
}
/*
We assume the result of any function that has a TIMESTAMP argument to be
timezone-dependent, since a TIMESTAMP value in both numeric and string

View File

@ -126,6 +126,16 @@ public:
return this;
}
bool excl_dep_on_table(table_map tab_map)
{
return Item_args::excl_dep_on_table(tab_map);
}
bool excl_dep_on_grouping_fields(st_select_lex *sel)
{
return Item_args::excl_dep_on_grouping_fields(sel);
}
bool check_vcol_func_processor(void *arg) {return FALSE; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_row>(thd, mem_root, this); }

View File

@ -1246,7 +1246,7 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
Item *cond_over_grouping_fields;
sl->collect_grouping_fields(thd);
sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy,
&Item::exclusive_dependence_on_grouping_fields_processor);
derived);
cond_over_grouping_fields=
sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true);
@ -1285,7 +1285,8 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
if (!extracted_cond_copy)
continue;
extracted_cond_copy->walk(&Item::cleanup_processor, 0, 0);
extracted_cond_copy->walk(&Item::cleanup_excluding_const_fields_processor,
0, 0);
sl->cond_pushed_into_having= extracted_cond_copy;
}
thd->lex->current_select= save_curr_select;

View File

@ -5006,8 +5006,9 @@ void st_select_lex::collect_grouping_fields(THD *thd)
from cond.
*/
void st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
Item_processor check_processor)
void
st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
TABLE_LIST *derived)
{
cond->clear_extraction_flag();
if (cond->type() == Item::COND_ITEM)
@ -5020,7 +5021,7 @@ void st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
Item *item;
while ((item=li++))
{
check_cond_extraction_for_grouping_fields(item, check_processor);
check_cond_extraction_for_grouping_fields(item, derived);
if (item->get_extraction_flag() != NO_EXTRACTION_FL)
{
count++;
@ -5041,10 +5042,12 @@ void st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
item->clear_extraction_flag();
}
}
else
cond->set_extraction_flag(cond->walk(check_processor,
0, (uchar *) this) ?
NO_EXTRACTION_FL : FULL_EXTRACTION_FL);
else
{
int fl= cond->excl_dep_on_grouping_fields(this) ?
FULL_EXTRACTION_FL : NO_EXTRACTION_FL;
cond->set_extraction_flag(fl);
}
}

View File

@ -1139,7 +1139,7 @@ public:
bool check_subqueries_with_recursive_references();
void collect_grouping_fields(THD *thd);
void check_cond_extraction_for_grouping_fields(Item *cond,
Item_processor processor);
TABLE_LIST *derived);
Item *build_cond_for_grouping_fields(THD *thd, Item *cond,
bool no_to_clones);

View File

@ -8128,8 +8128,7 @@ void TABLE_LIST::check_pushable_cond_for_table(Item *cond)
item->clear_extraction_flag();
}
}
else if (cond->walk(&Item::exclusive_dependence_on_table_processor,
0, (void *) &tab_map))
else if (!cond->excl_dep_on_table(tab_map))
cond->set_extraction_flag(NO_EXTRACTION_FL);
}