Commit fa7f6772 authored by Igor Babaev's avatar Igor Babaev

Fixed bug mdev-4355.

This patch almost totally revised the patch for bug mdev-4177.
The latter had too many defects. In particular, it did not
propagate multiple equalities formed when merging a degenerate
disjunct into underlying AND formula.
parent 8a732d5a
...@@ -5155,7 +5155,7 @@ a b c ...@@ -5155,7 +5155,7 @@ a b c
8 8 8 8 8 8
DROP TABLE t1,t2; DROP TABLE t1,t2;
# #
# Bug mdev-4413: another manifestations of bug mdev-2474 # Bug mdev-4413: another manifestations of bug mdev-4274
# (valgrind complains) # (valgrind complains)
# #
CREATE TABLE t1 (a int, b int) ENGINE=MyISAM; CREATE TABLE t1 (a int, b int) ENGINE=MyISAM;
...@@ -5167,4 +5167,54 @@ WHERE c = a AND ...@@ -5167,4 +5167,54 @@ WHERE c = a AND
( 0 OR ( b BETWEEN 45 AND 300 OR a > 45 AND a < 100 ) AND b = c ); ( 0 OR ( b BETWEEN 45 AND 300 OR a > 45 AND a < 100 ) AND b = c );
a b c a b c
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# Bug mdev-4355: equalities from the result of simplification of OR
# are not propagated to lower AND levels
#
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,101),(2,102),(3,103),(4,104),(5,11);
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (1 != 1 OR a = 5) AND (b != 1 OR a = 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = 5) and (`test`.`t1`.`b` <> 1))
SELECT * FROM t1 WHERE (1 != 1 OR a = 5) AND (b != 1 OR a = 1);
a b
5 11
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (1 != 1 OR a = 5);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = 5) and (`test`.`t1`.`b` <> 1))
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (1 != 1 OR a = 5);
a b
5 11
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (a = 5 OR 1 != 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = 5) and (`test`.`t1`.`b` <> 1))
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (a = 5 OR 1 != 1);
a b
5 11
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5 OR 1 != 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where 0
SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5 OR 1 != 1);
a b
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5 OR 1 != 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`b` = 5) and (`test`.`t1`.`a` = 5))
SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5 OR 1 != 1);
a b
DROP TABLE t1;
End of 5.3 tests End of 5.3 tests
...@@ -5166,7 +5166,7 @@ a b c ...@@ -5166,7 +5166,7 @@ a b c
8 8 8 8 8 8
DROP TABLE t1,t2; DROP TABLE t1,t2;
# #
# Bug mdev-4413: another manifestations of bug mdev-2474 # Bug mdev-4413: another manifestations of bug mdev-4274
# (valgrind complains) # (valgrind complains)
# #
CREATE TABLE t1 (a int, b int) ENGINE=MyISAM; CREATE TABLE t1 (a int, b int) ENGINE=MyISAM;
...@@ -5178,6 +5178,56 @@ WHERE c = a AND ...@@ -5178,6 +5178,56 @@ WHERE c = a AND
( 0 OR ( b BETWEEN 45 AND 300 OR a > 45 AND a < 100 ) AND b = c ); ( 0 OR ( b BETWEEN 45 AND 300 OR a > 45 AND a < 100 ) AND b = c );
a b c a b c
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# Bug mdev-4355: equalities from the result of simplification of OR
# are not propagated to lower AND levels
#
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,101),(2,102),(3,103),(4,104),(5,11);
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (1 != 1 OR a = 5) AND (b != 1 OR a = 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = 5) and (`test`.`t1`.`b` <> 1))
SELECT * FROM t1 WHERE (1 != 1 OR a = 5) AND (b != 1 OR a = 1);
a b
5 11
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (1 != 1 OR a = 5);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = 5) and (`test`.`t1`.`b` <> 1))
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (1 != 1 OR a = 5);
a b
5 11
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (a = 5 OR 1 != 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = 5) and (`test`.`t1`.`b` <> 1))
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (a = 5 OR 1 != 1);
a b
5 11
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5 OR 1 != 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where 0
SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5 OR 1 != 1);
a b
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5 OR 1 != 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`b` = 5) and (`test`.`t1`.`a` = 5))
SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5 OR 1 != 1);
a b
DROP TABLE t1;
End of 5.3 tests End of 5.3 tests
set join_cache_level=default; set join_cache_level=default;
show variables like 'join_cache_level'; show variables like 'join_cache_level';
......
...@@ -5155,7 +5155,7 @@ a b c ...@@ -5155,7 +5155,7 @@ a b c
8 8 8 8 8 8
DROP TABLE t1,t2; DROP TABLE t1,t2;
# #
# Bug mdev-4413: another manifestations of bug mdev-2474 # Bug mdev-4413: another manifestations of bug mdev-4274
# (valgrind complains) # (valgrind complains)
# #
CREATE TABLE t1 (a int, b int) ENGINE=MyISAM; CREATE TABLE t1 (a int, b int) ENGINE=MyISAM;
...@@ -5167,4 +5167,54 @@ WHERE c = a AND ...@@ -5167,4 +5167,54 @@ WHERE c = a AND
( 0 OR ( b BETWEEN 45 AND 300 OR a > 45 AND a < 100 ) AND b = c ); ( 0 OR ( b BETWEEN 45 AND 300 OR a > 45 AND a < 100 ) AND b = c );
a b c a b c
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# Bug mdev-4355: equalities from the result of simplification of OR
# are not propagated to lower AND levels
#
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,101),(2,102),(3,103),(4,104),(5,11);
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (1 != 1 OR a = 5) AND (b != 1 OR a = 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = 5) and (`test`.`t1`.`b` <> 1))
SELECT * FROM t1 WHERE (1 != 1 OR a = 5) AND (b != 1 OR a = 1);
a b
5 11
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (1 != 1 OR a = 5);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = 5) and (`test`.`t1`.`b` <> 1))
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (1 != 1 OR a = 5);
a b
5 11
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (a = 5 OR 1 != 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = 5) and (`test`.`t1`.`b` <> 1))
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (a = 5 OR 1 != 1);
a b
5 11
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5 OR 1 != 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where 0
SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5 OR 1 != 1);
a b
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5 OR 1 != 1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`b` = 5) and (`test`.`t1`.`a` = 5))
SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5 OR 1 != 1);
a b
DROP TABLE t1;
End of 5.3 tests End of 5.3 tests
...@@ -1380,7 +1380,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra ...@@ -1380,7 +1380,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 100.00 Using where 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 2 100.00 Using where
2 MATERIALIZED t3 hash_ALL NULL #hash#$hj 5 test.t2.i2 3 100.00 Using where; Using join buffer (flat, BNLH join) 2 MATERIALIZED t3 hash_ALL NULL #hash#$hj 5 test.t2.i2 3 100.00 Using where; Using join buffer (flat, BNLH join)
Warnings: Warnings:
Note 1003 select `test`.`t1`.`i1` AS `i1` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t3`.`i3` = `test`.`t2`.`i2`) and (`test`.`t1`.`i1` = `test`.`t2`.`i2`) and (`test`.`t2`.`i2` > 0)) Note 1003 select `test`.`t1`.`i1` AS `i1` from `test`.`t1` semi join (`test`.`t2` join `test`.`t3`) where ((`test`.`t3`.`i3` = `test`.`t2`.`i2`) and (`test`.`t1`.`i1` = `test`.`t2`.`i2`) and (`test`.`t3`.`i3` > 0))
SELECT * FROM t1 SELECT * FROM t1
WHERE i1 IN (SELECT i3 FROM t2, t3 WHERE i3 > 0 AND i3 = i2 OR 1=2); WHERE i1 IN (SELECT i3 FROM t2, t3 WHERE i3 > 0 AND i3 = i2 OR 1=2);
i1 i1
......
...@@ -4326,7 +4326,7 @@ SELECT * FROM t1 INNER JOIN t2 ON ( c = a ) ...@@ -4326,7 +4326,7 @@ SELECT * FROM t1 INNER JOIN t2 ON ( c = a )
DROP TABLE t1,t2; DROP TABLE t1,t2;
--echo # --echo #
--echo # Bug mdev-4413: another manifestations of bug mdev-2474 --echo # Bug mdev-4413: another manifestations of bug mdev-4274
--echo # (valgrind complains) --echo # (valgrind complains)
--echo # --echo #
...@@ -4342,4 +4342,34 @@ SELECT * FROM t1, t2 ...@@ -4342,4 +4342,34 @@ SELECT * FROM t1, t2
DROP TABLE t1, t2; DROP TABLE t1, t2;
--echo #
--echo # Bug mdev-4355: equalities from the result of simplification of OR
--echo # are not propagated to lower AND levels
--echo #
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,101),(2,102),(3,103),(4,104),(5,11);
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (1 != 1 OR a = 5) AND (b != 1 OR a = 1);
SELECT * FROM t1 WHERE (1 != 1 OR a = 5) AND (b != 1 OR a = 1);
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (1 != 1 OR a = 5);
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (1 != 1 OR a = 5);
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (a = 5 OR 1 != 1);
SELECT * FROM t1 WHERE (b != 1 OR a = 1) AND (a = 5 OR 1 != 1);
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5 OR 1 != 1);
SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5 OR 1 != 1);
EXPLAIN EXTENDED
SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5 OR 1 != 1);
SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5 OR 1 != 1);
DROP TABLE t1;
--echo End of 5.3 tests --echo End of 5.3 tests
...@@ -5609,9 +5609,11 @@ void Item_equal::merge(Item_equal *item) ...@@ -5609,9 +5609,11 @@ void Item_equal::merge(Item_equal *item)
Merge members of another Item_equal object into this one Merge members of another Item_equal object into this one
@param item multiple equality whose members are to be merged @param item multiple equality whose members are to be merged
@param save_merged keep the list of equalities in 'item' intact
(e.g. for other merges)
@details @details
If the Item_equal 'item' happened to have some elements of the list If the Item_equal 'item' happens to have some elements of the list
of equal items belonging to 'this' object then the function merges of equal items belonging to 'this' object then the function merges
the equal items from 'item' into this list. the equal items from 'item' into this list.
If both lists contains constants and they are different then If both lists contains constants and they are different then
...@@ -5626,24 +5628,45 @@ void Item_equal::merge(Item_equal *item) ...@@ -5626,24 +5628,45 @@ void Item_equal::merge(Item_equal *item)
The method 'merge' just joins the list of equal items belonging to 'item' 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 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'. 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 The method 'merge_into_with_check' really merges two lists of equal items if
have common members. they have common members.
*/ */
bool Item_equal::merge_with_check(Item_equal *item) bool Item_equal::merge_with_check(Item_equal *item, bool save_merged)
{ {
bool intersected= FALSE; bool intersected= FALSE;
Item_equal_fields_iterator_slow fi(*this); Item_equal_fields_iterator_slow fi(*item);
while (fi++) while (fi++)
{ {
if (item->contains(fi.get_curr_field())) if (contains(fi.get_curr_field()))
{ {
fi.remove();
intersected= TRUE; intersected= TRUE;
if (!save_merged)
fi.remove();
} }
} }
if (intersected) if (intersected)
item->merge(this); {
if (!save_merged)
merge(item);
else
{
Item *c= item->get_const();
if (c)
add_const(c);
if (!cond_false)
{
Item *item;
fi.rewind();
while ((item= fi++))
{
if (!contains(fi.get_curr_field()))
add(item);
}
}
}
}
return intersected; return intersected;
} }
...@@ -5653,16 +5676,24 @@ bool Item_equal::merge_with_check(Item_equal *item) ...@@ -5653,16 +5676,24 @@ bool Item_equal::merge_with_check(Item_equal *item)
Merge this object into a list of Item_equal objects Merge this object into a list of Item_equal objects
@param list the list of Item_equal objects to merge into @param list the list of Item_equal objects to merge into
@param save_merged keep the list of equalities in 'this' intact
(e.g. for other merges)
@param only_intersected do not merge if there are no common members
in any of Item_equal objects from the list
and this Item_equal
@details @details
If the list of equal items from 'this' object contains common members 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' 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 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 that replaces e1,...,ek in the 'list'. Otherwise, in the case
when the value of the parameter only_if_intersected is false, this
Item_equal is joined to the 'list'. Item_equal is joined to the 'list'.
*/ */
void Item_equal::merge_into_list(List<Item_equal> *list) void Item_equal::merge_into_list(List<Item_equal> *list,
bool save_merged,
bool only_intersected)
{ {
Item_equal *item; Item_equal *item;
List_iterator<Item_equal> it(*list); List_iterator<Item_equal> it(*list);
...@@ -5671,16 +5702,16 @@ void Item_equal::merge_into_list(List<Item_equal> *list) ...@@ -5671,16 +5702,16 @@ void Item_equal::merge_into_list(List<Item_equal> *list)
{ {
if (!merge_into) if (!merge_into)
{ {
if (merge_with_check(item)) if (item->merge_with_check(this, save_merged))
merge_into= item; merge_into= item;
} }
else else
{ {
if (item->merge_with_check(merge_into)) if (merge_into->merge_with_check(item, false))
it.remove(); it.remove();
} }
} }
if (!merge_into) if (!only_intersected && !merge_into)
list->push_back(this); list->push_back(this);
} }
......
...@@ -1761,8 +1761,9 @@ public: ...@@ -1761,8 +1761,9 @@ public:
/** Get number of field items / references to field items in this object */ /** Get number of field items / references to field items in this object */
uint n_field_items() { return equal_items.elements-test(with_const); } uint n_field_items() { return equal_items.elements-test(with_const); }
void merge(Item_equal *item); void merge(Item_equal *item);
bool merge_with_check(Item_equal *equal_item); bool merge_with_check(Item_equal *equal_item, bool save_merged);
void merge_into_list(List<Item_equal> *list); void merge_into_list(List<Item_equal> *list, bool save_merged,
bool only_intersected);
void update_const(); void update_const();
enum Functype functype() const { return MULT_EQUAL_FUNC; } enum Functype functype() const { return MULT_EQUAL_FUNC; }
longlong val_int(); longlong val_int();
......
...@@ -13134,14 +13134,175 @@ optimize_cond(JOIN *join, COND *conds, ...@@ -13134,14 +13134,175 @@ optimize_cond(JOIN *join, COND *conds,
/** /**
Remove const and eq items. @brief
Propagate multiple equalities to the sub-expressions of a condition
@param thd thread handle
@param cond the condition where equalities are to be propagated
@param *new_equalities the multiple equalities to be propagated
@param inherited path to all inherited multiple equality items
@param[out] is_simplifiable_cond 'cond' may be simplified after the
propagation of the equalities
@details
The function recursively traverses the tree of the condition 'cond' and
for each its AND sub-level of any depth the function merges the multiple
equalities from the list 'new_equalities' into the multiple equalities
attached to the AND item created for this sub-level.
The function also [re]sets references to the equalities formed by the
merges of multiple equalities in all field items occurred in 'cond'
that are encountered in the equalities.
If the result of any merge of multiple equalities is an impossible
condition the function returns TRUE in the parameter is_simplifiable_cond.
*/
void propagate_new_equalities(THD *thd, Item *cond,
List<Item_equal> *new_equalities,
COND_EQUAL *inherited,
bool *is_simplifiable_cond)
{
if (cond->type() == Item::COND_ITEM)
{
bool and_level= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC;
if (and_level)
{
Item_cond_and *cond_and= (Item_cond_and *) cond;
List<Item_equal> *cond_equalities= &cond_and->cond_equal.current_level;
inherited= cond_and->cond_equal.upper_levels;
if (!cond_equalities->is_empty() && cond_equalities != new_equalities)
{
Item_equal *equal_item;
List_iterator<Item_equal> it(*new_equalities);
while ((equal_item= it++))
{
equal_item->merge_into_list(cond_equalities, true, true);
}
List_iterator<Item_equal> ei(*cond_equalities);
while ((equal_item= ei++))
{
if (equal_item->const_item() && !equal_item->val_int())
{
*is_simplifiable_cond= true;
return;
}
}
}
}
Item *item;
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
while ((item= li++))
{
propagate_new_equalities(thd, item, new_equalities, inherited,
is_simplifiable_cond);
}
}
else if (cond->type() == Item::FUNC_ITEM &&
((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
{
Item_equal *equal_item;
List_iterator<Item_equal> it(*new_equalities);
Item_equal *equality= (Item_equal *) cond;
while ((equal_item= it++))
{
equality->merge_with_check(equal_item, true);
}
if (equality->const_item() && !equality->val_int())
*is_simplifiable_cond= true;
}
else
{
uchar* is_subst_valid= (uchar *) Item::ANY_SUBST;
cond= cond->compile(&Item::subst_argument_checker,
&is_subst_valid,
&Item::equal_fields_propagator,
(uchar *) inherited);
cond->update_used_tables();
}
}
/**
@brief
Evaluate all constant boolean sub-expressions in a condition
@param thd thread handle
@param cond condition where where to evaluate constant sub-expressions
@param[out] cond_value : the returned value of the condition
(TRUE/FALSE/UNKNOWN:
Item::COND_TRUE/Item::COND_FALSE/Item::COND_OK)
@return @return
Return new item, or NULL if no condition @n the item that is the result of the substitution of all inexpensive constant
cond_value is set to according: boolean sub-expressions into cond, or,
- COND_OK : query is possible (field = constant) NULL if the condition is constant and is evaluated to FALSE.
- COND_TRUE : always true ( 1 = 1 )
- COND_FALSE : always false ( 1 = 2 ) @details
This function looks for all inexpensive constant boolean sub-expressions in
the given condition 'cond' and substitutes them for their values.
For example, the condition 2 > (5 + 1) or a < (10 / 2)
will be transformed to the condition a < (10 / 2).
Note that a constant sub-expression is evaluated only if it is constant and
inexpensive. A sub-expression with an uncorrelated subquery may be evaluated
only if the subquery is considered as inexpensive.
The function does not evaluate a constant sub-expression if it is not on one
of AND/OR levels of the condition 'cond'. For example, the subquery in the
condition a > (select max(b) from t1 where b > 5) will never be evaluated
by this function.
If a constant boolean sub-expression is evaluated to TRUE then:
- when the sub-expression is a conjunct of an AND formula it is simply
removed from this formula
- when the sub-expression is a disjunct of an OR formula the whole OR
formula is converted to TRUE
If a constant boolean sub-expression is evaluated to FALSE then:
- when the sub-expression is a disjunct of an OR formula it is simply
removed from this formula
- when the sub-expression is a conjuct of an AND formula the whole AND
formula is converted to FALSE
When a disjunct/conjunct is removed from an OR/AND formula it might happen
that there is only one conjunct/disjunct remaining. In this case this
remaining disjunct/conjunct must be merged into underlying AND/OR formula,
because AND/OR levels must alternate in the same way as they alternate
after fix_fields() is called for the original condition.
The specifics of merging a formula f into an AND formula A appears
when A contains multiple equalities and f contains multiple equalities.
In this case the multiple equalities from f and A have to be merged.
After this the resulting multiple equalities have to be propagated into
the all AND/OR levels of the formula A (see propagate_new_equalities()).
The propagation of multiple equalities might result in forming multiple
equalities that are always FALSE. This, in its turn, might trigger further
simplification of the condition.
@note
EXAMPLE 1:
SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5 OR 1 != 1);
First 1 != 1 will be removed from the second conjunct:
=> SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5 AND a = 5);
Then (b = 5 AND a = 5) will be merged into the top level condition:
=> SELECT * FROM t1 WHERE (b = 1 OR a = 1) AND (b = 5) AND (a = 5);
Then (b = 5), (a = 5) will be propagated into the disjuncs of
(b = 1 OR a = 1):
=> SELECT * FROM t1 WHERE ((b = 1) AND (b = 5) AND (a = 5) OR
(a = 1) AND (b = 5) AND (a = 5)) AND
(b = 5) AND (a = 5)
=> SELECT * FROM t1 WHERE ((FALSE AND (a = 5)) OR
(FALSE AND (b = 5))) AND
(b = 5) AND (a = 5)
After this an additional call of remove_eq_conds() converts it
to FALSE
EXAMPLE 2:
SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5 OR 1 != 1);
=> SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5 AND a = 5);
=> SELECT * FROM t1 WHERE (b = 1 OR a = 5) AND (b = 5) AND (a = 5);
=> SELECT * FROM t1 WHERE ((b = 1) AND (b = 5) AND (a = 5) OR
(a = 5) AND (b = 5) AND (a = 5)) AND
(b = 5) AND (a = 5)
=> SELECT * FROM t1 WHERE ((FALSE AND (a = 5)) OR
((b = 5) AND (a = 5))) AND
(b = 5) AND (a = 5)
After this an additional call of remove_eq_conds() converts it to
=> SELECT * FROM t1 WHERE (b = 5) AND (a = 5)
*/ */
COND * COND *
...@@ -13149,9 +13310,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) ...@@ -13149,9 +13310,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
{ {
if (cond->type() == Item::COND_ITEM) if (cond->type() == Item::COND_ITEM)
{ {
List<Item_equal> new_equalities;
bool and_level= ((Item_cond*) cond)->functype() bool and_level= ((Item_cond*) cond)->functype()
== Item_func::COND_AND_FUNC; == Item_func::COND_AND_FUNC;
List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); List<Item> *cond_arg_list= ((Item_cond*) cond)->argument_list();
List_iterator<Item> li(*cond_arg_list);
Item::cond_result tmp_cond_value; Item::cond_result tmp_cond_value;
bool should_fix_fields=0; bool should_fix_fields=0;
...@@ -13161,91 +13324,71 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) ...@@ -13161,91 +13324,71 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
{ {
Item *new_item=remove_eq_conds(thd, item, &tmp_cond_value); Item *new_item=remove_eq_conds(thd, item, &tmp_cond_value);
if (!new_item) if (!new_item)
{
/* This can happen only when item is converted to TRUE or FALSE */
li.remove(); li.remove();
}
else if (item != new_item) else if (item != new_item)
{ {
/*
This can happen when:
- item was an OR formula converted to one disjunct
- item was an AND formula converted to one conjunct
In these cases the disjunct/conjunct must be merged into the
argument list of cond.
*/
if (new_item->type() == Item::COND_ITEM)
{
DBUG_ASSERT(((Item_cond *) cond)->functype() ==
((Item_cond *) new_item)->functype());
List<Item> *new_item_arg_list=
((Item_cond *) new_item)->argument_list();
if (and_level) if (and_level)
{ {
/* /*
Take a special care of multiple equality predicates If new_item is an AND formula then multiple equalities
that may be part of 'cond' and 'new_item'. of new_item_arg_list must merged into multiple equalities
Those multiple equalities that have common members of cond_arg_list.
must be merged.
*/ */
Item_cond_and *cond_and= (Item_cond_and *) cond; List<Item_equal> *new_item_equalities=
List<Item_equal> *cond_equal_items= &((Item_cond_and *) new_item)->cond_equal.current_level;
&cond_and->cond_equal.current_level; if (!new_item_equalities->is_empty())
List<Item> *cond_and_list= cond_and->argument_list();
if (new_item->type() == Item::COND_ITEM &&
((Item_cond*) new_item)->functype() == Item_func::COND_AND_FUNC)
{
Item_cond_and *new_item_and= (Item_cond_and *) new_item;
List<Item_equal> *new_item_equal_items=
&new_item_and->cond_equal.current_level;
List<Item> *new_item_and_list= new_item_and->argument_list();
cond_and_list->disjoin((List<Item>*) cond_equal_items);
new_item_and_list->disjoin((List<Item>*) new_item_equal_items);
Item_equal *equal_item;
List_iterator<Item_equal> it(*new_item_equal_items);
while ((equal_item= it++))
{ {
equal_item->merge_into_list(cond_equal_items); /*
Cut the multiple equalities from the new_item_arg_list and
append them on the list new_equalities. Later the equalities
from this list will be merged into the multiple equalities
of cond_arg_list all together.
*/
new_item_arg_list->disjoin((List<Item> *) new_item_equalities);
new_equalities.concat(new_item_equalities);
} }
if (new_item_and_list->is_empty()) }
if (new_item_arg_list->is_empty())
li.remove(); li.remove();
else else
{ {
Item *list_item; uint cnt= new_item_arg_list->elements;
Item *new_list_item; li.replace(*new_item_arg_list);
uint cnt= new_item_and_list->elements; /* Make iterator li ignore new items */
List_iterator<Item> it(*new_item_and_list);
while ((list_item= it++))
{
uchar* is_subst_valid= (uchar *) Item::ANY_SUBST;
new_list_item=
list_item->compile(&Item::subst_argument_checker,
&is_subst_valid,
&Item::equal_fields_propagator,
(uchar *) &cond_and->cond_equal);
if (new_list_item != list_item)
it.replace(new_list_item);
new_list_item->update_used_tables();
}
li.replace(*new_item_and_list);
for (cnt--; cnt; cnt--) for (cnt--; cnt; cnt--)
item= li++; li++;
should_fix_fields= 1;
} }
cond_and_list->concat((List<Item>*) cond_equal_items);
} }
else if (new_item->type() == Item::FUNC_ITEM && else if (and_level &&
new_item->type() == Item::FUNC_ITEM &&
((Item_cond*) new_item)->functype() == ((Item_cond*) new_item)->functype() ==
Item_func::MULT_EQUAL_FUNC) Item_func::MULT_EQUAL_FUNC)
{ {
cond_and_list->disjoin((List<Item>*) cond_equal_items);
((Item_equal *) new_item)->merge_into_list(cond_equal_items);
li.remove(); li.remove();
cond_and_list->concat((List<Item>*) cond_equal_items); new_equalities.push_back((Item_equal *) new_item);
}
else
li.replace(new_item);
} }
else else
{ {
if (new_item->type() == Item::COND_ITEM &&
((Item_cond*) new_item)->functype() ==
((Item_cond*) cond)->functype())
{
List<Item> *arg_list= ((Item_cond*) new_item)->argument_list();
uint cnt= arg_list->elements;
li.replace(*arg_list);
for ( cnt--; cnt; cnt--)
item= li++;
}
else
li.replace(new_item); li.replace(new_item);
should_fix_fields= 1;
} }
should_fix_fields=1;
} }
if (*cond_value == Item::COND_UNDEF) if (*cond_value == Item::COND_UNDEF)
*cond_value=tmp_cond_value; *cond_value=tmp_cond_value;
...@@ -13272,6 +13415,53 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) ...@@ -13272,6 +13415,53 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
break; /* purecov: deadcode */ break; /* purecov: deadcode */
} }
} }
if (!new_equalities.is_empty())
{
DBUG_ASSERT(and_level);
/*
Merge multiple equalities that were cut from the results of
simplification of OR formulas converted into AND formulas.
These multiple equalities are to be merged into the
multiple equalities of cond_arg_list.
*/
COND_EQUAL *cond_equal= &((Item_cond_and *) cond)->cond_equal;
List<Item_equal> *cond_equalities= &cond_equal->current_level;
cond_arg_list->disjoin((List<Item> *) cond_equalities);
Item_equal *equality;
List_iterator_fast<Item_equal> it(new_equalities);
while ((equality= it++))
{
equality->merge_into_list(cond_equalities, false, false);
List_iterator_fast<Item_equal> ei(*cond_equalities);
while ((equality= ei++))
{
if (equality->const_item() && !equality->val_int())
{
*cond_value= Item::COND_FALSE;
return (COND*) 0;
}
}
}
cond_arg_list->concat((List<Item> *) cond_equalities);
/*
Propagate the newly formed multiple equalities to
the all AND/OR levels of cond
*/
bool is_simplifiable_cond= true;
propagate_new_equalities(thd, cond, cond_equalities,
cond_equal->upper_levels,
&is_simplifiable_cond);
/*
If the above propagation of multiple equalities brings us
to multiple equalities that are always FALSE then try to
simplify the condition with remove_eq_cond() again.
*/
if (is_simplifiable_cond)
{
if (!(cond= remove_eq_conds(thd, cond, cond_value)))
return cond;
}
}
if (should_fix_fields) if (should_fix_fields)
cond->update_used_tables(); cond->update_used_tables();
...@@ -13383,6 +13573,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) ...@@ -13383,6 +13573,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
return cond; // Point at next and level return cond; // Point at next and level
} }
/** /**
Check if equality can be used in removing components of GROUP BY/DISTINCT Check if equality can be used in removing components of GROUP BY/DISTINCT
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment