diff options
Diffstat (limited to 'sql/table.cc')
-rw-r--r-- | sql/table.cc | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/sql/table.cc b/sql/table.cc index 6e5caf7f998..1b2b7352046 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -7903,3 +7903,179 @@ double KEY::actual_rec_per_key(uint i) return (is_statistics_from_stat_tables ? read_stats->get_avg_frequency(i) : (double) rec_per_key[i]); } + + +/** + @brief + Mark subformulas of a condition unusable for the condition pushed into table + + @param cond The condition whose subformulas are to be marked + + @details + This method recursively traverses the AND-OR condition cond and for each subformula + of the codition it checks whether it can be usable for the extraction of a condition + that can be pushed into this table. The subformulas that are not usable are + marked with the flag NO_EXTRACTION_FL. + @note + This method is called before any call of TABLE_LIST::build_pushable_cond_for_table. + The flag NO_EXTRACTION_FL set in a subformula allows to avoid building clone + for the subformula when extracting the pushable condition. +*/ + +void TABLE_LIST::check_pushable_cond_for_table(Item *cond) +{ + table_map tab_map= table->map; + cond->clear_extraction_flag(); + if (cond->type() == Item::COND_ITEM) + { + bool and_cond= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC; + List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + uint count= 0; + Item *item; + while ((item=li++)) + { + check_pushable_cond_for_table(item); + if (item->get_extraction_flag() != NO_EXTRACTION_FL) + count++; + else if (!and_cond) + break; + } + if ((and_cond && count == 0) || item) + { + cond->set_extraction_flag(NO_EXTRACTION_FL); + if (and_cond) + li.rewind(); + while ((item= li++)) + item->clear_extraction_flag(); + } + } + else if (cond->walk(&Item::exclusive_dependence_on_table_processor, + 0, (uchar *) &tab_map)) + cond->set_extraction_flag(NO_EXTRACTION_FL); +} + + +/** + @brief + Build condition extractable from the given one depended only on this table + + @param thd The thread handle + @param cond The condition from which the pushable one is to be extracted + + @details + For the given condition cond this method finds out what condition depended + only on this table can be extracted from cond. If such condition C exists + the method builds the item for it. + The method uses the flag NO_EXTRACTION_FL set by the preliminary call of + the method TABLE_LIST::check_pushable_cond_for_table to figure out whether + a subformula depends only on this table or not. + @note + The built condition C is always implied by the condition cond + (cond => C). The method tries to build the most restictive such + condition (i.e. for any other condition C' such that cond => C' + we have C => C'). + @note + The build item is not ready for usage: substitution for the field items + has to be done and it has to be re-fixed. + + @retval + the built condition pushable into this table if such a condition exists + NULL if there is no such a condition +*/ + +Item* TABLE_LIST::build_pushable_cond_for_table(THD *thd, Item *cond) +{ + table_map tab_map= table->map; + bool is_multiple_equality= cond->type() == Item::FUNC_ITEM && + ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC; + if (cond->get_extraction_flag() == NO_EXTRACTION_FL) + return 0; + if (cond->type() == Item::COND_ITEM) + { + bool cond_and= false; + Item_cond *new_cond; + if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) + { + cond_and= true; + new_cond=new (thd->mem_root) Item_cond_and(thd); + } + else + new_cond= new (thd->mem_root) Item_cond_or(thd); + if (!new_cond) + return 0; + List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + Item *item; + while ((item=li++)) + { + if (item->get_extraction_flag() == NO_EXTRACTION_FL) + { + if (!cond_and) + return 0; + continue; + } + Item *fix= build_pushable_cond_for_table(thd, item); + if (!fix && !cond_and) + return 0; + if (!fix) + continue; + new_cond->argument_list()->push_back(fix, thd->mem_root); + } + switch (new_cond->argument_list()->elements) + { + case 0: + return 0; + case 1: + return new_cond->argument_list()->head(); + default: + return new_cond; + } + } + else if (is_multiple_equality) + { + if (!(cond->used_tables() & tab_map)) + return 0; + Item *new_cond= NULL; + int i= 0; + Item_equal *item_equal= (Item_equal *) cond; + Item *left_item = item_equal->get_const(); + Item_equal_fields_iterator it(*item_equal); + Item *item; + if (!left_item) + { + while ((item=it++)) + if (item->used_tables() == tab_map) + { + left_item= item; + break; + } + } + if (!left_item) + return 0; + while ((item=it++)) + { + if (!(item->used_tables() == tab_map)) + continue; + Item_func_eq *eq= + new (thd->mem_root) Item_func_eq(thd, item, left_item); + if (eq) + { + i++; + switch (i) + { + case 1: + new_cond= eq; + break; + case 2: + new_cond= new (thd->mem_root) Item_cond_and(thd, new_cond, eq); + break; + default: + ((Item_cond_and*)new_cond)->argument_list()->push_back(eq, thd->mem_root); + } + } + } + return new_cond; + } + else if (cond->get_extraction_flag() != NO_EXTRACTION_FL) + return cond->build_clone(thd, thd->mem_root); + return 0; +} |