summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2011-04-26 21:11:06 -0700
committerIgor Babaev <igor@askmonty.org>2011-04-26 21:11:06 -0700
commit24edac2211c46ea9ebeb4a13bc467fb20008916e (patch)
treee882cd519a70e326be9086468c7a6113102bf7f8
parent79439d9a7447aac68bba7d68c2d3bf76cc319fdb (diff)
parent8d9dd21d85e257051b45b2f779dcd9bf696bf9e1 (diff)
downloadmariadb-git-24edac2211c46ea9ebeb4a13bc467fb20008916e.tar.gz
Merge
-rw-r--r--mysql-test/r/view.result155
-rw-r--r--mysql-test/t/view.test74
-rw-r--r--sql/item.cc151
-rw-r--r--sql/item.h26
-rw-r--r--sql/item_cmpfunc.cc372
-rw-r--r--sql/item_cmpfunc.h120
-rw-r--r--sql/opt_range.cc13
-rw-r--r--sql/opt_subselect.cc6
-rw-r--r--sql/opt_sum.cc2
-rw-r--r--sql/opt_table_elimination.cc7
-rw-r--r--sql/sql_select.cc147
11 files changed, 817 insertions, 256 deletions
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 6f6fc949222..2b6bd3b3706 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -3974,3 +3974,158 @@ WHERE t3.pk = v1.a AND t2.b = 1 AND t2.b = t3.pk AND v1.a BETWEEN 2 AND 5;
a pk b pk b
DROP VIEW v1;
DROP TABLE t1, t2, t3;
+#
+# Bug#717577: substitution for best field in a query over a view and
+# with OR in the WHERE condition
+#
+create table t1 (a int, b int);
+insert into t1 values (2,4), (1,3);
+create table t2 (c int);
+insert into t2 values (6), (4), (1), (3), (8), (3), (4), (2);
+select * from t1,t2 where t2.c=t1.a and t2.c < 3 or t2.c=t1.b and t2.c >=4;
+a b c
+2 4 4
+1 3 1
+2 4 4
+2 4 2
+explain extended
+select * from t1,t2 where t2.c=t1.a and t2.c < 3 or t2.c=t1.b and t2.c >=4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where (((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`a` < 3)) or ((`test`.`t2`.`c` = `test`.`t1`.`b`) and (`test`.`t1`.`b` >= 4)))
+create view v1 as select * from t2;
+select * from t1,v1 where v1.c=t1.a and v1.c < 3 or v1.c=t1.b and v1.c >=4;
+a b c
+2 4 4
+1 3 1
+2 4 4
+2 4 2
+explain extended
+select * from t1,v1 where v1.c=t1.a and v1.c < 3 or v1.c=t1.b and v1.c >=4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where (((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`a` < 3)) or ((`test`.`t2`.`c` = `test`.`t1`.`b`) and (`test`.`t1`.`b` >= 4)))
+create view v2 as select * from v1;
+select * from t1,v2 where v2.c=t1.a and v2.c < 3 or v2.c=t1.b and v2.c >=4;
+a b c
+2 4 4
+1 3 1
+2 4 4
+2 4 2
+explain extended
+select * from t1,v2 where v2.c=t1.a and v2.c < 3 or v2.c=t1.b and v2.c >=4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where (((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`a` < 3)) or ((`test`.`t2`.`c` = `test`.`t1`.`b`) and (`test`.`t1`.`b` >= 4)))
+create view v3 as select * from t1;
+select * from v3,v2 where v2.c=v3.a and v2.c < 3 or v2.c=v3.b and v2.c >=4;
+a b c
+2 4 4
+1 3 1
+2 4 4
+2 4 2
+explain extended
+select * from v3,v2 where v2.c=v3.a and v2.c < 3 or v2.c=v3.b and v2.c >=4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (flat, BNL join)
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where (((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`a` < 3)) or ((`test`.`t2`.`c` = `test`.`t1`.`b`) and (`test`.`t1`.`b` >= 4)))
+drop view v1,v2,v3;
+drop table t1,t2;
+#
+# Bug#724942: substitution of the constant into a view field
+#
+CREATE TABLE t1 (a int);
+INSERT INTO t1 VALUES (2), (9), (9), (6), (5), (4), (7);
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1 WHERE a > -1 OR a > 6 AND a = 3;
+a
+2
+9
+9
+6
+5
+4
+7
+EXPLAIN EXTENDED
+SELECT * FROM v1 WHERE a > -1 OR a > 6 AND a = 3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 7 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > -(1))
+SELECT * FROM v1 WHERE a > -1 OR a AND a = 0;
+a
+2
+9
+9
+6
+5
+4
+7
+EXPLAIN EXTENDED
+SELECT * FROM v1 WHERE a > -1 OR a AND a = 0;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 7 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > -(1))
+CREATE VIEW v2 AS SELECT * FROM v1;
+SELECT * FROM v2 WHERE a > -1 OR a AND a = 0;
+a
+2
+9
+9
+6
+5
+4
+7
+EXPLAIN EXTENDED
+SELECT * FROM v2 WHERE a > -1 OR a AND a = 0;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 7 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > -(1))
+DROP VIEW v1,v2;
+DROP TABLE t1;
+CREATE TABLE t1 (a varchar(10), KEY (a)) ;
+INSERT INTO t1 VALUES
+('DD'), ('ZZ'), ('ZZ'), ('KK'), ('FF'), ('HH'),('MM');
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1 WHERE a > 'JJ' OR a <> 0 AND a = 'VV';
+a
+KK
+MM
+ZZ
+ZZ
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'VV'
+EXPLAIN EXTENDED
+SELECT * FROM v1 WHERE a > 'JJ' OR a <> 0 AND a = 'VV';
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range a a 13 NULL 4 100.00 Using where; Using index
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'VV'
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 'JJ')
+SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV';
+a
+KK
+MM
+ZZ
+ZZ
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: 'VV'
+EXPLAIN EXTENDED
+SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV';
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 range a a 13 NULL 4 100.00 Using where; Using index
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: 'VV'
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 'JJ')
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index d0295543d16..7bd559452f5 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -3999,3 +3999,77 @@ SELECT * FROM v1, t2, t3
DROP VIEW v1;
DROP TABLE t1, t2, t3;
+--echo #
+--echo # Bug#717577: substitution for best field in a query over a view and
+--echo # with OR in the WHERE condition
+--echo #
+
+create table t1 (a int, b int);
+insert into t1 values (2,4), (1,3);
+create table t2 (c int);
+insert into t2 values (6), (4), (1), (3), (8), (3), (4), (2);
+
+select * from t1,t2 where t2.c=t1.a and t2.c < 3 or t2.c=t1.b and t2.c >=4;
+explain extended
+select * from t1,t2 where t2.c=t1.a and t2.c < 3 or t2.c=t1.b and t2.c >=4;
+
+create view v1 as select * from t2;
+select * from t1,v1 where v1.c=t1.a and v1.c < 3 or v1.c=t1.b and v1.c >=4;
+explain extended
+select * from t1,v1 where v1.c=t1.a and v1.c < 3 or v1.c=t1.b and v1.c >=4;
+
+create view v2 as select * from v1;
+select * from t1,v2 where v2.c=t1.a and v2.c < 3 or v2.c=t1.b and v2.c >=4;
+explain extended
+select * from t1,v2 where v2.c=t1.a and v2.c < 3 or v2.c=t1.b and v2.c >=4;
+
+create view v3 as select * from t1;
+select * from v3,v2 where v2.c=v3.a and v2.c < 3 or v2.c=v3.b and v2.c >=4;
+explain extended
+select * from v3,v2 where v2.c=v3.a and v2.c < 3 or v2.c=v3.b and v2.c >=4;
+
+drop view v1,v2,v3;
+drop table t1,t2;
+
+--echo #
+--echo # Bug#724942: substitution of the constant into a view field
+--echo #
+
+CREATE TABLE t1 (a int);
+INSERT INTO t1 VALUES (2), (9), (9), (6), (5), (4), (7);
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+SELECT * FROM v1 WHERE a > -1 OR a > 6 AND a = 3;
+EXPLAIN EXTENDED
+SELECT * FROM v1 WHERE a > -1 OR a > 6 AND a = 3;
+
+SELECT * FROM v1 WHERE a > -1 OR a AND a = 0;
+EXPLAIN EXTENDED
+SELECT * FROM v1 WHERE a > -1 OR a AND a = 0;
+
+CREATE VIEW v2 AS SELECT * FROM v1;
+
+SELECT * FROM v2 WHERE a > -1 OR a AND a = 0;
+EXPLAIN EXTENDED
+SELECT * FROM v2 WHERE a > -1 OR a AND a = 0;
+
+DROP VIEW v1,v2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a varchar(10), KEY (a)) ;
+INSERT INTO t1 VALUES
+ ('DD'), ('ZZ'), ('ZZ'), ('KK'), ('FF'), ('HH'),('MM');
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+SELECT * FROM v1 WHERE a > 'JJ' OR a <> 0 AND a = 'VV';
+EXPLAIN EXTENDED
+SELECT * FROM v1 WHERE a > 'JJ' OR a <> 0 AND a = 'VV';
+
+SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV';
+EXPLAIN EXTENDED
+SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV';
+
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/sql/item.cc b/sql/item.cc
index 94617c68e0f..b0530f0e17e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4669,13 +4669,14 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
/**
- Check whether a field can be substituted by an equal item.
+ Check whether a field item can be substituted for an equal item
- The function checks whether a substitution of the field
- occurrence for an equal item is valid.
+ @details
+ The function checks whether a substitution of a field item for
+ an equal item is valid.
- @param arg *arg != NULL <-> the field is in the context where
- substitution for an equal item is valid
+ @param arg *arg != NULL && **arg <-> the field is in the context
+ where substitution for an equal item is valid
@note
The following statement is not always true:
@@ -4700,7 +4701,8 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
bool Item_field::subst_argument_checker(uchar **arg)
{
- return (result_type() != STRING_RESULT) || (*arg);
+ return (!(*arg) && (result_type() != STRING_RESULT)) ||
+ ((*arg) && (**arg));
}
@@ -4737,6 +4739,7 @@ static void convert_zerofill_number_to_string(Item **item, Field_num *field)
Set a pointer to the multiple equality the field reference belongs to
(if any).
+ @details
The function looks for a multiple equality containing the field item
among those referenced by arg.
In the case such equality exists the function does the following.
@@ -4813,6 +4816,7 @@ bool Item_field::set_no_const_sub(uchar *arg)
Replace an Item_field for an equal Item_field that evaluated earlier
(if any).
+ @details
If this->item_equal points to some item and coincides with arg then
the function returns a pointer to an item that is taken from
the very beginning of the item_equal list which the Item_field
@@ -4827,7 +4831,7 @@ bool Item_field::set_no_const_sub(uchar *arg)
@note
This function is supposed to be called as a callback parameter in calls
- of the thransformer method.
+ of the transformer method.
@return
- pointer to a replacement Item_field if there is a better equal item or
@@ -4847,7 +4851,9 @@ Item *Item_field::replace_equal_field(uchar *arg)
return this;
return const_item;
}
- Item_field *subst= item_equal->get_first(this);
+ Item_field *subst= (Item_field *)(item_equal->get_first(this));
+ if (subst)
+ subst= (Item_field *) (subst->real_item());
if (subst && !field->eq(subst->field))
return subst;
}
@@ -6393,10 +6399,11 @@ Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p,
/* Compile the Item we are referencing. */
DBUG_ASSERT((*ref) != NULL);
- Item *new_item= (*ref)->compile(analyzer, arg_p, transformer, arg_t);
+ uchar *arg_v= *arg_p;
+ Item *new_item= (*ref)->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && *ref != new_item)
current_thd->change_item_tree(ref, new_item);
-
+
/* Transform this Item object. */
return (this->*transformer)(arg_t);
}
@@ -7246,6 +7253,130 @@ bool Item_direct_view_ref::eq(const Item *item, bool binary_cmp) const
return FALSE;
}
+
+Item_equal *Item_direct_view_ref::find_item_equal(COND_EQUAL *cond_equal)
+{
+ Item* field_item= real_item();
+ if (field_item->type() != FIELD_ITEM)
+ return NULL;
+ return ((Item_field *) field_item)->find_item_equal(cond_equal);
+}
+
+
+/**
+ Check whether a reference to field item can be substituted for an equal item
+
+ @details
+ The function checks whether a substitution of a reference to field item for
+ an equal item is valid.
+
+ @param arg *arg != NULL && **arg <-> the reference is in the context
+ where substitution for an equal item is valid
+
+ @note
+ See also the note for Item_field::subst_argument_checker
+
+ @retval
+ TRUE substitution is valid
+ @retval
+ FALSE otherwise
+*/
+bool Item_direct_view_ref::subst_argument_checker(uchar **arg)
+{
+ bool res= (!(*arg) && (result_type() != STRING_RESULT)) ||
+ ((*arg) && (**arg));
+ /* Block any substitution into the wrapped object */
+ if (*arg)
+ **arg= (uchar) 0;
+ return res;
+}
+
+
+/**
+ Set a pointer to the multiple equality the view field reference belongs to
+ (if any).
+
+ @details
+ The function looks for a multiple equality containing this item of the type
+ Item_direct_view_ref among those referenced by arg.
+ In the case such equality exists the function does the following.
+ If the found multiple equality contains a constant, then the item
+ is substituted for this constant, otherwise the function sets a pointer
+ to the multiple equality in the item.
+
+ @param arg reference to list of multiple equalities where
+ the item (this object) is to be looked for
+
+ @note
+ This function is supposed to be called as a callback parameter in calls
+ of the compile method.
+
+ @note
+ The function calls Item_field::equal_fields_propagator for the field item
+ this->real_item() to do the job. Then it takes the pointer to equal_item
+ from this field item and assigns it to this->item_equal.
+
+ @return
+ - pointer to the replacing constant item, if the field item was substituted
+ - pointer to the field item, otherwise.
+*/
+
+Item *Item_direct_view_ref::equal_fields_propagator(uchar *arg)
+{
+ Item *field_item= real_item();
+ if (field_item->type() != FIELD_ITEM)
+ return this;
+ Item *item= field_item->equal_fields_propagator(arg);
+ set_item_equal(field_item->get_item_equal());
+ field_item->set_item_equal(NULL);
+ if (item != field_item)
+ return item;
+ return this;
+}
+
+
+/**
+ Replace an Item_direct_view_ref for an equal Item_field evaluated earlier
+ (if any).
+
+ @details
+ If this->item_equal points to some item and coincides with arg then
+ the function returns a pointer to a field item that is referred to by the
+ first element of the item_equal list which the Item_direct_view_ref
+ object belongs to unless item_equal contains a constant item. In this
+ case the function returns this constant item (if the substitution does
+ not require conversion).
+ If the Item_direct_view_item object does not refer any Item_equal object
+ 'this' is returned .
+
+ @param arg NULL or points to so some item of the Item_equal type
+
+ @note
+ This function is supposed to be called as a callback parameter in calls
+ of the transformer method.
+
+ @note
+ The function calls Item_field::replace_equal_field for the field item
+ this->real_item() to do the job.
+
+ @return
+ - pointer to a replacement Item_field if there is a better equal item or
+ a pointer to a constant equal item;
+ - this - otherwise.
+*/
+
+Item *Item_direct_view_ref::replace_equal_field(uchar *arg)
+{
+ Item *field_item= real_item();
+ if (field_item->type() != FIELD_ITEM)
+ return this;
+ field_item->set_item_equal(item_equal);
+ Item *item= field_item->replace_equal_field(arg);
+ field_item->set_item_equal(0);
+ return item;
+}
+
+
bool Item_default_value::eq(const Item *item, bool binary_cmp) const
{
return item->type() == DEFAULT_VALUE_ITEM &&
diff --git a/sql/item.h b/sql/item.h
index 2a98e8c22dc..120ff358098 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -487,6 +487,9 @@ typedef bool (Item::*Item_analyzer) (uchar **argp);
typedef Item* (Item::*Item_transformer) (uchar *arg);
typedef void (*Cond_traverser) (const Item *item, void *arg);
+class Item_equal;
+class COND_EQUAL;
+
class Item {
Item(const Item &); /* Prevent use of these */
@@ -1195,6 +1198,10 @@ public:
bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs);
Item* set_expr_cache(THD *thd, List<Item*> &depends_on);
+
+ virtual Item_equal *get_item_equal() { return NULL; }
+ virtual void set_item_equal(Item_equal *item_eq) {};
+ virtual Item_equal *find_item_equal(COND_EQUAL *cond_equal) { return NULL; }
};
@@ -1626,9 +1633,6 @@ public:
};
-class Item_equal;
-class COND_EQUAL;
-
class Item_field :public Item_ident
{
protected:
@@ -1723,6 +1727,8 @@ public:
{
return field->can_be_compared_as_longlong();
}
+ Item_equal *get_item_equal() { return item_equal; }
+ void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; }
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
bool subst_argument_checker(uchar **arg);
Item *equal_fields_propagator(uchar *arg);
@@ -2739,17 +2745,19 @@ public:
*/
class Item_direct_view_ref :public Item_direct_ref
{
+ Item_equal *item_equal;
public:
Item_direct_view_ref(Name_resolution_context *context_arg, Item **item,
const char *table_name_arg,
const char *field_name_arg)
- :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg) {}
+ :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg),
+ item_equal(0) {}
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_view_ref(THD *thd, Item_direct_ref *item)
- :Item_direct_ref(thd, item) {}
+ :Item_direct_ref(thd, item), item_equal(0) {}
Item_direct_view_ref(TABLE_LIST *view_arg, Item **item,
const char *field_name_arg)
- :Item_direct_ref(view_arg, item, field_name_arg)
+ :Item_direct_ref(view_arg, item, field_name_arg), item_equal(0)
{}
bool fix_fields(THD *, Item **);
@@ -2761,6 +2769,12 @@ public:
return item;
}
virtual Ref_Type ref_type() { return VIEW_REF; }
+ Item_equal *get_item_equal() { return item_equal; }
+ void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; }
+ Item_equal *find_item_equal(COND_EQUAL *cond_equal);
+ bool subst_argument_checker(uchar **arg);
+ Item *equal_fields_propagator(uchar *arg);
+ Item *replace_equal_field(uchar *arg);
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index af0138402a9..cc6f2f41982 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -5525,43 +5525,92 @@ Item *Item_bool_rowready_func2::negated_item()
return 0;
}
-Item_equal::Item_equal(Item_field *f1, Item_field *f2)
- : Item_bool_func(), const_item(0), eval_item(0), cond_false(0),
- compare_as_dates(FALSE)
-{
- const_item_cache= 0;
- fields.push_back(f1);
- fields.push_back(f2);
-}
-Item_equal::Item_equal(Item *c, Item_field *f)
+/**
+ Construct a minimal multiple equality item
+
+ @param f1 the first equal item
+ @param f2 the second equal item
+ @param with_const_item TRUE if the first item is constant
+
+ @details
+ The constructor builds a new item equal object for the equality f1=f2.
+ One of the equal items can be constant. If this is the case it is passed
+ always as the first parameter and the parameter with_const_item serves
+ as an indicator of this case.
+ Currently any non-constant parameter items must point to an item of the
+ of the type Item_field or Item_direct_view_ref(Item_field).
+*/
+
+Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item)
: Item_bool_func(), eval_item(0), cond_false(0)
{
const_item_cache= 0;
- fields.push_back(f);
- const_item= c;
- compare_as_dates= f->is_datetime();
+ with_const= with_const_item;
+ compare_as_dates= with_const_item && f2->is_datetime();
+ equal_items.push_back(f1);
+ equal_items.push_back(f2);
}
+/**
+ Copy constructor for a multiple equality
+
+ @param item_equal source item for the constructor
+
+ @details
+ The function creates a copy of an Item_equal object.
+ This constructor is used when an item belongs to a multiple equality
+ of an upper level (an upper AND/OR level or an upper level of a nested
+ outer join).
+*/
+
Item_equal::Item_equal(Item_equal *item_equal)
: Item_bool_func(), eval_item(0), cond_false(0)
{
const_item_cache= 0;
- List_iterator_fast<Item_field> li(item_equal->fields);
- Item_field *item;
+ List_iterator_fast<Item> li(item_equal->equal_items);
+ Item *item;
while ((item= li++))
{
- fields.push_back(item);
+ equal_items.push_back(item);
}
- const_item= item_equal->const_item;
+ with_const= item_equal->with_const;
compare_as_dates= item_equal->compare_as_dates;
cond_false= item_equal->cond_false;
}
-void Item_equal::compare_const(Item *c)
+/*
+ @brief
+ Add a constant item to the Item_equal object
+
+ @param[in] c the constant to add
+ @param[in] f item from the list equal_items the item c is equal to
+ (this parameter is optional)
+
+ @details
+ The method adds the constant item c to the equal_items list. If the list
+ doesn't have any constant item yet the item c is just put in the front
+ the list. Otherwise the value of c is compared with the value of the
+ constant item from equal_items. If they are not equal cond_false is set
+ to TRUE. This serves as an indicator that this Item_equal is always FALSE.
+ The optional parameter f is used to adjust the flag compare_as_dates.
+*/
+
+void Item_equal::add_const(Item *c, Item *f)
{
+ if (cond_false)
+ return;
+ if (!with_const)
+ {
+ with_const= TRUE;
+ if (f)
+ compare_as_dates= f->is_datetime();
+ equal_items.push_front(c);
+ return;
+ }
+ Item *const_item= get_const();
if (compare_as_dates)
{
cmp.set_datetime_cmp_func(this, &c, &const_item);
@@ -5579,64 +5628,28 @@ void Item_equal::compare_const(Item *c)
}
-void Item_equal::add(Item *c, Item_field *f)
-{
- if (cond_false)
- return;
- if (!const_item)
- {
- DBUG_ASSERT(f);
- const_item= c;
- compare_as_dates= f->is_datetime();
- return;
- }
- compare_const(c);
-}
-
-
-void Item_equal::add(Item *c)
-{
- if (cond_false)
- return;
- if (!const_item)
- {
- const_item= c;
- return;
- }
- compare_const(c);
-}
-
-void Item_equal::add(Item_field *f)
-{
- fields.push_back(f);
-}
-
-uint Item_equal::members()
-{
- return fields.elements;
-}
-
-
/**
- Check whether a field is referred in the multiple equality.
-
- The function checks whether field is occurred in the Item_equal object .
+ @brief
+ Check whether a field is referred to in the multiple equality
@param field field whose occurrence is to be checked
+ @details
+ The function checks whether field is referred to by one of the
+ items from the equal_items list.
+
@retval
- 1 if nultiple equality contains a reference to field
+ 1 if multiple equality contains a reference to field
@retval
0 otherwise
*/
bool Item_equal::contains(Field *field)
{
- List_iterator_fast<Item_field> it(fields);
- Item_field *item;
- while ((item= it++))
+ Item_equal_fields_iterator it(*this);
+ while (it++)
{
- if (field->eq(item->field))
+ if (field->eq(it.get_curr_field()))
return 1;
}
return 0;
@@ -5644,111 +5657,168 @@ bool Item_equal::contains(Field *field)
/**
- Join members of another Item_equal object.
+ @brief
+ Join members of another Item_equal object
- The function actually merges two multiple equalities.
- After this operation the Item_equal object additionally contains
- the field items of another item of the type Item_equal.
- If the optional constant items are not equal the cond_false flag is
- set to 1.
@param item multiple equality whose members are to be joined
+
+ @details
+ The function actually merges two multiple equalities. After this operation
+ the Item_equal object additionally contains the field items of another item of
+ the type Item_equal.
+ If the optional constant items are not equal the cond_false flag is set to TRUE.
+
+ @notes
+ The function is called for any equality f1=f2 such that f1 and f2 are items
+ of the type Item_field or Item_direct_view_ref(Item_field), and, f1->field is
+ referred to in the list this->equal_items, while the list item->equal_items
+ contains a reference to f2->field.
*/
void Item_equal::merge(Item_equal *item)
{
- fields.concat(&item->fields);
- Item *c= item->const_item;
+ Item *c= item->get_const();
+ if (c)
+ item->equal_items.pop();
+ equal_items.concat(&item->equal_items);
if (c)
{
/*
- The flag cond_false will be set to 1 after this, if
+ The flag cond_false will be set to TRUE after this if
the multiple equality already contains a constant and its
- value is not equal to the value of c.
+ value is not equal to the value of c.
*/
- add(c);
+ add_const(c);
}
cond_false|= item->cond_false;
}
/**
- Order field items in multiple equality according to a sorting criteria.
+ @brief
+ Order equal items of the multiple equality according to a sorting criteria
- The function perform ordering of the field items in the Item_equal
- object according to the criteria determined by the cmp callback parameter.
- If cmp(item_field1,item_field2,arg)<0 than item_field1 must be
- placed after item_fiel2.
+ @param compare function to compare items from the equal_items list
+ @param arg context extra parameter for the cmp function
- The function sorts field items by the bubble sort algorithm.
+ @details
+ The function performs ordering of the items from the equal_items list
+ according to the criteria determined by the cmp callback parameter.
+ If cmp(item1,item2,arg)<0 than item1 must be placed after item2.
+
+ @notes
+ The function sorts equal items by the bubble sort algorithm.
The list of field items is looked through and whenever two neighboring
members follow in a wrong order they are swapped. This is performed
again and again until we get all members in a right order.
-
- @param compare function to compare field item
- @param arg context extra parameter for the cmp function
*/
void Item_equal::sort(Item_field_cmpfunc compare, void *arg)
{
- bubble_sort<Item_field>(&fields, compare, arg);
+ bubble_sort<Item>(&equal_items, compare, arg);
}
/**
- Check appearance of new constant items in the multiple equality object.
+ @brief
+ Check appearance of new constant items in the multiple equality object
- The function checks appearance of new constant items among
- the members of multiple equalities. Each new constant item is
- compared with the designated constant item if there is any in the
- multiple equality. If there is none the first new constant item
- becomes designated.
+ @details
+ The function checks appearance of new constant items among the members
+ of the equal_items list. Each new constant item is compared with
+ the constant item from the list if there is any. If there is none the first
+ new constant item is placed at the very beginning of the list and
+ with_const is set to TRUE. If it happens that the compared constant items
+ are unequal then the flag cond_false is set to TRUE.
+
+ @notes
+ Currently this function is called only after substitution of constant tables.
*/
void Item_equal::update_const()
{
- List_iterator<Item_field> it(fields);
- Item *item;
- while ((item= it++))
+ List_iterator<Item> it(equal_items);
+ if (with_const)
+ it++;
+ Item *item= it++;
+ while (item)
{
if (item->const_item())
{
it.remove();
- add(item);
+ Item *next_item= it++;
+ add_const(item);
+ item= next_item;
}
+ else
+ item= it++;
}
}
+
+/**
+ @brief
+ Fix fields in a completely built multiple equality
+
+ @param thd currently not used thread handle
+ @param ref not used
+
+ @details
+ This function is called once the multiple equality has been built out of
+ the WHERE/ON condition and no new members are expected to be added to the
+ equal_items list anymore.
+ As any implementation of the virtual fix_fields method the function
+ calculates the cached values of not_null_tables_cache, used_tables_cache,
+ const_item_cache and calls fix_length_and_dec().
+ Additionally the function sets a reference to the Item_equal object in
+ the non-constant items of the equal_items list unless such a reference has
+ been already set.
+
+ @notes
+ Currently this function is called only in the function
+ build_equal_items_for_cond.
+
+ @retval
+ FALSE always
+*/
+
bool Item_equal::fix_fields(THD *thd, Item **ref)
-{
- List_iterator_fast<Item_field> li(fields);
- Item_field *item;
+{
+ DBUG_ASSERT(fixed == 0);
+ Item_equal_fields_iterator it(*this);
+ Item *item;
not_null_tables_cache= used_tables_cache= 0;
const_item_cache= 0;
- while ((item= li++))
+ while ((item= it++))
{
table_map tmp_table_map;
used_tables_cache|= item->used_tables();
tmp_table_map= item->not_null_tables();
not_null_tables_cache|= tmp_table_map;
if (item->maybe_null)
- maybe_null=1;
- if (!item->item_equal)
- item->item_equal= this;
+ maybe_null= 1;
+ if (!item->get_item_equal())
+ item->set_item_equal(this);
}
fix_length_and_dec();
fixed= 1;
- return 0;
+ return FALSE;
}
+
+/**
+ Update the value of the used table attribute and other attributes
+ */
+
void Item_equal::update_used_tables()
{
- List_iterator_fast<Item_field> li(fields);
- Item *item;
not_null_tables_cache= used_tables_cache= 0;
if ((const_item_cache= cond_false))
return;
+ Item_equal_fields_iterator it(*this);
+ Item *item;
const_item_cache= 1;
- while ((item=li++))
+ while ((item= it++))
{
item->update_used_tables();
used_tables_cache|= item->used_tables();
@@ -5756,28 +5826,54 @@ void Item_equal::update_used_tables()
}
}
+
+
+/**
+ @brief
+ Evaluate multiple equality
+
+ @details
+ The function evaluate multiple equality to a boolean value.
+ The function ignores non-constant items from the equal_items list.
+ The function returns 1 if all constant items from the list are equal.
+ It returns 0 if there are unequal constant items in the list or
+ one of the constant items is evaluated to NULL.
+
+ @notes
+ Currently this function can be called only at the optimization
+ stage after the constant table substitution, since all Item_equals
+ are eliminated before the execution stage.
+
+ @retval
+ 0 multiple equality is always FALSE or NULL
+ 1 otherwise
+*/
+
longlong Item_equal::val_int()
{
- Item_field *item_field;
if (cond_false)
return 0;
- List_iterator_fast<Item_field> it(fields);
- Item *item= const_item ? const_item : it++;
- if ((null_value= item->is_null()))
- return 0;
+ Item *item= get_const();
+ Item_equal_fields_iterator it(*this);
+ if (!item)
+ item= it++;
eval_item->store_value(item);
- while ((item_field= it++))
+ if ((null_value= item->null_value))
+ return 0;
+ while ((item= it++))
{
+ Field *field= it.get_curr_field();
/* Skip fields of non-const tables. They haven't been read yet */
- if (item_field->field->table->const_table)
+ if (field->table->const_table)
{
- if ((null_value= item_field->is_null()) || eval_item->cmp(item_field))
+ if (eval_item->cmp(item) || (null_value= item->null_value))
return 0;
}
}
return 1;
}
+
void Item_equal::fix_length_and_dec()
{
Item *item= get_first(NULL);
@@ -5785,10 +5881,11 @@ void Item_equal::fix_length_and_dec()
item->collation.collation);
}
+
bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
- List_iterator_fast<Item_field> it(fields);
Item *item;
+ Item_equal_fields_iterator it(*this);
while ((item= it++))
{
if (item->walk(processor, walk_subquery, arg))
@@ -5797,12 +5894,13 @@ bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
return Item_func::walk(processor, walk_subquery, arg);
}
+
Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
- List_iterator<Item_field> it(fields);
Item *item;
+ Item_equal_fields_iterator it(*this);
while ((item= it++))
{
Item *new_item= item->transform(transformer, arg);
@@ -5821,19 +5919,15 @@ Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
return Item_func::transform(transformer, arg);
}
+
void Item_equal::print(String *str, enum_query_type query_type)
{
str->append(func_name());
str->append('(');
- List_iterator_fast<Item_field> it(fields);
+ List_iterator_fast<Item> it(equal_items);
Item *item;
- if (const_item)
- const_item->print(str, query_type);
- else
- {
- item= it++;
- item->print(str, query_type);
- }
+ item= it++;
+ item->print(str, query_type);
while ((item= it++))
{
str->append(',');
@@ -5844,6 +5938,14 @@ void Item_equal::print(String *str, enum_query_type query_type)
}
+CHARSET_INFO *Item_equal::compare_collation()
+{
+ Item_equal_fields_iterator it(*this);
+ Item *item= it++;
+ return item->collation.collation;
+}
+
+
/*
@brief Get the first equal field of multiple equality.
@param[in] field the field to get equal field to
@@ -5869,13 +5971,14 @@ void Item_equal::print(String *str, enum_query_type query_type)
@retval 0 if no field found.
*/
-Item_field* Item_equal::get_first(Item_field *field)
+Item* Item_equal::get_first(Item *field_item)
{
- List_iterator<Item_field> it(fields);
- Item_field *item;
+ Item_equal_fields_iterator it(*this);
+ Item *item;
JOIN_TAB *field_tab;
- if (!field)
- return fields.head();
+ if (!field_item)
+ return (it++);
+ Field *field= ((Item_field *) (field_item->real_item()))->field;
/*
Of all equal fields, return the first one we can use. Normally, this is the
@@ -5897,9 +6000,9 @@ Item_field* Item_equal::get_first(Item_field *field)
in presense of SJM nests.
*/
- field_tab= field->field->table->reginfo.join_tab;
+ field_tab= field->table->reginfo.join_tab;
- TABLE_LIST *emb_nest= field->field->table->pos_in_table_list->embedding;
+ TABLE_LIST *emb_nest= field->table->pos_in_table_list->embedding;
if (emb_nest && emb_nest->sj_mat_info && emb_nest->sj_mat_info->is_used)
{
@@ -5926,13 +6029,13 @@ Item_field* Item_equal::get_first(Item_field *field)
/* Find an item to substitute for. */
while ((item= it++))
{
- if (item->field->table->reginfo.join_tab >= first)
+ if (it.get_curr_field()->table->reginfo.join_tab >= first)
{
/*
If we found given field then return NULL to avoid unnecessary
substitution.
*/
- return (item != field) ? item : NULL;
+ return (item != field_item) ? item : NULL;
}
}
}
@@ -5956,7 +6059,8 @@ Item_field* Item_equal::get_first(Item_field *field)
*/
while ((item= it++))
{
- TABLE_LIST *emb_nest= item->field->table->pos_in_table_list->embedding;
+ Item_field *fld_item= (Item_field *) (item->real_item());
+ TABLE_LIST *emb_nest= fld_item->field->table->pos_in_table_list->embedding;
if (!emb_nest || !emb_nest->sj_mat_info ||
!emb_nest->sj_mat_info->is_used)
{
@@ -5964,7 +6068,7 @@ Item_field* Item_equal::get_first(Item_field *field)
}
}
#endif
- return fields.head();
+ return equal_items.head();
}
// Shouldn't get here.
DBUG_ASSERT(0);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 2e5e4df6c2c..9f4efbc08be 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -26,7 +26,7 @@ class Arg_comparator;
typedef int (Arg_comparator::*arg_cmp_func)();
-typedef int (*Item_field_cmpfunc)(Item_field *f1, Item_field *f2, void *arg);
+typedef int (*Item_field_cmpfunc)(Item *f1, Item *f2, void *arg);
class Arg_comparator: public Sql_alloc
{
@@ -1614,28 +1614,64 @@ public:
class Item_equal: public Item_bool_func
{
- List<Item_field> fields; /* list of equal field items */
- Item *const_item; /* optional constant item equal to fields items */
+ /*
+ The list of equal items. Currently the list can contain:
+ - Item_fields items for references to table columns
+ - Item_direct_view_ref items for references to view columns
+ - one const item
+
+ If the list contains a constant item this item is always first in the list.
+ The list contains at least two elements.
+ Currently all Item_fields/Item_direct_view_ref items in the list should
+ refer to table columns with equavalent type definitions. In particular
+ if these are string columns they should have the same charset/collation.
+
+ Use objects of the companion class Item_equal_fields_iterator to iterate
+ over all items from the list of the Item_field/Item_direct_view_ref classes.
+ */
+ List<Item> equal_items;
+ /*
+ TRUE <-> one of the items is a const item.
+ Such item is always first in in the equal_items list
+ */
+ bool with_const;
+ /*
+ The field eval_item is used when this item is evaluated
+ with the method val_int()
+ */
cmp_item *eval_item;
- Arg_comparator cmp;
+ /*
+ This initially is set to FALSE. It becomes TRUE when this item is evaluated
+ as being always false. If the flag is TRUE the contents of the list
+ the equal_items should be ignored.
+ */
bool cond_false;
+ /*
+ compare_as_dates=TRUE <-> constants equal to fields from equal_items
+ must be compared as datetimes and not as strings.
+ compare_as_dates can be TRUE only if with_const=TRUE
+ */
bool compare_as_dates;
+ /*
+ The comparator used to compare constants equal to fields from equal_items
+ as datetimes. The comparator is used only if compare_as_dates=TRUE
+ */
+ Arg_comparator cmp;
public:
inline Item_equal()
- : Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
+ : Item_bool_func(), with_const(FALSE), eval_item(0), cond_false(0)
{ const_item_cache=0 ;}
- Item_equal(Item_field *f1, Item_field *f2);
- Item_equal(Item *c, Item_field *f);
+ Item_equal(Item *f1, Item *f2, bool with_const_item);
Item_equal(Item_equal *item_equal);
- inline Item* get_const() { return const_item; }
- void compare_const(Item *c);
- void add(Item *c, Item_field *f);
- void add(Item *c);
- void add(Item_field *f);
- uint members();
+ /* Currently the const item is always the first in the list of equal items */
+ inline Item* get_const() { return with_const ? equal_items.head() : NULL; }
+ void add_const(Item *c, Item *f = NULL);
+ /** Add a non-constant item to the multiple equality */
+ void add(Item *f) { equal_items.push_back(f); }
bool contains(Field *field);
- Item_field* get_first(Item_field *field);
- uint n_fields() { return fields.elements; }
+ Item* get_first(Item *field);
+ /** Get number of field items / references to field items in this object */
+ uint n_field_items() { return equal_items.elements-test(with_const); }
void merge(Item_equal *item);
void update_const();
enum Functype functype() const { return MULT_EQUAL_FUNC; }
@@ -1643,15 +1679,14 @@ public:
const char *func_name() const { return "multiple equal"; }
optimize_type select_optimize() const { return OPTIMIZE_EQUAL; }
void sort(Item_field_cmpfunc compare, void *arg);
- friend class Item_equal_iterator;
void fix_length_and_dec();
bool fix_fields(THD *thd, Item **ref);
void update_used_tables();
bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
Item *transform(Item_transformer transformer, uchar *arg);
virtual void print(String *str, enum_query_type query_type);
- CHARSET_INFO *compare_collation()
- { return fields.head()->collation.collation; }
+ CHARSET_INFO *compare_collation();
+ friend class Item_equal_fields_iterator;
friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
Item_equal *item_equal);
friend bool setup_sj_materialization(struct st_join_table *tab);
@@ -1672,23 +1707,52 @@ public:
};
-class Item_equal_iterator : public List_iterator_fast<Item_field>
+/*
+ The class Item_equal_fields_iterator is used to iterate over references
+ to table/view columns from a list of equal items.
+*/
+
+class Item_equal_fields_iterator : public List_iterator_fast<Item>
{
+ Item_equal *item_equal;
+ Item *curr_item;
public:
- inline Item_equal_iterator(Item_equal &item_equal)
- :List_iterator_fast<Item_field> (item_equal.fields)
- {}
- inline Item_field* operator++(int)
- {
- Item_field *item= (*(List_iterator_fast<Item_field> *) this)++;
- return item;
+ Item_equal_fields_iterator(Item_equal &item_eq)
+ :List_iterator_fast<Item> (item_eq.equal_items)
+ {
+ curr_item= NULL;
+ item_equal= &item_eq;
+ if (item_eq.with_const)
+ {
+ List_iterator_fast<Item> *list_it= this;
+ curr_item= (*list_it)++;
+ }
}
- inline void rewind(void)
+ Item* operator++(int)
{
- List_iterator_fast<Item_field>::rewind();
+ List_iterator_fast<Item> *list_it= this;
+ curr_item= (*list_it)++;
+ return curr_item;
+ }
+ Item ** ref()
+ {
+ return List_iterator_fast<Item>::ref();
}
+ void rewind(void)
+ {
+ List_iterator_fast<Item> *list_it= this;
+ list_it->rewind();
+ if (item_equal->with_const)
+ curr_item= (*list_it)++;
+ }
+ Field *get_curr_field()
+ {
+ Item_field *item= (Item_field *) (curr_item->real_item());
+ return item->field;
+ }
};
+
class Item_cond_and :public Item_cond
{
public:
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 0eb1bd3ce36..8d0d1c03ee5 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -7104,11 +7104,10 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
Item_equal *item_equal= field_item->item_equal;
if (item_equal)
{
- Item_equal_iterator it(*item_equal);
- Item_field *item;
- while ((item= it++))
+ Item_equal_fields_iterator it(*item_equal);
+ while (it++)
{
- Field *f= item->field;
+ Field *f= it.get_curr_field();
if (field->eq(f))
continue;
if (!((ref_tables | f->table->map) & param_comp))
@@ -7259,11 +7258,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
Item_equal *item_equal= (Item_equal *) cond;
if (!(value= item_equal->get_const()))
DBUG_RETURN(0);
- Item_equal_iterator it(*item_equal);
+ Item_equal_fields_iterator it(*item_equal);
ref_tables= value->used_tables();
- while ((field_item= it++))
+ while (it++)
{
- Field *field= field_item->field;
+ Field *field= it.get_curr_field();
Item_result cmp_type= field->cmp_type();
if (!((ref_tables | field->table->map) & param_comp))
{
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 75ff73b81b1..e12412299c5 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -2386,13 +2386,13 @@ bool setup_sj_materialization(JOIN_TAB *tab)
if (item_eq)
{
- List_iterator<Item_field> it(item_eq->fields);
- Item_field *item;
+ List_iterator<Item> it(item_eq->equal_items);
+ Item *item;
while ((item= it++))
{
if (!(item->used_tables() & ~emb_sj_nest->sj_inner_tables))
{
- copy_to= item->field;
+ copy_to= ((Item_field *) (item->real_item()))->field;
break;
}
}
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 0c2e41225ba..310b48756d0 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -473,7 +473,7 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
/* MULT_EQUAL_FUNC */
{
Item_equal *item_equal= (Item_equal *) func_item;
- Item_equal_iterator it(*item_equal);
+ Item_equal_fields_iterator it(*item_equal);
args[0]= it++;
if (it++)
return 0;
diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc
index 7497395d628..c8c61720068 100644
--- a/sql/opt_table_elimination.cc
+++ b/sql/opt_table_elimination.cc
@@ -1208,15 +1208,16 @@ void build_eq_mods_for_cond(Dep_analysis_context *ctx,
if (!(fvl= new List<Dep_value_field>))
break; /* purecov: inspected */
- Item_equal_iterator it(*item_equal);
- Item_field *item;
+ Item_equal_fields_iterator it(*item_equal);
+ Item *item;
Item *bound_item= item_equal->get_const();
while ((item= it++))
{
+ Field *equal_field= it.get_curr_field();
if ((item->used_tables() & ctx->usable_tables))
{
Dep_value_field *field_val;
- if ((field_val= ctx->get_field_value(item->field)))
+ if ((field_val= ctx->get_field_value(equal_field)))
fvl->push_back(field_val);
}
else
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 118e14cf346..c23318975dc 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3764,28 +3764,28 @@ add_key_field(JOIN *join,
static void
add_key_equal_fields(JOIN *join, KEY_FIELD **key_fields, uint and_level,
- Item_func *cond, Item_field *field_item,
+ Item_func *cond, Item *field_item,
bool eq_func, Item **val,
uint num_values, table_map usable_tables,
SARGABLE_PARAM **sargables)
{
- Field *field= field_item->field;
+ Field *field= ((Item_field *) (field_item->real_item()))->field;
add_key_field(join, key_fields, and_level, cond, field,
eq_func, val, num_values, usable_tables, sargables);
- Item_equal *item_equal= field_item->item_equal;
+ Item_equal *item_equal= field_item->get_item_equal();
if (item_equal)
{
/*
Add to the set of possible key values every substitution of
the field for an equal field included into item_equal
*/
- Item_equal_iterator it(*item_equal);
- Item_field *item;
- while ((item= it++))
+ Item_equal_fields_iterator it(*item_equal);
+ while (it++)
{
- if (!field->eq(item->field))
+ Field *equal_field= it.get_curr_field();
+ if (!field->eq(equal_field))
{
- add_key_field(join, key_fields, and_level, cond, item->field,
+ add_key_field(join, key_fields, and_level, cond, equal_field,
eq_func, val, num_values, usable_tables,
sargables);
}
@@ -3982,8 +3982,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
case Item_func::OPTIMIZE_EQUAL:
Item_equal *item_equal= (Item_equal *) cond;
Item *const_item= item_equal->get_const();
- Item_equal_iterator it(*item_equal);
- Item_field *item;
+ Item_equal_fields_iterator it(*item_equal);
if (const_item)
{
/*
@@ -3991,9 +3990,10 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
field1=const_item as a condition allowing an index access of the table
with field1 by the keys value of field1.
*/
- while ((item= it++))
+ while (it++)
{
- add_key_field(join, key_fields, *and_level, cond_func, item->field,
+ Field *equal_field= it.get_curr_field();
+ add_key_field(join, key_fields, *and_level, cond_func, equal_field,
TRUE, &const_item, 1, usable_tables, sargables);
}
}
@@ -4005,17 +4005,18 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
field1=field2 as a condition allowing an index access of the table
with field1 by the keys value of field2.
*/
- Item_equal_iterator fi(*item_equal);
- while ((item= fi++))
+ Item_equal_fields_iterator fi(*item_equal);
+ while (fi++)
{
- Field *field= item->field;
+ Field *field= fi.get_curr_field();
+ Item *item;
while ((item= it++))
{
- if (!field->eq(item->field))
+ Field *equal_field= it.get_curr_field();
+ if (!field->eq(equal_field))
{
- Item *tmp_item= item;
add_key_field(join, key_fields, *and_level, cond_func, field,
- TRUE, &tmp_item, 1, usable_tables,
+ TRUE, &item, 1, usable_tables,
sargables);
}
}
@@ -9291,6 +9292,8 @@ finish:
static bool check_simple_equality(Item *left_item, Item *right_item,
Item *item, COND_EQUAL *cond_equal)
{
+ Item *orig_left_item= left_item;
+ Item *orig_right_item= right_item;
if (left_item->type() == Item::REF_ITEM &&
((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF)
{
@@ -9357,7 +9360,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
{
/* left item was found in the current or one of the upper levels */
if (! right_item_equal)
- left_item_equal->add((Item_field *) right_item);
+ left_item_equal->add(orig_right_item);
else
{
/* Merge two multiple equalities forming a new one */
@@ -9372,12 +9375,13 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
{
/* left item was not found neither the current nor in upper levels */
if (right_item_equal)
- right_item_equal->add((Item_field *) left_item);
+ right_item_equal->add(orig_left_item);
else
{
/* None of the fields was found in multiple equalities */
- Item_equal *item_equal= new Item_equal((Item_field *) left_item,
- (Item_field *) right_item);
+ Item_equal *item_equal= new Item_equal(orig_left_item,
+ orig_right_item,
+ FALSE);
cond_equal->current_level.push_back(item_equal);
}
}
@@ -9388,18 +9392,21 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
/* The predicate of the form field=const/const=field is processed */
Item *const_item= 0;
Item_field *field_item= 0;
+ Item *orig_field_item= 0;
if (left_item->type() == Item::FIELD_ITEM &&
!((Item_field*)left_item)->depended_from &&
right_item->const_item())
{
- field_item= (Item_field*) left_item;
+ orig_field_item= left_item;
+ field_item= (Item_field *) left_item;
const_item= right_item;
}
else if (right_item->type() == Item::FIELD_ITEM &&
!((Item_field*)right_item)->depended_from &&
left_item->const_item())
{
- field_item= (Item_field*) right_item;
+ orig_field_item= right_item;
+ field_item= (Item_field *) right_item;
const_item= left_item;
}
@@ -9414,7 +9421,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
if (!item)
{
Item_func_eq *eq_item;
- if ((eq_item= new Item_func_eq(left_item, right_item)))
+ if ((eq_item= new Item_func_eq(orig_left_item, orig_right_item)))
return FALSE;
eq_item->set_cmp_func();
eq_item->quick_fix_field();
@@ -9439,11 +9446,11 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
already contains a constant and its value is not equal to
the value of const_item.
*/
- item_equal->add(const_item, field_item);
+ item_equal->add_const(const_item, orig_field_item);
}
else
{
- item_equal= new Item_equal(const_item, field_item);
+ item_equal= new Item_equal(const_item, orig_field_item, TRUE);
cond_equal->current_level.push_back(item_equal);
}
return TRUE;
@@ -9688,7 +9695,7 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
item_equal->fix_fields(thd, NULL);
item_equal->update_used_tables();
set_if_bigger(thd->lex->current_select->max_equal_elems,
- item_equal->members());
+ item_equal->n_field_items());
}
((Item_cond_and*)cond)->cond_equal= cond_equal;
@@ -9719,7 +9726,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
args->concat((List<Item> *)&cond_equal.current_level);
}
}
- else if (cond->type() == Item::FUNC_ITEM)
+ else if (cond->type() == Item::FUNC_ITEM ||
+ cond->real_item()->type() == Item::FIELD_ITEM)
{
List<Item> eq_list;
/*
@@ -9741,10 +9749,10 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
{
if ((item_equal= cond_equal.current_level.pop()))
{
- item_equal->fix_length_and_dec();
+ item_equal->fix_fields(thd, NULL);
item_equal->update_used_tables();
set_if_bigger(thd->lex->current_select->max_equal_elems,
- item_equal->members());
+ item_equal->n_field_items());
return item_equal;
}
@@ -9765,7 +9773,7 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
item_equal->fix_length_and_dec();
item_equal->update_used_tables();
set_if_bigger(thd->lex->current_select->max_equal_elems,
- item_equal->members());
+ item_equal->n_field_items());
}
and_cond->cond_equal= cond_equal;
args->concat((List<Item> *)&cond_equal.current_level);
@@ -9779,9 +9787,10 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
as soon the field is not of a string type or the field reference is
an argument of a comparison predicate.
*/
- uchar *is_subst_valid= (uchar *) 1;
+ uchar is_subst_valid= (uchar) 1;
+ uchar *is_subst_valid_ptr= &is_subst_valid;
cond= cond->compile(&Item::subst_argument_checker,
- &is_subst_valid,
+ &is_subst_valid_ptr,
&Item::equal_fields_propagator,
(uchar *) inherited);
cond->update_used_tables();
@@ -9935,18 +9944,24 @@ static COND *build_equal_items(THD *thd, COND *cond,
0 otherwise
*/
-static int compare_fields_by_table_order(Item_field *field1,
- Item_field *field2,
+static int compare_fields_by_table_order(Item *field1,
+ Item *field2,
void *table_join_idx)
{
int cmp= 0;
bool outer_ref= 0;
- if (field2->used_tables() & OUTER_REF_TABLE_BIT)
+ Item_field *f1= (Item_field *) (field1->real_item());
+ Item_field *f2= (Item_field *) (field2->real_item());
+ if (f1->const_item())
+ return 1;
+ if (f2->const_item())
+ return -1;
+ if (f2->used_tables() & OUTER_REF_TABLE_BIT)
{
outer_ref= 1;
cmp= -1;
}
- if (field1->used_tables() & OUTER_REF_TABLE_BIT)
+ if (f1->used_tables() & OUTER_REF_TABLE_BIT)
{
outer_ref= 1;
cmp++;
@@ -9954,10 +9969,10 @@ static int compare_fields_by_table_order(Item_field *field1,
if (outer_ref)
return cmp;
JOIN_TAB **idx= (JOIN_TAB **) table_join_idx;
- cmp= idx[field2->field->table->tablenr]-idx[field1->field->table->tablenr];
+ cmp= idx[f2->field->table->tablenr]-idx[f1->field->table->tablenr];
if (!cmp)
{
- JOIN_TAB *tab= idx[field1->field->table->tablenr];
+ JOIN_TAB *tab= idx[f1->field->table->tablenr];
uint keyno= MAX_KEY;
if (tab->ref.key_parts)
keyno= tab->ref.key;
@@ -9965,9 +9980,9 @@ static int compare_fields_by_table_order(Item_field *field1,
keyno = tab->select->quick->index;
if (keyno != MAX_KEY)
{
- if (field2->field->part_of_key.is_set(keyno))
+ if (f2->field->part_of_key.is_set(keyno))
cmp= -1;
- if (field1->field->part_of_key.is_set(keyno))
+ if (f1->field->part_of_key.is_set(keyno))
cmp++;
if (!cmp)
{
@@ -9975,12 +9990,12 @@ static int compare_fields_by_table_order(Item_field *field1,
for (uint i= 0; i < key_info->key_parts; i++)
{
Field *fld= key_info->key_part[i].field;
- if (fld->eq(field2->field))
+ if (fld->eq(f2->field))
{
cmp= -1;
break;
}
- if (fld->eq(field1->field))
+ if (fld->eq(f1->field))
{
cmp= 1;
break;
@@ -9989,14 +10004,15 @@ static int compare_fields_by_table_order(Item_field *field1,
}
}
else
- cmp= field2->field->field_index-field1->field->field_index;
+ cmp= f2->field->field_index-f1->field->field_index;
}
return cmp < 0 ? -1 : (cmp ? 1 : 0);
}
-static TABLE_LIST* embedding_sjm(Item_field *item_field)
+static TABLE_LIST* embedding_sjm(Item *item)
{
+ Item_field *item_field= (Item_field *) (item->real_item());
TABLE_LIST *nest= item_field->field->table->pos_in_table_list->embedding;
if (nest && nest->sj_mat_info && nest->sj_mat_info->is_used)
return nest;
@@ -10069,7 +10085,7 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
if (((Item *) item_equal)->const_item() && !item_equal->val_int())
return new Item_int((longlong) 0,1);
Item *item_const= item_equal->get_const();
- Item_equal_iterator it(*item_equal);
+ Item_equal_fields_iterator it(*item_equal);
Item *head;
DBUG_ASSERT(!cond || cond->type() == Item::COND_ITEM);
@@ -10085,27 +10101,26 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
else
{
TABLE_LIST *emb_nest;
- Item_field *item_field;
- head= item_field= item_equal->get_first(NULL);
+ head= item_equal->get_first(NULL);
it++;
- if ((emb_nest= embedding_sjm(item_field)))
+ if ((emb_nest= embedding_sjm(head)))
{
current_sjm= emb_nest;
current_sjm_head= head;
}
}
- Item_field *item_field;
+ Item *field_item;
/*
For each other item, generate "item=head" equality (except the tables that
are within SJ-Materialization nests, for those "head" is defined
differently)
*/
- while ((item_field= it++))
+ while ((field_item= it++))
{
- Item_equal *upper= item_field->find_item_equal(upper_levels);
- Item_field *item= item_field;
- TABLE_LIST *field_sjm= embedding_sjm(item_field);
+ Item_equal *upper= field_item->find_item_equal(upper_levels);
+ Item *item= field_item;
+ TABLE_LIST *field_sjm= embedding_sjm(field_item);
if (!field_sjm)
{
current_sjm= NULL;
@@ -10122,8 +10137,8 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
item= 0;
else
{
- Item_equal_iterator li(*item_equal);
- while ((item= li++) != item_field)
+ Item_equal_fields_iterator li(*item_equal);
+ while ((item= li++) != field_item)
{
if (item->find_item_equal(upper_levels) == upper)
break;
@@ -10131,11 +10146,11 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
}
}
- bool produce_equality= test(item == item_field);
+ bool produce_equality= test(item == field_item);
if (!item_const && field_sjm && field_sjm != current_sjm)
{
/* Entering an SJM nest */
- current_sjm_head= item_field;
+ current_sjm_head= field_item;
if (!field_sjm->sj_mat_info->is_sj_scan)
produce_equality= FALSE;
}
@@ -10144,8 +10159,13 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
{
if (eq_item)
eq_list.push_back(eq_item);
+
+ Item *head_item= current_sjm? current_sjm_head: head;
+ Item *head_real_item= head_item->real_item();
+ if (head_real_item->type() == Item::FIELD_ITEM)
+ head_item= head_real_item;
- eq_item= new Item_func_eq(item_field, current_sjm? current_sjm_head: head);
+ eq_item= new Item_func_eq(field_item->real_item(), head_item);
if (!eq_item)
return 0;
@@ -10330,11 +10350,10 @@ static void update_const_equal_items(COND *cond, JOIN_TAB *tab)
if (!contained_const && item_equal->get_const())
{
/* Update keys for range analysis */
- Item_equal_iterator it(*item_equal);
- Item_field *item_field;
- while ((item_field= it++))
+ Item_equal_fields_iterator it(*item_equal);
+ while (it++)
{
- Field *field= item_field->field;
+ Field *field= it.get_curr_field();
JOIN_TAB *stat= field->table->reginfo.join_tab;
key_map possible_keys= field->key_start;
possible_keys.intersect(field->table->keys_in_use_for_query);