diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index fc918012d1f..c4fac8d8e7f 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3266,3 +3266,13 @@ select wss_type from t1 where wss_type =102935229216544093; wss_type 102935229216544093 drop table t1; +select 1+2,"aaaa",3.13*2.0 into @a,@b,@c; +select @a; +@a +3 +select @b; +@b +aaaa +select @c; +@c +6.26 diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 94806d44e37..57a17e40723 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1751,3 +1751,7 @@ select wss_type from t1 where wss_type ='102935229216544104'; select wss_type from t1 where wss_type ='102935229216544093'; select wss_type from t1 where wss_type =102935229216544093; drop table t1; +select 1+2,"aaaa",3.13*2.0 into @a,@b,@c; +select @a; +select @b; +select @c; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f778a721f54..a1689feb754 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -912,3 +912,47 @@ bool select_exists_subselect::send_data(List &items) DBUG_RETURN(0); } + +/*************************************************************************** +** Dump of select to variables +***************************************************************************/ + + +bool select_dumpvar::send_data(List &items) +{ + List_iterator_fast li(items); + List_iterator_fast gl(current_thd->lex.select_into_var_list); + Item *item; + LEX_STRING *ls; + DBUG_ENTER("send_data"); + + if (row_count++ > 1) + { + my_error(ER_TOO_MANY_ROWS, MYF(0)); + goto err; + } + while ((item=li++) && (ls=gl++)) + { + Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item); + xx->fix_fields(current_thd,(TABLE_LIST*) current_thd->lex.select_lex.table_list.first,&item); + xx->fix_length_and_dec(); + xx->update(); + } + DBUG_RETURN(0); +err: + DBUG_RETURN(1); +} + +bool select_dumpvar::send_eof() +{ + if (row_count) + { + ::send_ok(thd,row_count); + return 0; + } + else + { + my_error(ER_EMPTY_QUERY,MYF(0)); + return 1; + } +} diff --git a/sql/sql_class.h b/sql/sql_class.h index e9a4109a4c1..cc01344c8de 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -966,3 +966,25 @@ public: bool send_eof(); }; +class select_dumpvar :public select_result { + ha_rows row_count; +public: + select_dumpvar(void) { row_count=0;} + ~select_dumpvar() {} + int prepare(List &list, SELECT_LEX_UNIT *u) { return 0;} + bool send_fields(List &list, uint flag) + { + if (current_thd->lex.select_into_var_list.elements != list.elements) + { + my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, MYF(0)); + return 1; + } + return 0; + } + bool send_data(List &items); + void send_error(uint errcode,const char *err) + { + my_message(errcode, err, MYF(0)); + } + bool send_eof(); +}; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index acf73f34d5d..f618d9b7219 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -347,6 +347,7 @@ typedef struct st_lex List many_values; List var_list; List param_list; + List select_into_var_list; SQL_LIST proc_list, auxilliary_table_list; TYPELIB *interval; create_field *last_field; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7902e66043d..e1049988a83 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1449,25 +1449,36 @@ mysql_execute_command(THD *thd) } } } - else if (!(result=new select_send())) + else if (lex->select_into_var_list.elements) { - res= -1; -#ifdef DELETE_ITEMS - delete select_lex->having; - delete select_lex->where; -#endif - break; + if (!(result=new select_dumpvar())) + { + res= -1; + break; + } } - else + else { - /* - Normal select: - Change lock if we are using SELECT HIGH PRIORITY, - FOR UPDATE or IN SHARE MODE - */ - TABLE_LIST *table; - for (table = tables ; table ; table=table->next) - table->lock_type= lex->lock_option; + if (!(result=new select_send())) + { + res= -1; +#ifdef DELETE_ITEMS + delete select_lex->having; + delete select_lex->where; +#endif + break; + } + else + { + /* + Normal select: + Change lock if we are using SELECT HIGH PRIORITY, + FOR UPDATE or IN SHARE MODE + */ + TABLE_LIST *table; + for (table = tables ; table ; table=table->next) + table->lock_type= lex->lock_option; + } } if (!(res=open_and_lock_tables(thd,tables))) @@ -2966,6 +2977,7 @@ mysql_init_select(LEX *lex) select_lex->olap= UNSPECIFIED_OLAP_TYPE; lex->exchange= 0; lex->proc_list.first= 0; + lex->select_into_var_list.empty(); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f7ab07b2da3..5d77e887bd1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -523,7 +523,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %type IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME - ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET + ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET %type opt_table_alias @@ -632,7 +632,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); handler_rkey_function handler_read_or_scan single_multi table_wild_list table_wild_one opt_wild union union_list precision union_option opt_on_delete_item subselect_start opt_and - subselect_end + subselect_end select_var_list END_OF_INPUT %type @@ -1544,6 +1544,7 @@ select_part2: select_into: limit_clause {} | select_from + | opt_into | opt_into select_from | select_from opt_into; @@ -2287,11 +2288,11 @@ select_part3: mysql_init_select(lex); lex->select->linkage= DERIVED_TABLE_TYPE; } - select_options select_item_list select_intoto + select_options select_item_list select_intoto; select_intoto: limit_clause {} - | select_from + | select_from; opt_outer: /* empty */ {} @@ -2544,8 +2545,20 @@ procedure_item: $2->set_name($1,(uint) ((char*) Lex->tok_end - $1)); }; +select_var_list: + select_var_list ',' '@' ident_or_text + { + if (Lex->select_into_var_list.push_back((LEX_STRING*) sql_memdup(&$4,sizeof(LEX_STRING)))) + YYABORT; + } + | '@' ident_or_text + { + if (Lex->select_into_var_list.push_back((LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING)))) + YYABORT; + }; + opt_into: - INTO OUTFILE TEXT_STRING + INTO OUTFILE TEXT_STRING { if (!(Lex->exchange= new sql_exchange($3.str,0))) YYABORT; @@ -2555,6 +2568,10 @@ opt_into: { if (!(Lex->exchange= new sql_exchange($3.str,1))) YYABORT; + } + | INTO select_var_list + { + current_thd->safe_to_cache_query=0; }; /* @@ -3225,7 +3242,7 @@ param_marker: yyerror("You have an error in your SQL syntax"); YYABORT; } - } + }; literal: text_literal { $$ = $1; } | NUM { $$ = new Item_int($1.str, (longlong) atol($1.str),$1.length); } @@ -3565,7 +3582,7 @@ option_value: | PASSWORD FOR_SYM user equal text_or_password { Lex->var_list.push_back(new set_var_password($3,$5)); - } + }; internal_variable_name: ident @@ -3574,7 +3591,7 @@ internal_variable_name: if (!tmp) YYABORT; $$=tmp; - } + }; isolation_types: READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; } @@ -3933,7 +3950,7 @@ require_clause: /* empty */ | REQUIRE_SYM NONE_SYM { Lex->ssl_type=SSL_TYPE_NONE; - } + }; grant_options: /* empty */ {} @@ -4076,4 +4093,4 @@ subselect_end: { LEX *lex=Lex; lex->select = lex->select->outer_select(); - } + };