diff options
author | Igor Babaev <igor@askmonty.org> | 2011-04-26 19:58:41 -0700 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2011-04-26 19:58:41 -0700 |
commit | 8d9dd21d85e257051b45b2f779dcd9bf696bf9e1 (patch) | |
tree | 8a848ea3c6c25075015261314a0f2e128dee4149 /sql | |
parent | bbd4bb310d7b500a57be56b8f0501fa8eee6d40f (diff) | |
download | mariadb-git-8d9dd21d85e257051b45b2f779dcd9bf696bf9e1.tar.gz |
Fixed LP bugs #717577, #724942.
Both these two bugs happened due to the following problem.
When a view column is referenced in the query an Item_direct_view_ref
object is created that is refers to the Item_field for the column.
All references to the same view column refer to the same Item_field.
Different references can belong to different AND/OR levels and,
as a result, can be included in different Item_equal object.
These Item_equal objects may include different constant objects.
If these constant objects are substituted for the Item_field created
for a view column we have a conflict situation when the second
substitution annuls the first substitution. This leads to
wrong result sets returned by the query. Bug #724942 demonstrates
such an erroneous behaviour.
Test case of the bug #717577 produces wrong result sets because best
equal fields of the multiple equalities built for different OR levels
of the WHERE condition differs. The subsitution for the best equal field
in the second OR branch overwrites the the substitution made for the
first branch.
To avoid such conflicts we have to substitute for the references
to the view columns rather than for the underlying field items.
To make such substitutions possible we have to include into
multiple equalities references to view columns rather than
field items created for such columns.
This patch modifies the Item_equal class to include references
to view columns into multiple equality objects. It also performs
a clean up of the class methods and adds more comments. The methods
of the Item_direct_view_ref class that assist substitutions for
references to view columns has been also added by this patch.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 151 | ||||
-rw-r--r-- | sql/item.h | 27 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 371 | ||||
-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 |
9 files changed, 588 insertions, 256 deletions
diff --git a/sql/item.cc b/sql/item.cc index 0b367fe2477..f68ec5558df 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4670,13 +4670,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: @@ -4701,7 +4702,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)); } @@ -4738,6 +4740,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. @@ -4814,6 +4817,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 @@ -4828,7 +4832,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 @@ -4848,7 +4852,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; } @@ -6377,10 +6383,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); } @@ -7226,6 +7233,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 08b283b6903..811ebacef46 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 */ @@ -1179,6 +1182,9 @@ public: Item* set_expr_cache(THD *thd, List<Item*> &depends_on); virtual Item *get_cached_item() { return NULL; } + 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; } }; @@ -1610,9 +1616,6 @@ public: }; -class Item_equal; -class COND_EQUAL; - class Item_field :public Item_ident { protected: @@ -1707,6 +1710,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); @@ -2405,7 +2410,7 @@ public: const char *db_arg, const char *table_name_arg, const char *field_name_arg) :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg), - result_field(0), ref(0) {} + result_field(0), ref(0) {} /* This constructor is used in two scenarios: A) *item = NULL @@ -2720,17 +2725,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 **); @@ -2742,6 +2749,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 be281d4b62c..eadcb610b92 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5516,43 +5516,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); @@ -5570,64 +5619,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; @@ -5635,110 +5648,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; - 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(); @@ -5746,28 +5817,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); @@ -5775,10 +5872,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)) @@ -5787,12 +5885,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); @@ -5811,19 +5910,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(','); @@ -5834,6 +5929,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 @@ -5859,13 +5962,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 @@ -5887,9 +5991,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) { @@ -5916,13 +6020,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; } } } @@ -5946,7 +6050,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) { @@ -5954,7 +6059,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 8a62f69de1f..59888d778ca 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 6c9ed241de2..7975840c75c 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 57db6241490..893f72a35ab 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2383,13 +2383,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 450ded89653..43887c84b75 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 616b17255bc..20a19546011 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3715,28 +3715,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); } @@ -3933,8 +3933,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) { /* @@ -3942,9 +3941,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); } } @@ -3956,17 +3956,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); } } @@ -9195,6 +9196,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) { @@ -9261,7 +9264,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 */ @@ -9276,12 +9279,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); } } @@ -9292,18 +9296,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; } @@ -9318,7 +9325,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(); @@ -9343,11 +9350,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; @@ -9592,7 +9599,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; @@ -9623,7 +9630,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; /* @@ -9645,10 +9653,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; } @@ -9669,7 +9677,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); @@ -9683,9 +9691,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(); @@ -9839,18 +9848,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++; @@ -9858,10 +9873,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; @@ -9869,9 +9884,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) { @@ -9879,12 +9894,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; @@ -9893,14 +9908,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; @@ -9973,7 +9989,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); @@ -9989,27 +10005,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; @@ -10026,8 +10041,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; @@ -10035,11 +10050,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; } @@ -10048,8 +10063,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; @@ -10234,11 +10254,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); |