diff options
-rw-r--r-- | mysql-test/r/subselect.result | 3 | ||||
-rw-r--r-- | sql/item.cc | 5 | ||||
-rw-r--r-- | sql/item.h | 4 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 9 | ||||
-rw-r--r-- | sql/item_row.cc | 28 | ||||
-rw-r--r-- | sql/item_row.h | 17 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 3 | ||||
-rw-r--r-- | sql/item_subselect.cc | 37 |
8 files changed, 63 insertions, 43 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 7059054104f..7dc03a31878 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -39,9 +39,8 @@ Reference 'a' not supported (forward reference in item list) EXPLAIN SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> system NULL NULL NULL NULL 1 +3 DEPENDENT SUBSELECT NULL NULL NULL NULL NULL NULL NULL No tables used 2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used -Warnings: -Note 1247 Select 3 was reduced during optimisation SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; 1 1 diff --git a/sql/item.cc b/sql/item.cc index 5de4c6951e5..8feeabd306e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1289,9 +1289,10 @@ bool Item_cache_row::setup(Item * item) return 1; for (uint i= 0; i < item_count; i++) { - if (!(values[i]= Item_cache::get_cache(item->el(i)->result_type()))) + Item *el= item->el(i); + if (!(values[i]= Item_cache::get_cache(el->result_type()))) return 1; - values[i]->setup(item->el(i)); + values[i]->setup(el); } return 0; } diff --git a/sql/item.h b/sql/item.h index 046464da97d..3decdc388eb 100644 --- a/sql/item.h +++ b/sql/item.h @@ -515,6 +515,10 @@ public: /* Used to find item in list of select items after '*' items processing. + + Because item '*' can be used in item list. when we create + Item_ref_on_list_position we do not know how item list will be changed, but + we know number of item position (I mean queries like "select * from t"). */ class Item_ref_on_list_position: public Item_ref_null_helper { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 2aca3e1fabb..44c788f381c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -97,6 +97,13 @@ public: bool preallocate_row(); bool fix_fields(THD *, struct st_table_list *, Item **); bool is_null(); + /* + Item_in_optimizer item is special boolean function. On value request + (one of val, val_int or val_str methods) it evaluate left expression + of IN by storing it value in cache item (one of Item_cache* items), + then it test cache is it NULL. If left expression (cache) is NULL then + Item_in_optimizer return NULL, else it evaluate Item_in_subselect. + */ longlong val_int(); Item_cache **get_cache() { return &cache; } @@ -546,8 +553,10 @@ public: { if (comparators) for (uint i= 0; i < n; i++) + { if (comparators[i]) delete comparators[i]; + } } void store_value(Item *item); int cmp(Item *arg); diff --git a/sql/item_row.cc b/sql/item_row.cc index b54653f4183..ba4ac19b880 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -54,7 +54,14 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) if (items[i]->fix_fields(thd, tabl, items+i)) return 1; used_tables_cache |= items[i]->used_tables(); - const_item_cache&= items[i]->const_item(); + if (const_item_cache&= items[i]->const_item() && !with_null) + if (items[i]->cols() > 1) + with_null|= items[i]->null_inside(); + else + { + items[i]->val_int(); + with_null|= items[i]->null_value; + } maybe_null|= items[i]->maybe_null; } return 0; @@ -82,25 +89,6 @@ bool Item_row::check_cols(uint c) return 0; } -bool Item_row::null_inside() -{ - for (uint i= 0; i < arg_count; i++) - { - if (items[i]->cols() > 1) - { - if (items[i]->null_inside()) - return 1; - } - else - { - items[i]->val_int(); - if (items[i]->null_value) - return 1; - } - } - return 0; -} - void Item_row::bring_value() { for (uint i= 0; i < arg_count; i++) diff --git a/sql/item_row.h b/sql/item_row.h index 82580797ebc..ccaf68bed64 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -16,19 +16,22 @@ class Item_row: public Item { - bool array_holder; + Item **items; table_map used_tables_cache; - bool const_item_cache; uint arg_count; - Item **items; + bool array_holder; + bool const_item_cache; + bool with_null; public: Item_row(List<Item> &); Item_row(Item_row *item): - Item(), array_holder(0), + Item(), + items(item->items), used_tables_cache(item->used_tables_cache), - const_item_cache(item->const_item_cache), arg_count(item->arg_count), - items(item->items) + array_holder(0), + const_item_cache(item->const_item_cache), + with_null(0) {} ~Item_row() @@ -71,6 +74,6 @@ public: Item* el(uint i) { return items[i]; } Item** addr(uint i) { return items + i; } bool check_cols(uint c); - bool null_inside(); + bool null_inside() { return with_null; }; void bring_value(); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 43eee0abf1c..ce362d6b972 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1961,7 +1961,8 @@ String *Item_func_conv_charset::val_str(String *str) d0=d=(unsigned char*)str->ptr(); de=d+dmaxlen; - while (s < se && d < de){ + while (s < se && d < de) + { cnvres=from->mb_wc(from,&wc,s,se); if (cnvres>0) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8763701b7a3..75aef846b17 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -157,7 +157,11 @@ void Item_singlerow_subselect::select_transformer(THD *thd, SELECT_LEX *select_lex= unit->first_select(); if (!select_lex->next_select() && !select_lex->table_list.elements && - select_lex->item_list.elements == 1) + select_lex->item_list.elements == 1 && + // TODO: mark subselect items from item list separately + !(select_lex->item_list.head()->type() == FIELD_ITEM || + select_lex->item_list.head()->type() == REF_ITEM) + ) { have_to_be_excluded= 1; @@ -170,9 +174,6 @@ void Item_singlerow_subselect::select_transformer(THD *thd, } substitution= select_lex->item_list.head(); substitution->set_outer_resolving(); - if (substitution->type() == FIELD_ITEM || - substitution->type() == REF_ITEM) - name= substitution->name; // Save name for correct resolving if (select_lex->where || select_lex->having) { @@ -444,6 +445,9 @@ void Item_in_subselect::single_value_transformer(THD *thd, "LIMIT & IN/ALL/ANY/SOME subquery"); DBUG_VOID_RETURN; } + // no sense in ORDER BY without LIMIT + unit->global_parameters->order_list.empty(); + Item_in_optimizer *optimizer; substitution= optimizer= new Item_in_optimizer(left_expr, this); if (!optimizer) @@ -476,18 +480,16 @@ void Item_in_subselect::single_value_transformer(THD *thd, else item= (Item*) sl->item_list.pop(); - if (sl->having || sl->with_sum_func || sl->group_list.first || - sl->order_list.first) + sl->order_list.empty(); // no sense in ORDER BY without LIMIT + + if (sl->having || sl->with_sum_func || sl->group_list.first) { sl->item_list.push_back(item); item= (*func)(expr, new Item_ref_null_helper(this, sl->item_list.head_ref(), (char *)"<no matter>", (char*)"<result>")); - if (sl->having || sl->with_sum_func || sl->group_list.first) - sl->having= and_items(sl->having, item); - else - sl->where= and_items(sl->where, item); + sl->having= and_items(sl->having, item); } else { @@ -547,10 +549,22 @@ void Item_in_subselect::row_value_transformer(THD *thd, if (unit->global_parameters->select_limit != HA_POS_ERROR) { + /* + Because we do the following (not exactly, following is just explenation) + transformation + SELECT * from t1 WHERE t1.a IN (SELECT t2.a FROM t2) + -> + SELECT * from t1 WHERE EXISTS(SELECT 1 FROM t2 t1.a = t2.a LIMIT 1) + + it's impossible to support limit in the sub select. + */ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "LIMIT & IN/ALL/ANY/SOME subquery"); DBUG_VOID_RETURN; } + // no sense in ORDER BY without LIMIT + unit->global_parameters->order_list.empty(); + Item_in_optimizer *optimizer; substitution= optimizer= new Item_in_optimizer(left_expr, this); if (!optimizer) @@ -568,6 +582,7 @@ void Item_in_subselect::row_value_transformer(THD *thd, "LIMIT & IN/ALL/ANY/SOME subquery"); DBUG_VOID_RETURN; } + sl->order_list.empty(); // no sense in ORDER BY without LIMIT sl->dependent= 1; @@ -589,7 +604,7 @@ void Item_in_subselect::row_value_transformer(THD *thd, } if (sl->having || sl->with_sum_func || sl->group_list.first || - !sl->table_list.elements) + !sl->table_list.elements || !sl->table_list.elements) sl->having= and_items(sl->having, item); else sl->where= and_items(sl->where, item); |