diff options
Diffstat (limited to 'sql/sql_yacc.yy')
-rw-r--r-- | sql/sql_yacc.yy | 772 |
1 files changed, 726 insertions, 46 deletions
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6072be28dca..f84839a607b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -28,13 +28,16 @@ #define MYSQL_YACC #define YYINITDEPTH 100 #define YYMAXDEPTH 3200 /* Because of 64K stack */ -#define Lex (&(YYTHD->lex)) +#define Lex ((YYTHD->lex)) #define Select Lex->current_select #include "mysql_priv.h" #include "slave.h" #include "sql_acl.h" #include "lex_symbol.h" #include "item_create.h" +#include "sp_head.h" +#include "sp_pcontext.h" +#include "sp.h" #include <myisam.h> #include <myisammrg.h> @@ -121,6 +124,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token AVG_SYM %token BEGIN_SYM %token BINLOG_SYM +%token CALL_SYM %token CHANGE %token CLIENT_SYM %token COMMENT_SYM @@ -198,10 +202,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token COLUMNS %token COLUMN_SYM %token CONCURRENT +%token CONNECTION_SYM %token CONSTRAINT %token CONVERT_SYM %token DATABASES %token DATA_SYM +%token DECLARE_SYM %token DEFAULT %token DELAYED_SYM %token DELAY_KEY_WRITE_SYM @@ -247,6 +253,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token INFILE %token INNER_SYM %token INNOBASE_SYM +%token INOUT_SYM %token INTO %token IN_SYM %token ISOLATION @@ -262,6 +269,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token LIKE %token LINES %token LOCAL_SYM +%token LOCATOR_SYM %token LOG_SYM %token LOGS_SYM %token LONG_NUM @@ -305,6 +313,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token OR %token OR_OR_CONCAT %token ORDER_SYM +%token OUT_SYM %token OUTER %token OUTFILE %token DUMPFILE @@ -344,6 +353,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SIMPLE_SYM %token SHUTDOWN %token SPATIAL_SYM +%token SPECIFIC_SYM %token SSL_SYM %token STARTING %token STATUS_SYM @@ -364,9 +374,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token FUNC_ARG1 %token FUNC_ARG2 %token FUNC_ARG3 -%token UDF_RETURNS_SYM +%token RETURN_SYM +%token RETURNS_SYM %token UDF_SONAME_SYM -%token UDF_SYM +%token FUNCTION_SYM %token UNCOMMITTED_SYM %token UNDERSCORE_CHARSET %token UNICODE_SYM @@ -506,6 +517,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token ROUND %token SECOND_SYM %token SHARE_SYM +%token SP_FUNC %token SUBSTRING %token SUBSTRING_INDEX %token TRIM @@ -535,6 +547,18 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SQL_SMALL_RESULT %token SQL_BUFFER_RESULT +%token CURSOR_SYM +%token ELSEIF_SYM +%token ITERATE_SYM +%token LEAVE_SYM +%token LOOP_SYM +%token REPEAT_SYM +%token UNTIL_SYM +%token WHILE_SYM +%token ASENSITIVE_SYM +%token INSENSITIVE_SYM +%token SENSITIVE_SYM + %token ISSUER_SYM %token SUBJECT_SYM %token CIPHER_SYM @@ -562,6 +586,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal NCHAR_STRING + SP_FUNC ident_or_spfunc %type <lex_str_ptr> opt_table_alias @@ -597,7 +622,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); table_wild no_in_expr expr_expr simple_expr no_and_expr using_list expr_or_default set_expr_or_default interval_expr param_marker singlerow_subselect singlerow_subselect_init - exists_subselect exists_subselect_init + exists_subselect exists_subselect_init sp_opt_default %type <item_list> expr_list udf_expr_list when_list ident_list ident_list_arg @@ -684,8 +709,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); union_clause union_list union_option precision subselect_start opt_and charset subselect_end select_var_list select_var_list_init help opt_len + statement END_OF_INPUT +%type <NONE> call sp_proc_stmts sp_proc_stmt +%type <num> sp_decls sp_decl sp_decl_idents sp_opt_inout + %type <NONE> '-' '+' '*' '/' '%' '(' ')' ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM @@ -698,23 +727,29 @@ query: { THD *thd= YYTHD; if (!thd->bootstrap && - (!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT))) + (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT))) { send_error(thd,ER_EMPTY_QUERY); YYABORT; } else { - thd->lex.sql_command = SQLCOM_EMPTY_QUERY; + thd->lex->sql_command = SQLCOM_EMPTY_QUERY; } } | verb_clause END_OF_INPUT {}; verb_clause: + statement + | begin + ; + +/* Verb clauses, except begin */ +statement: alter | analyze | backup - | begin + | call | change | check | commit @@ -898,20 +933,560 @@ create: lex->name=$4.str; lex->create_info.options=$3; } - | CREATE udf_func_type UDF_SYM IDENT_sys + | CREATE udf_func_type FUNCTION_SYM ident_or_spfunc { LEX *lex=Lex; - lex->sql_command = SQLCOM_CREATE_FUNCTION; lex->udf.name = $4; lex->udf.type= $2; } - UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys + create_function_tail + {} + | CREATE PROCEDURE ident + { + LEX *lex= Lex; + sp_head *sp; + + if (lex->sphead) + { + net_printf(YYTHD, ER_SP_NO_RECURSIVE_CREATE, "PROCEDURE"); + YYABORT; + } + /* Order is important here: new - reset - init */ + sp= new sp_head(); + sp->reset_thd_mem_root(YYTHD); + sp->init(&$3, lex, 0, 0); + + sp->m_type= TYPE_ENUM_PROCEDURE; + lex->sphead= sp; + /* + * We have to turn of CLIENT_MULTI_QUERIES while parsing a + * stored procedure, otherwise yylex will chop it into pieces + * at each ';'. + */ + sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; + YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES); + } + '(' sp_pdparam_list ')' + { + Lex->spcont->set_params(); + } + sp_proc_stmt + { + LEX *lex= Lex; + + lex->sql_command= SQLCOM_CREATE_PROCEDURE; + /* Restore flag if it was cleared above */ + if (lex->sphead->m_old_cmq) + YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; + lex->sphead->restore_thd_mem_root(YYTHD); + } + ; + +ident_or_spfunc: + IDENT_sys { $$= $1; } + | SP_FUNC { $$= $1; } + ; + +create_function_tail: + RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys { LEX *lex=Lex; - lex->udf.returns=(Item_result) $7; - lex->udf.dl=$9.str; + lex->sql_command = SQLCOM_CREATE_FUNCTION; + lex->udf.returns=(Item_result) $2; + lex->udf.dl=$4.str; } - ; + | '(' + { + LEX *lex= Lex; + sp_head *sp; + + if (lex->sphead) + { + net_printf(YYTHD, ER_SP_NO_RECURSIVE_CREATE, "FUNCTION"); + YYABORT; + } + /* Order is important here: new - reset - init */ + sp= new sp_head(); + sp->reset_thd_mem_root(YYTHD); + sp->init(&lex->udf.name, lex, 0, 0); + + sp->m_type= TYPE_ENUM_FUNCTION; + lex->sphead= sp; + /* + * We have to turn of CLIENT_MULTI_QUERIES while parsing a + * stored procedure, otherwise yylex will chop it into pieces + * at each ';'. + */ + sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; + YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES; + } + sp_fdparam_list ')' + { + Lex->spcont->set_params(); + } + RETURNS_SYM type + { + Lex->sphead->m_returns= (enum enum_field_types)$7; + } + sp_proc_stmt + { + LEX *lex= Lex; + + lex->sql_command = SQLCOM_CREATE_SPFUNCTION; + /* Restore flag if it was cleared above */ + if (lex->sphead->m_old_cmq) + YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; + lex->sphead->restore_thd_mem_root(YYTHD); + } + ; + +call: + CALL_SYM ident_or_spfunc + { + LEX *lex = Lex; + + lex->sql_command= SQLCOM_CALL; + lex->udf.name= $2; + lex->value_list.empty(); + } + '(' sp_cparam_list ')' {} + ; + +/* CALL parameters */ +sp_cparam_list: + /* Empty */ + | sp_cparams + ; + +sp_cparams: + sp_cparams ',' expr + { + Lex->value_list.push_back($3); + } + | expr + { + Lex->value_list.push_back($1); + } + ; + +/* Stored FUNCTION parameter declaration list */ +sp_fdparam_list: + /* Empty */ + | sp_fdparams + ; + +sp_fdparams: + sp_fdparams ',' sp_fdparam + | sp_fdparam + ; + +sp_fdparam: + ident type sp_opt_locator + { + Lex->spcont->push(&$1, (enum enum_field_types)$2, sp_param_in); + } + ; + +/* Stored PROCEDURE parameter declaration list */ +sp_pdparam_list: + /* Empty */ + | sp_pdparams + ; + +sp_pdparams: + sp_pdparams ',' sp_pdparam + | sp_pdparam + ; + +sp_pdparam: + sp_opt_inout ident type sp_opt_locator + { + Lex->spcont->push(&$2, + (enum enum_field_types)$3, + (sp_param_mode_t)$1); + } + ; + +sp_opt_inout: + /* Empty */ { $$= sp_param_in; } + | IN_SYM { $$= sp_param_in; } + | OUT_SYM { $$= sp_param_out; } + | INOUT_SYM { $$= sp_param_inout; } + ; + +sp_opt_locator: + /* Empty */ + | AS LOCATOR_SYM + ; + +sp_proc_stmts: + sp_proc_stmt ';' + | sp_proc_stmts sp_proc_stmt ';' + ; + +sp_decls: + /* Empty */ + { + $$= 0; + } + | sp_decls sp_decl ';' + { + $$= $1 + $2; + } + ; + +sp_decl: + DECLARE_SYM sp_decl_idents type sp_opt_default + { + LEX *lex= Lex; + uint max= lex->spcont->current_framesize(); + enum enum_field_types type= (enum enum_field_types)$3; + Item *it= $4; + + for (uint i = max-$2 ; i < max ; i++) + { + lex->spcont->set_type(i, type); + if (! it) + lex->spcont->set_isset(i, FALSE); + else + { + sp_instr_set *in= new sp_instr_set(lex->sphead->instructions(), + i, it, type); + + lex->sphead->add_instr(in); + lex->spcont->set_isset(i, TRUE); + } + } + $$= $2; + } + ; + +sp_decl_idents: + ident + { + Lex->spcont->push(&$1, (enum_field_types)0, sp_param_in); + $$= 1; + } + | sp_decl_idents ',' ident + { + Lex->spcont->push(&$3, (enum_field_types)0, sp_param_in); + $$= $1 + 1; + } + ; + +sp_opt_default: + /* Empty */ { $$ = NULL; } + | DEFAULT expr { $$ = $2; } + ; + +sp_proc_stmt: + { + Lex->sphead->reset_lex(YYTHD); + } + statement + { + LEX *lex= Lex; + + if (lex->sql_command == SQLCOM_SELECT && !lex->result) + { + /* We maybe have one or more SELECT without INTO */ + lex->sphead->m_multi_query= TRUE; + } + /* Don't add an instruction for empty SET statements. + ** (This happens if the SET only contained local variables, + ** which get their set instructions generated separately.) + */ + if (lex->sql_command != SQLCOM_SET_OPTION || + ! lex->var_list.is_empty()) + { + /* Currently we can't handle queries inside a FUNCTION, + ** because of the way table locking works. + ** This is unfortunate, and limits the usefulness of functions + ** a great deal, but it's nothing we can do about this at the + ** moment. + */ + if (lex->sphead->m_type == TYPE_ENUM_FUNCTION && + lex->sql_command != SQLCOM_SET_OPTION) + { + send_error(YYTHD, ER_SP_BADQUERY); + YYABORT; + } + else + { + sp_instr_stmt *i=new sp_instr_stmt(lex->sphead->instructions()); + + i->set_lex(lex); + lex->sphead->add_instr(i); + lex->sp_lex_in_use= TRUE; + } + } + lex->sphead->restore_lex(YYTHD); + } + | RETURN_SYM expr + { + LEX *lex= Lex; + + if (lex->sphead->m_type == TYPE_ENUM_PROCEDURE) + { + send_error(YYTHD, ER_SP_BADRETURN); + YYABORT; + } + else + { + sp_instr_return *i= + new sp_instr_return(lex->sphead->instructions(), + $2, lex->sphead->m_returns); + + lex->sphead->add_instr(i); + } + } + | IF sp_if END IF {} + | CASE_SYM WHEN_SYM + { + Lex->sphead->m_simple_case= FALSE; + } + sp_case END CASE_SYM {} + | CASE_SYM expr WHEN_SYM + { + /* We "fake" this by using an anonymous variable which we + set to the expression. Note that all WHENs are evaluate + at the same frame level, so we then know that it's the + top-most variable in the frame. */ + LEX *lex= Lex; + uint offset= lex->spcont->current_framesize(); + sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(), + offset, $2, MYSQL_TYPE_STRING); + LEX_STRING dummy; + + dummy.str= (char *)""; + dummy.length= 0; + lex->spcont->push(&dummy, MYSQL_TYPE_STRING, sp_param_in); + lex->sphead->add_instr(i); + lex->sphead->m_simple_case= TRUE; + } + sp_case END CASE_SYM + { + Lex->spcont->pop(); + } + | sp_labeled_control + {} + | { /* Unlabeled controls get a secret label. */ + LEX *lex= Lex; + + lex->spcont->push_label((char *)"", lex->sphead->instructions()); + } + sp_unlabeled_control + { + LEX *lex= Lex; + + lex->sphead->backpatch(lex->spcont->pop_label()); + } + | LEAVE_SYM IDENT + { + LEX *lex= Lex; + sp_head *sp = lex->sphead; + sp_label_t *lab= lex->spcont->find_label($2.str); + + if (! lab) + { + net_printf(YYTHD, ER_SP_LILABEL_MISMATCH, "LEAVE", $2.str); + YYABORT; + } + else + { + sp_instr_jump *i= new sp_instr_jump(sp->instructions()); + + sp->push_backpatch(i, lab); /* Jumping forward */ + sp->add_instr(i); + } + } + | ITERATE_SYM IDENT + { + LEX *lex= Lex; + sp_label_t *lab= lex->spcont->find_label($2.str); + + if (! lab) + { + net_printf(YYTHD, ER_SP_LILABEL_MISMATCH, "ITERATE", $2.str); + YYABORT; + } + else + { + uint ip= lex->sphead->instructions(); + sp_instr_jump *i= new sp_instr_jump(ip, lab->ip); /* Jump back */ + + lex->sphead->add_instr(i); + } + } + ; + +sp_if: + expr THEN_SYM + { + sp_head *sp= Lex->sphead; + sp_pcontext *ctx= Lex->spcont; + uint ip= sp->instructions(); + sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $1); + + sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->add_instr(i); + } + sp_proc_stmts + { + sp_head *sp= Lex->sphead; + sp_pcontext *ctx= Lex->spcont; + uint ip= sp->instructions(); + sp_instr_jump *i = new sp_instr_jump(ip); + + sp->add_instr(i); + sp->backpatch(ctx->pop_label()); + sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + } + sp_elseifs + { + LEX *lex= Lex; + + lex->sphead->backpatch(lex->spcont->pop_label()); + } + ; + +sp_elseifs: + /* Empty */ + | ELSEIF_SYM sp_if + | ELSE sp_proc_stmts + ; + +sp_case: + expr THEN_SYM + { + sp_head *sp= Lex->sphead; + sp_pcontext *ctx= Lex->spcont; + uint ip= sp->instructions(); + sp_instr_jump_if_not *i; + + if (! sp->m_simple_case) + i= new sp_instr_jump_if_not(ip, $1); + else + { /* Simple case: <caseval> = <whenval> */ + Item *var= (Item*) new Item_splocal(ctx->current_framesize()-1); + Item *expr= Item_bool_func2::eq_creator(var, $1); + + i= new sp_instr_jump_if_not(ip, expr); + } + sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->add_instr(i); + } + sp_proc_stmts + { + sp_head *sp= Lex->sphead; + sp_pcontext *ctx= Lex->spcont; + uint ip= sp->instructions(); + sp_instr_jump *i = new sp_instr_jump(ip); + + sp->add_instr(i); + sp->backpatch(ctx->pop_label()); + sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + } + sp_whens + { + LEX *lex= Lex; + + lex->sphead->backpatch(lex->spcont->pop_label()); + } + ; + +sp_whens: + /* Empty */ {} + | WHEN_SYM sp_case {} + | ELSE sp_proc_stmts {} + ; + +sp_labeled_control: + IDENT ':' + { + LEX *lex= Lex; + sp_label_t *lab= lex->spcont->find_label($1.str); + + if (lab) + { + net_printf(YYTHD, ER_SP_LABEL_REDEFINE, $1.str); + YYABORT; + } + else + { + lex->spcont->push_label($1.str, + lex->sphead->instructions()); + } + } + sp_unlabeled_control IDENT + { + LEX *lex= Lex; + sp_label_t *lab= lex->spcont->find_label($5.str); + + if (!lab || + my_strcasecmp(system_charset_info, $5.str, lab->name) != 0) + { + net_printf(YYTHD, ER_SP_LABEL_MISMATCH, $5.str); + YYABORT; + } + else + { + lex->spcont->pop_label(); + lex->sphead->backpatch(lab); + } + } + ; + +sp_unlabeled_control: + BEGIN_SYM + sp_decls + sp_proc_stmts + END + { /* QQ This is just a dummy for grouping declarations and statements + together. No [[NOT] ATOMIC] yet, and we need to figure out how + make it coexist with the existing BEGIN COMMIT/ROLLBACK. */ + Lex->spcont->pop($2); + } + | LOOP_SYM + sp_proc_stmts END LOOP_SYM + { + LEX *lex= Lex; + uint ip= lex->sphead->instructions(); + sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ + sp_instr_jump *i = new sp_instr_jump(ip, lab->ip); + + lex->sphead->add_instr(i); + } + | WHILE_SYM expr DO_SYM + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + uint ip= sp->instructions(); + sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $2); + + /* Jumping forward */ + sp->push_backpatch(i, lex->spcont->last_label()); + sp->add_instr(i); + } + sp_proc_stmts END WHILE_SYM + { + LEX *lex= Lex; + uint ip= lex->sphead->instructions(); + sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ + sp_instr_jump *i = new sp_instr_jump(ip, lab->ip); + + lex->sphead->add_instr(i); + } + | REPEAT_SYM sp_proc_stmts UNTIL_SYM expr END REPEAT_SYM + { + LEX *lex= Lex; + uint ip= lex->sphead->instructions(); + sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ + sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $4, lab->ip); + + lex->sphead->add_instr(i); + } + ; create2: '(' field_list ')' opt_create_table_options create3 {} @@ -1544,7 +2119,7 @@ alter: ALTER opt_ignore TABLE_SYM table_ident { THD *thd= YYTHD; - LEX *lex=&thd->lex; + LEX *lex= thd->lex; lex->sql_command = SQLCOM_ALTER_TABLE; lex->name=0; if (!lex->select_lex.add_table_to_list(thd, $4, NULL, @@ -1572,8 +2147,30 @@ alter: LEX *lex=Lex; lex->sql_command=SQLCOM_ALTER_DB; lex->name=$3.str; - }; + } + | ALTER PROCEDURE ident + /* QQ Characteristics missing for now */ + opt_restrict + { + LEX *lex=Lex; + /* This is essensially an no-op right now, since we haven't + put the characteristics in yet. */ + lex->sql_command= SQLCOM_ALTER_PROCEDURE; + lex->udf.name= $3; + } + | ALTER FUNCTION_SYM ident + /* QQ Characteristics missing for now */ + opt_restrict + { + LEX *lex=Lex; + + /* This is essensially an no-op right now, since we haven't + put the characteristics in yet. */ + lex->sql_command= SQLCOM_ALTER_FUNCTION; + lex->udf.name= $3; + } + ; alter_list: | alter_list_item @@ -2039,7 +2636,7 @@ select_item_list: THD *thd= YYTHD; if (add_item_to_list(thd, new Item_field(NULL, NULL, "*"))) YYABORT; - (thd->lex.current_select->select_lex()->with_wild)++; + (thd->lex->current_select->select_lex()->with_wild)++; }; @@ -2334,6 +2931,8 @@ simple_expr: { $$= ((Item*(*)(Item*,Item*))($1.symbol->create_func))($3,$5);} | FUNC_ARG3 '(' expr ',' expr ',' expr ')' { $$= ((Item*(*)(Item*,Item*,Item*))($1.symbol->create_func))($3,$5,$7);} + | REPEAT_SYM '(' expr ',' expr ')' + { $$= new Item_func_repeat($3,$5); } | ATAN '(' expr ')' { $$= new Item_func_atan($3); } | ATAN '(' expr ',' expr ')' @@ -2577,6 +3176,14 @@ simple_expr: { $$= new Item_func_round($3,$5,1); } | TRUE_SYM { $$= new Item_int((char*) "TRUE",1,1); } + | SP_FUNC '(' udf_expr_list ')' + { + sp_add_fun_to_lex(Lex, $1); + if ($3) + $$= new Item_func_sp($1, *$3); + else + $$= new Item_func_sp($1); + } | UDA_CHAR_SUM '(' udf_expr_list ')' { if ($3 != NULL) @@ -3230,11 +3837,33 @@ select_var_list: | select_var_ident {} ; -select_var_ident: '@' ident_or_text +select_var_ident: + '@' ident_or_text + { + LEX *lex=Lex; + if (lex->result) + ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($2,0,0)); + else + YYABORT; + } + | ident_or_text { LEX *lex=Lex; - if (lex->result && ((select_dumpvar *)lex->result)->var_list.push_back((LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING)))) + if (!lex->spcont) + YYABORT; + sp_pvar_t *t; + if (!(t=lex->spcont->find_pvar(&$1))) + { + send_error(lex->thd, ER_SYNTAX_ERROR); + YYABORT; + } + if (! lex->result) YYABORT; + else + { + ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($1,1,t->offset)); + t->isset= TRUE; + } } ; @@ -3315,11 +3944,19 @@ drop: lex->drop_if_exists=$3; lex->name=$4.str; } - | DROP UDF_SYM IDENT_sys + | DROP FUNCTION_SYM if_exists IDENT_sys opt_restrict { LEX *lex=Lex; lex->sql_command = SQLCOM_DROP_FUNCTION; - lex->udf.name = $3; + lex->drop_if_exists= $3; + lex->udf.name= $4; + } + | DROP PROCEDURE if_exists IDENT_sys opt_restrict + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_DROP_PROCEDURE; + lex->drop_if_exists= $3; + lex->udf.name= $4; } | DROP USER { @@ -3331,7 +3968,6 @@ drop: {} ; - table_list: table_name | table_list ',' table_name; @@ -3388,7 +4024,6 @@ replace: } insert_field_spec {} - {} ; insert_lock_option: @@ -3758,8 +4393,8 @@ show_param: | opt_var_type VARIABLES wild { THD *thd= YYTHD; - thd->lex.sql_command= SQLCOM_SHOW_VARIABLES; - thd->lex.option_type= (enum_var_type) $1; + thd->lex->sql_command= SQLCOM_SHOW_VARIABLES; + thd->lex->option_type= (enum_var_type) $1; } | charset wild { Lex->sql_command= SQLCOM_SHOW_CHARSETS; } @@ -3938,18 +4573,23 @@ purge_option: /* kill threads */ kill: - KILL_SYM expr + KILL_SYM kill_option expr { LEX *lex=Lex; - if ($2->fix_fields(lex->thd, 0, &$2) || $2->check_cols(1)) + if ($3->fix_fields(lex->thd, 0, &$3) || $3->check_cols(1)) { send_error(lex->thd, ER_SET_CONSTANTS_ONLY); YYABORT; } lex->sql_command=SQLCOM_KILL; - lex->thread_id= (ulong) $2->val_int(); + lex->thread_id= (ulong) $3->val_int(); }; +kill_option: + /* empty */ { Lex->type= 0; } + | CONNECTION_SYM { Lex->type= 0; } + | QUERY_SYM { Lex->type= ONLY_KILL_QUERY; }; + /* change database */ use: USE_SYM ident @@ -4135,16 +4775,33 @@ order_ident: simple_ident: ident { - SELECT_LEX_NODE *sel=Select; - $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING || - sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,NullS,$1.str) : - (Item*) new Item_ref(NullS,NullS,$1.str); + sp_pvar_t *spv; + LEX *lex = Lex; + sp_pcontext *spc = lex->spcont; + + if (spc && (spv = spc->find_pvar(&$1))) + { /* We're compiling a stored procedure and found a variable */ + if (lex->sql_command != SQLCOM_CALL && ! spv->isset) + { + net_printf(YYTHD, ER_SP_UNINIT_VAR, $1.str); + YYABORT; + } + else + $$ = (Item*) new Item_splocal(spv->offset); + } + else + { + SELECT_LEX_NODE *sel=Select; + $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING || + sel->get_in_sum_expr() > 0) ? + (Item*) new Item_field(NullS,NullS,$1.str) : + (Item*) new Item_ref(NullS,NullS,$1.str); + } } | ident '.' ident { THD *thd= YYTHD; - LEX *lex= &thd->lex; + LEX *lex= thd->lex; SELECT_LEX_NODE *sel= lex->current_select; if (sel->no_table_names_allowed) { @@ -4160,7 +4817,7 @@ simple_ident: | '.' ident '.' ident { THD *thd= YYTHD; - LEX *lex= &thd->lex; + LEX *lex= thd->lex; SELECT_LEX_NODE *sel= lex->current_select; if (sel->no_table_names_allowed) { @@ -4176,7 +4833,7 @@ simple_ident: | ident '.' ident '.' ident { THD *thd= YYTHD; - LEX *lex= &thd->lex; + LEX *lex= thd->lex; SELECT_LEX_NODE *sel= lex->current_select; if (sel->no_table_names_allowed) { @@ -4469,7 +5126,7 @@ keyword: | TIMESTAMP {} | TIME_SYM {} | TYPE_SYM {} - | UDF_SYM {} + | FUNCTION_SYM {} | UNCOMMITTED_SYM {} | UNICODE_SYM {} | USER {} @@ -4525,15 +5182,12 @@ opt_var_ident_type: ; option_value: - '@' ident_or_text equal expr - { - Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4))); - } - | internal_variable_name equal set_expr_or_default + '@' ident_or_text equal expr { - LEX *lex=Lex; - lex->var_list.push_back(new set_var(lex->option_type, $1, $3)); + Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4))); } + | internal_or_splocal + {} | '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default { LEX *lex=Lex; @@ -4574,7 +5228,7 @@ option_value: YYABORT; user->host.str=0; user->user.str=thd->priv_user; - thd->lex.var_list.push_back(new set_var_password(user, $3)); + thd->lex->var_list.push_back(new set_var_password(user, $3)); } | PASSWORD FOR_SYM user equal text_or_password { @@ -4592,6 +5246,32 @@ internal_variable_name: } ; +internal_or_splocal: + ident equal set_expr_or_default + { + LEX *lex= Lex; + sp_pcontext *spc= lex->spcont; + sp_pvar_t *spv; + + if (!spc || !(spv = spc->find_pvar(&$1))) + { /* Not an SP local variable */ + sys_var *tmp= find_sys_var($1.str, $1.length); + + if (!tmp) + YYABORT; + lex->var_list.push_back(new set_var(lex->option_type, tmp, $3)); + } + else + { /* An SP local variable */ + sp_instr_set *i= new sp_instr_set(lex->sphead->instructions(), + spv->offset, $3, spv->type); + + lex->sphead->add_instr(i); + spv->isset= TRUE; + } + } + ; + isolation_types: READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; } | READ_SYM COMMITTED_SYM { $$= ISO_READ_COMMITTED; } @@ -5076,7 +5756,7 @@ optional_order_or_limit: | { THD *thd= YYTHD; - LEX *lex= &thd->lex; + LEX *lex= thd->lex; DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE); SELECT_LEX *sel= lex->current_select->select_lex(); SELECT_LEX_UNIT *unit= sel->master_unit(); @@ -5088,7 +5768,7 @@ optional_order_or_limit: order_or_limit { THD *thd= YYTHD; - thd->lex.current_select->no_table_names_allowed= 0; + thd->lex->current_select->no_table_names_allowed= 0; thd->where= ""; } ; |