diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 8a7422ba5ec..722ff76e556 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -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 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; diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result index dbc25fb255c..db65d9cfec9 100644 --- a/mysql-test/r/derived_cond_pushdown.result +++ b/mysql-test/r/derived_cond_pushdown.result @@ -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": "", + "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": "", + "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": "", + "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": "", + "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; diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index 5e6bcd0db37..f3964605b1a 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -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 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 diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test index bc448093e33..6b5da541b7d 100644 --- a/mysql-test/t/derived_cond_pushdown.test +++ b/mysql-test/t/derived_cond_pushdown.test @@ -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; diff --git a/sql/item.cc b/sql/item.cc index df615b5ace9..61a85f6d487 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -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 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 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 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 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 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) diff --git a/sql/item.h b/sql/item.h index 5ed3e8acb82..02e4b2e3468 100644 --- a/sql/item.h +++ b/sql/item.h @@ -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(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(thd, mem_root, this); } }; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 18ce611d306..c81a1621f8a 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -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; diff --git a/sql/item_func.h b/sql/item_func.h index 0919685bbf3..585b981ba05 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -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 diff --git a/sql/item_row.h b/sql/item_row.h index 26468336dc8..cd58e15fe8b 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -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(thd, mem_root, this); } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 8f0410b4284..649f745fdc4 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -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; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index e3ead45447f..9584f2aba36 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -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); + } } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0c55ffc5892..a1ef42861b4 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -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); diff --git a/sql/table.cc b/sql/table.cc index a856799ddd5..28fa34c5ad7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -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); }