diff options
author | Igor Babaev <igor@askmonty.org> | 2017-06-22 00:41:44 -0700 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2017-06-22 22:06:03 -0700 |
commit | 9f3622191df074d9f4e512320effe86f06b250fb (patch) | |
tree | 16aadc76e982cb17349df79a381af23fec27b2f8 /sql/item.cc | |
parent | a8131e71f9504a7399bc9a7f312b14ed6700d099 (diff) | |
download | mariadb-git-9f3622191df074d9f4e512320effe86f06b250fb.tar.gz |
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.
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 299 |
1 files changed, 178 insertions, 121 deletions
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) -{ - 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; - } - } +static +Item *get_field_item_for_having(THD *thd, 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_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_where(THD *thd, uchar *arg) +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; - 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++; - return 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++)) + 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 (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); + if (equal_item->used_tables() == tab_map) + { + field_item= (Item_field *) (equal_item->real_item()); + break; } } } - return this; + 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) +{ + 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); + return this; +} -Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg) +Item *Item_direct_view_ref::derived_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) + if (item_equal) { - while ((field=li++)) - { - if (((Item_field*) this)->field == field->tmp_field) - return field->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); } - 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++)) + 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++)) { - 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); - } - } + 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 *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) |