summaryrefslogtreecommitdiff
path: root/sql/table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/table.cc')
-rw-r--r--sql/table.cc176
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;
+}