diff options
author | Igor Babaev <igor@askmonty.org> | 2011-04-26 21:11:06 -0700 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2011-04-26 21:11:06 -0700 |
commit | 24edac2211c46ea9ebeb4a13bc467fb20008916e (patch) | |
tree | e882cd519a70e326be9086468c7a6113102bf7f8 | |
parent | 79439d9a7447aac68bba7d68c2d3bf76cc319fdb (diff) | |
parent | 8d9dd21d85e257051b45b2f779dcd9bf696bf9e1 (diff) | |
download | mariadb-git-24edac2211c46ea9ebeb4a13bc467fb20008916e.tar.gz |
Merge
-rw-r--r-- | mysql-test/r/view.result | 155 | ||||
-rw-r--r-- | mysql-test/t/view.test | 74 | ||||
-rw-r--r-- | sql/item.cc | 151 | ||||
-rw-r--r-- | sql/item.h | 26 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 372 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 120 | ||||
-rw-r--r-- | sql/opt_range.cc | 13 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 6 | ||||
-rw-r--r-- | sql/opt_sum.cc | 2 | ||||
-rw-r--r-- | sql/opt_table_elimination.cc | 7 | ||||
-rw-r--r-- | sql/sql_select.cc | 147 |
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); |