summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.cc
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2013-02-24 19:16:11 -0800
committerIgor Babaev <igor@askmonty.org>2013-02-24 19:16:11 -0800
commitd434d79acff4d01e6b4d54fdd8e0aa0edb195157 (patch)
treef7761d231ffd23d535ab1de6cdf3590578167103 /sql/item_cmpfunc.cc
parented7671d52367ab424a1ec4f42779fdec894476ae (diff)
downloadmariadb-git-d434d79acff4d01e6b4d54fdd8e0aa0edb195157.tar.gz
Fixed bug mdev-4177
The function remove_eq_cond removes the parts of a disjunction for which it has been proved that they are always true. In the result of this removal the disjunction may be converted into a formula without OR that must be merged into the the AND formula that contains the disjunction. The merging of two AND conditions must take into account the multiple equalities that may be part of each of them. These multiple equality must be merged and become part of the and object built as the result of the merge of the AND conditions. Erroneously the function remove_eq_cond lacked the code that would merge multiple equalities of the merged AND conditions. This could lead to confusing situations when at the same AND level there were two multiple equalities with common members and the list of equal items contained only some of these multiple equalities. This, in its turn, could lead to an incorrect work of the function substitute_for_best_equal_field when it tried to optimize ref accesses. This resulted in forming invalid TABLE_REF objects that were used to build look-up keys when materialized subqueries were exploited.
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r--sql/item_cmpfunc.cc84
1 files changed, 83 insertions, 1 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index b6ffc03a794..1aaedf3a6ad 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -5491,7 +5491,7 @@ Item_equal::Item_equal(Item_equal *item_equal)
}
-/*
+/**
@brief
Add a constant item to the Item_equal object
@@ -5537,6 +5537,7 @@ void Item_equal::add_const(Item *c, Item *f)
const_item_cache= 1;
}
+
/**
@brief
Check whether a field is referred to in the multiple equality
@@ -5605,6 +5606,87 @@ void Item_equal::merge(Item_equal *item)
/**
@brief
+ Merge members of another Item_equal object into this one
+
+ @param item multiple equality whose members are to be merged
+
+ @details
+ If the Item_equal 'item' happened to have some elements of the list
+ of equal items belonging to 'this' object then the function merges
+ the equal items from 'item' into this list.
+ If both lists contains constants and they are different then
+ the value of the cond_false flag is set to TRUE.
+
+ @retval
+ 1 the lists of equal items in 'item' and 'this' contain common elements
+ @retval
+ 0 otherwise
+
+ @notes
+ The method 'merge' just joins the list of equal items belonging to 'item'
+ to the list of equal items belonging to this object assuming that the lists
+ are disjoint. It would be more correct to call the method 'join'.
+ The method 'merge_with_check' really merges two lists of equal items if they
+ have common members.
+*/
+
+bool Item_equal::merge_with_check(Item_equal *item)
+{
+ bool intersected= FALSE;
+ Item_equal_fields_iterator_slow fi(*this);
+ while (fi++)
+ {
+ if (item->contains(fi.get_curr_field()))
+ {
+ fi.remove();
+ intersected= TRUE;
+ }
+ }
+ if (intersected)
+ item->merge(this);
+ return intersected;
+}
+
+
+/**
+ @brief
+ Merge this object into a list of Item_equal objects
+
+ @param list the list of Item_equal objects to merge into
+
+ @details
+ If the list of equal items from 'this' object contains common members
+ with the lists of equal items belonging to Item_equal objects from 'list'
+ then all involved Item_equal objects e1,...,ek are merged into one
+ Item equal that replaces e1,...,ek in the 'list'. Otherwise this
+ Item_equal is joined to the 'list'.
+*/
+
+void Item_equal::merge_into_list(List<Item_equal> *list)
+{
+ Item_equal *item;
+ List_iterator<Item_equal> it(*list);
+ Item_equal *merge_into= NULL;
+ while((item= it++))
+ {
+ if (!merge_into)
+ {
+ if (merge_with_check(item))
+ merge_into= item;
+ }
+ else
+ {
+ if (item->merge_with_check(merge_into))
+ it.remove();
+ }
+ }
+ if (!merge_into)
+ list->push_back(this);
+}
+
+
+/**
+ @brief
Order equal items of the multiple equality according to a sorting criteria
@param compare function to compare items from the equal_items list