diff options
-rw-r--r-- | mysql-test/r/subselect.result | 31 | ||||
-rw-r--r-- | mysql-test/t/subselect.test | 14 | ||||
-rw-r--r-- | sql/item.cc | 109 | ||||
-rw-r--r-- | sql/item.h | 70 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 27 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 9 | ||||
-rw-r--r-- | sql/item_row.cc | 9 | ||||
-rw-r--r-- | sql/item_row.h | 1 | ||||
-rw-r--r-- | sql/item_subselect.cc | 97 | ||||
-rw-r--r-- | sql/item_subselect.h | 12 | ||||
-rw-r--r-- | sql/sql_class.cc | 6 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 12 |
13 files changed, 353 insertions, 48 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index d45b7b24585..f983825a56b 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -773,3 +773,34 @@ a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c') (select c from t1 where 2 0 b NULL NULL NULL drop table t1,t2; +drop table if exists t; +create table t (a int, b real, c varchar(10)); +insert into t values (1, 1, 'a'), (2,2,'b'), (NULL, 2, 'b'); +select ROW(1, 1, 'a') IN (select a,b,c from t); +ROW(1, 1, 'a') IN (select a,b,c from t) +1 +select ROW(1, 2, 'a') IN (select a,b,c from t); +ROW(1, 2, 'a') IN (select a,b,c from t) +NULL +select ROW(1, 1, 'a') IN (select b,a,c from t); +ROW(1, 1, 'a') IN (select b,a,c from t) +1 +select ROW(1, 1, 'a') IN (select a,b,c from t where a is not null); +ROW(1, 1, 'a') IN (select a,b,c from t where a is not null) +1 +select ROW(1, 2, 'a') IN (select a,b,c from t where a is not null); +ROW(1, 2, 'a') IN (select a,b,c from t where a is not null) +0 +select ROW(1, 1, 'a') IN (select b,a,c from t where a is not null); +ROW(1, 1, 'a') IN (select b,a,c from t where a is not null) +1 +select ROW(1, 1, 'a') IN (select a,b,c from t where c='b' or c='a'); +ROW(1, 1, 'a') IN (select a,b,c from t where c='b' or c='a') +1 +select ROW(1, 2, 'a') IN (select a,b,c from t where c='b' or c='a'); +ROW(1, 2, 'a') IN (select a,b,c from t where c='b' or c='a') +NULL +select ROW(1, 1, 'a') IN (select b,a,c from t where c='b' or c='a'); +ROW(1, 1, 'a') IN (select b,a,c from t where c='b' or c='a') +1 +drop table if exists t; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index ee3d31e66af..863c5f0ad9c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -434,3 +434,17 @@ select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),(select c from t select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2; select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c'),(select c from t1 where a=t2.a) from t2; drop table t1,t2; + +drop table if exists t; +create table t (a int, b real, c varchar(10)); +insert into t values (1, 1, 'a'), (2,2,'b'), (NULL, 2, 'b'); +select ROW(1, 1, 'a') IN (select a,b,c from t); +select ROW(1, 2, 'a') IN (select a,b,c from t); +select ROW(1, 1, 'a') IN (select b,a,c from t); +select ROW(1, 1, 'a') IN (select a,b,c from t where a is not null); +select ROW(1, 2, 'a') IN (select a,b,c from t where a is not null); +select ROW(1, 1, 'a') IN (select b,a,c from t where a is not null); +select ROW(1, 1, 'a') IN (select a,b,c from t where c='b' or c='a'); +select ROW(1, 2, 'a') IN (select a,b,c from t where c='b' or c='a'); +select ROW(1, 1, 'a') IN (select b,a,c from t where c='b' or c='a'); +drop table if exists t; diff --git a/sql/item.cc b/sql/item.cc index 340eb2c985c..37cc9939bde 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -498,6 +498,27 @@ bool Item_asterisk_remover::fix_fields(THD *thd, DBUG_RETURN(res); } +bool Item_ref_on_list_position::fix_fields(THD *thd, + struct st_table_list *tables, + Item ** reference) +{ + ref= 0; + List_iterator<Item> li(list); + Item *item; + uint i= 0; + for (; (item= li++) && i < pos; i++); + if (i == pos) + { + ref= li.ref(); + return Item_ref_null_helper::fix_fields(thd, tables, reference); + } + else + { + my_error(ER_CARDINALITY_COL, MYF(0), pos); + return 1; + } +} + double Item_ref_null_helper::val() { double tmp= (*ref)->val_result(); @@ -1196,6 +1217,8 @@ Item_cache* Item_cache::get_cache(Item_result type) return new Item_cache_real(); case STRING_RESULT: return new Item_cache_str(); + case ROW_RESULT: + return new Item_cache_row(); default: // should never be in real life DBUG_ASSERT(0); @@ -1241,6 +1264,92 @@ longlong Item_cache_str::val_int() return (longlong)0; } +bool Item_cache_row::allocate(uint num) +{ + n= num; + THD *thd= current_thd; + if (!(values= (Item_cache **) thd->calloc(sizeof(Item_cache *)*n))) + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + thd->fatal_error= 1; + return 1; + } + return 0; +} + +bool Item_cache_row::setup(Item * item) +{ + if (!values && allocate(item->cols())) + return 1; + for(uint i= 0; i < n; i++) + { + if (!(values[i]= Item_cache::get_cache(item->el(i)->result_type()))) + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return 1; + } + values[i]->setup(item->el(i)); + } + return 0; +} + +void Item_cache_row::store(Item * item) +{ + null_value= 0; + item->bring_value(); + for(uint i= 0; i < n; i++) + { + values[i]->store(item->el(i)); + null_value|= values[i]->null_value; + } +} + +void Item_cache_row::illegal_method_call(const char *method) +{ + DBUG_ENTER("Item_cache_row::illegal_method_call"); + DBUG_PRINT("error", ("!!! %s method was called for row item", method)); + DBUG_ASSERT(0); + my_error(ER_CARDINALITY_COL, MYF(0), 1); + DBUG_VOID_RETURN; +} + +bool Item_cache_row::check_cols(uint c) +{ + if (c != n) + { + my_error(ER_CARDINALITY_COL, MYF(0), c); + return 1; + } + return 0; +} + +bool Item_cache_row::null_inside() +{ + for (uint i= 0; i < n; i++) + { + if (values[i]->cols() > 1) + { + if (values[i]->null_inside()) + return 1; + } + else + { + values[i]->val_int(); + if (values[i]->null_value) + return 1; + } + } + return 0; +} + +void Item_cache_row::bring_value() +{ + for (uint i= 0; i < n; i++) + values[i]->bring_value(); + return; +} + /***************************************************************************** ** Instantiate templates *****************************************************************************/ diff --git a/sql/item.h b/sql/item.h index 21087cfe0e2..4e3c5f597ab 100644 --- a/sql/item.h +++ b/sql/item.h @@ -501,7 +501,7 @@ protected: Item_in_subselect* owner; public: Item_ref_null_helper(Item_in_subselect* master, Item **item, - char *table_name_par,char *field_name_par): + char *table_name_par, char *field_name_par): Item_ref(item, table_name_par, field_name_par), owner(master) {} double val(); longlong val_int(); @@ -509,6 +509,24 @@ public: bool get_date(TIME *ltime, bool fuzzydate); }; + +/* + Used to find item in list of select items after '*' items processing. +*/ +class Item_ref_on_list_position: public Item_ref_null_helper +{ +protected: + List<Item> &list; + uint pos; +public: + Item_ref_on_list_position(Item_in_subselect* master, + List<Item> &li, uint num, + char *table_name, char *field_name): + Item_ref_null_helper(master, 0, table_name, field_name), + list(li), pos(num) {} + bool fix_fields(THD *, struct st_table_list *, Item ** ref); +}; + /* To resolve '*' field moved to condition and register NULL values @@ -642,6 +660,8 @@ public: class Item_cache: public Item { public: + virtual bool allocate(uint i) { return 0; }; + virtual bool setup(Item *) { return 0; }; virtual void store(Item *)= 0; void set_len_n_dec(uint32 max_len, uint8 dec) { @@ -705,6 +725,54 @@ public: CHARSET_INFO *charset() const { return value->charset(); }; }; +class Item_cache_row: public Item_cache +{ + Item_cache **values; + uint n; +public: + Item_cache_row(): values(0), n(2) { fixed= 1; null_value= 1; } + + /* + 'allocate' used only in row transformer, to preallocate space for row + cache. + */ + bool allocate(uint num); + /* + 'setup' is needed only by row => it not called by simple row subselect + (only by IN subselect (in subselect optimizer)) + */ + bool setup(Item *item); + void store(Item *item); + void illegal_method_call(const char *); + void make_field(Send_field *) + { + illegal_method_call((const char*)"make_field"); + }; + double val() + { + illegal_method_call((const char*)"val"); + return 0; + }; + longlong val_int() + { + illegal_method_call((const char*)"val_int"); + return 0; + }; + String *val_str(String *) + { + illegal_method_call((const char*)"val_str"); + return 0; + }; + enum Item_result result_type() const { return ROW_RESULT; } + + uint cols() { return n; } + Item* el(uint i) { return values[i]; } + Item** addr(uint i) { return (Item **) (values + i); } + bool check_cols(uint c); + bool null_inside(); + void bring_value(); +}; + extern Item_buff *new_Item_buff(Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern Item *resolve_const_item(Item *item,Item *cmp_item); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index be25a2609b0..df949a910bd 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -274,12 +274,19 @@ int Arg_comparator::compare_e_row() return 1; } +bool Item_in_optimizer::preallocate_row() +{ + if ((cache= Item_cache::get_cache(ROW_RESULT))) + return 0; + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return 1; +} + bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, Item ** ref) { - - if (args[0]->check_cols(allowed_arg_cols) || - args[0]->fix_fields(thd, tables, args)) + if (args[0]->fix_fields(thd, tables, args)) return 1; if (args[0]->maybe_null) maybe_null=1; @@ -288,15 +295,21 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, with_sum_func= args[0]->with_sum_func; used_tables_cache= args[0]->used_tables(); const_item_cache= args[0]->const_item(); - if (!(cache= Item_cache::get_cache(args[0]->result_type()))) + if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))) { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); thd->fatal_error= 1; return 1; } - if (args[1]->check_cols(allowed_arg_cols) || - args[1]->fix_fields(thd, tables, args)) + cache->setup(args[0]); + if (args[1]->fix_fields(thd, tables, args)) + return 1; + Item_in_subselect * sub= (Item_in_subselect *)args[1]; + if (args[0]->cols() != sub->engine->cols()) + { + my_error(ER_CARDINALITY_COL, MYF(0), args[0]->cols()); return 1; + } if (args[1]->maybe_null) maybe_null=1; with_sum_func= with_sum_func || args[1]->with_sum_func; @@ -1215,7 +1228,7 @@ void cmp_item_row::store_value(Item *item) { THD *thd= current_thd; n= item->cols(); - if ((comparators= (cmp_item **) thd->alloc(sizeof(cmp_item *)*n))) + if ((comparators= (cmp_item **) thd->calloc(sizeof(cmp_item *)*n))) { item->bring_value(); item->null_value= 0; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 41171da1338..e3d8eb7746d 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -91,14 +91,15 @@ class Item_in_optimizer: public Item_bool_func protected: Item_cache *cache; public: - Item_in_optimizer(Item *a,Item *b): - Item_bool_func(a,b), cache(0) {} + Item_in_optimizer(Item *a, Item_in_subselect *b): + Item_bool_func(a, (Item *)b), cache(0) {} + // used by row in transformer + bool preallocate_row(); bool fix_fields(THD *, struct st_table_list *, Item **); bool is_null(); longlong val_int(); - Item **get_cache() { return (Item**)&cache; } - + Item_cache **get_cache() { return &cache; } }; class Item_bool_func2 :public Item_int_func diff --git a/sql/item_row.cc b/sql/item_row.cc index 85a81a50256..9d605e05242 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -41,7 +41,7 @@ void Item_row::illegal_method_call(const char *method) DBUG_ENTER("Item_row::illegal_method_call"); DBUG_PRINT("error", ("!!! %s method was called for row item", method)); DBUG_ASSERT(0); - my_error(ER_CARDINALITY_COL, MYF(0), arg_count); + my_error(ER_CARDINALITY_COL, MYF(0), 1); DBUG_VOID_RETURN; } @@ -100,3 +100,10 @@ bool Item_row::null_inside() } return 0; } + +void Item_row::bring_value() +{ + for (uint i= 0; i < arg_count; i++) + items[i]->bring_value(); + return; +} diff --git a/sql/item_row.h b/sql/item_row.h index 4767d19d08f..cf67567c3ed 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -70,4 +70,5 @@ public: Item** addr(uint i) { return items + i; } bool check_cols(uint c); bool null_inside(); + void bring_value(); }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index c4a97731625..bb7a497a15c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -127,36 +127,36 @@ inline table_map Item_subselect::used_tables() const return (table_map) engine->depended() ? 1L : 0L; } -Item_singleval_subselect::Item_singleval_subselect(THD *thd, +Item_singlerow_subselect::Item_singlerow_subselect(THD *thd, st_select_lex *select_lex): Item_subselect(), value(0) { - DBUG_ENTER("Item_singleval_subselect::Item_singleval_subselect"); - init(thd, select_lex, new select_singleval_subselect(this)); + DBUG_ENTER("Item_singlerow_subselect::Item_singlerow_subselect"); + init(thd, select_lex, new select_singlerow_subselect(this)); max_columns= 1; maybe_null= 1; max_columns= UINT_MAX; DBUG_VOID_RETURN; } -void Item_singleval_subselect::reset() +void Item_singlerow_subselect::reset() { null_value= 1; if (value) value->null_value= 1; } -void Item_singleval_subselect::store(uint i, Item *item) +void Item_singlerow_subselect::store(uint i, Item *item) { row[i]->store(item); } -enum Item_result Item_singleval_subselect::result_type() const +enum Item_result Item_singlerow_subselect::result_type() const { return engine->type(); } -void Item_singleval_subselect::fix_length_and_dec() +void Item_singlerow_subselect::fix_length_and_dec() { if ((max_columns= engine->cols()) == 1) { @@ -182,12 +182,12 @@ void Item_singleval_subselect::fix_length_and_dec() } } -uint Item_singleval_subselect::cols() +uint Item_singlerow_subselect::cols() { return engine->cols(); } -bool Item_singleval_subselect::check_cols(uint c) +bool Item_singlerow_subselect::check_cols(uint c) { if (c != engine->cols()) { @@ -197,7 +197,7 @@ bool Item_singleval_subselect::check_cols(uint c) return 0; } -bool Item_singleval_subselect::null_inside() +bool Item_singlerow_subselect::null_inside() { for (uint i= 0; i < max_columns ; i++) { @@ -207,12 +207,12 @@ bool Item_singleval_subselect::null_inside() return 0; } -void Item_singleval_subselect::bring_value() +void Item_singlerow_subselect::bring_value() { engine->exec(); } -double Item_singleval_subselect::val () +double Item_singlerow_subselect::val () { if (!engine->exec() && !value->null_value) { @@ -226,7 +226,7 @@ double Item_singleval_subselect::val () } } -longlong Item_singleval_subselect::val_int () +longlong Item_singlerow_subselect::val_int () { if (!engine->exec() && !value->null_value) { @@ -240,7 +240,7 @@ longlong Item_singleval_subselect::val_int () } } -String *Item_singleval_subselect::val_str (String *str) +String *Item_singlerow_subselect::val_str (String *str) { if (!engine->exec() && !value->null_value) { @@ -293,7 +293,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, left_expr= left_exp; func= f; init(thd, select_lex, new select_exists_subselect(this)); - max_columns= UINT_MAX; + max_columns= 1; reset(); // We need only 1 row to determinate existence select_lex->master_unit()->global_parameters->select_limit= 1; @@ -305,6 +305,7 @@ void Item_exists_subselect::fix_length_and_dec() { decimals= 0; max_length= 1; + max_columns= engine->cols(); } double Item_exists_subselect::val () @@ -409,7 +410,7 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, As far as Item_ref_in_optimizer do not substitude itself on fix_fields we can use same item for all selects. */ - Item *expr= new Item_ref(optimizer->get_cache(), + Item *expr= new Item_ref((Item**)optimizer->get_cache(), (char *)"<no matter>", (char*)"<left expr>"); select_lex->master_unit()->dependent= 1; @@ -440,7 +441,7 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, sl->having= item; else if (sl->where) - sl->where= new Item_cond_and(sl->having, item); + sl->where= new Item_cond_and(sl->where, item); else sl->where= item; } @@ -498,10 +499,68 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, DBUG_VOID_RETURN; } +void Item_in_subselect::row_value_transformer(st_select_lex *select_lex, + Item *left_expr) +{ + DBUG_ENTER("Item_in_subselect::row_value_transformer"); + Item_in_optimizer *optimizer; + substitution= optimizer= new Item_in_optimizer(left_expr, this); + if (!optimizer) + { + current_thd->fatal_error= 1; + DBUG_VOID_RETURN; + } + select_lex->master_unit()->dependent= 1; + uint n= left_expr->cols(); + if (optimizer->preallocate_row() || (*optimizer->get_cache())->allocate(n)) + DBUG_VOID_RETURN; + for (SELECT_LEX * sl= select_lex; sl; sl= sl->next_select()) + { + select_lex->dependent= 1; + + Item *item= 0; + List_iterator_fast<Item> li(sl->item_list); + for (uint i= 0; i < n; i++) + { + Item *func= + new Item_ref_on_list_position(this, sl->item_list, i, + (char *) "<no matter>", + (char *) "<list ref>"); + func= + Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())-> + addr(i), + (char *)"<no matter>", + (char *)"<left expr>"), + func); + if (!item) + item= func; + else + item= new Item_cond_and(item, func); + } + + if (sl->having || sl->with_sum_func || sl->group_list.first || + !sl->table_list.elements) + if (sl->having) + sl->having= new Item_cond_and(sl->having, item); + else + sl->having= item; + else + if (sl->where) + sl->where= new Item_cond_and(sl->where, item); + else + sl->where= item; + } + DBUG_VOID_RETURN; +} + + void Item_in_subselect::select_transformer(st_select_lex *select_lex) { - single_value_transformer(select_lex, left_expr, - &Item_bool_func2::eq_creator); + if (left_expr->cols() == 1) + single_value_transformer(select_lex, left_expr, + &Item_bool_func2::eq_creator); + else + row_value_transformer(select_lex, left_expr); } void Item_allany_subselect::select_transformer(st_select_lex *select_lex) diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 3cb68cb3875..04f0e6f3c83 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -86,18 +86,19 @@ public: bool check_loop(uint id); friend class select_subselect; + friend class Item_in_optimizer; }; /* single value subselect */ class Item_cache; -class Item_singleval_subselect :public Item_subselect +class Item_singlerow_subselect :public Item_subselect { protected: Item_cache *value, **row; public: - Item_singleval_subselect(THD *thd, st_select_lex *select_lex); - Item_singleval_subselect(Item_singleval_subselect *item): + Item_singlerow_subselect(THD *thd, st_select_lex *select_lex); + Item_singlerow_subselect(Item_singlerow_subselect *item): Item_subselect(item) { value= item->value; @@ -109,7 +110,7 @@ public: double val(); longlong val_int (); String *val_str (String *); - Item *new_item() { return new Item_singleval_subselect(this); } + Item *new_item() { return new Item_singlerow_subselect(this); } enum Item_result result_type() const; void fix_length_and_dec(); @@ -120,7 +121,7 @@ public: bool null_inside(); void bring_value(); - friend class select_singleval_subselect; + friend class select_singlerow_subselect; }; /* exists subselect */ @@ -174,6 +175,7 @@ public: virtual void select_transformer(st_select_lex *select_lex); void single_value_transformer(st_select_lex *select_lex, Item *left_expr, compare_func_creator func); + void row_value_transformer(st_select_lex *select_lex, Item *left_expr); longlong val_int(); double val(); String *val_str(String*); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0b12a34ebfb..061bf12b71c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -916,10 +916,10 @@ select_subselect::select_subselect(Item_subselect *item) this->item=item; } -bool select_singleval_subselect::send_data(List<Item> &items) +bool select_singlerow_subselect::send_data(List<Item> &items) { - DBUG_ENTER("select_singleval_subselect::send_data"); - Item_singleval_subselect *it= (Item_singleval_subselect *)item; + DBUG_ENTER("select_singlerow_subselect::send_data"); + Item_singlerow_subselect *it= (Item_singlerow_subselect *)item; if (it->assigned()) { my_message(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0)); diff --git a/sql/sql_class.h b/sql/sql_class.h index 7ca66d9ffb7..3abcf12e4b7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -824,10 +824,10 @@ public: }; /* Single value subselect interface class */ -class select_singleval_subselect :public select_subselect +class select_singlerow_subselect :public select_subselect { public: - select_singleval_subselect(Item_subselect *item):select_subselect(item){} + select_singlerow_subselect(Item_subselect *item):select_subselect(item){} bool send_data(List<Item> &items); }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 55f165c0739..d160c5281a8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -587,7 +587,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr using_list expr_or_default set_expr_or_default - param_marker singleval_subselect singleval_subselect_init + param_marker singlerow_subselect singlerow_subselect_init exists_subselect exists_subselect_init %type <item_list> @@ -2017,7 +2017,7 @@ simple_expr: $$= new Item_row(*$5); } | EXISTS exists_subselect { $$= $2; } - | singleval_subselect { $$= $1; } + | singlerow_subselect { $$= $1; } | '{' ident expr '}' { $$= $3; } | MATCH ident_list_arg AGAINST '(' expr ')' { Select->add_ftfunc_to_list((Item_func_match *) @@ -4487,17 +4487,17 @@ union_option: /* empty */ {} | ALL {Select->master_unit()->union_option= 1;}; -singleval_subselect: - subselect_start singleval_subselect_init +singlerow_subselect: + subselect_start singlerow_subselect_init subselect_end { $$= $2; }; -singleval_subselect_init: +singlerow_subselect_init: select_init2 { - $$= new Item_singleval_subselect(YYTHD, + $$= new Item_singlerow_subselect(YYTHD, Lex->current_select->master_unit()-> first_select()); }; |