diff options
Diffstat (limited to 'sql/sql_yacc.yy')
-rw-r--r-- | sql/sql_yacc.yy | 6780 |
1 files changed, 3886 insertions, 2894 deletions
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ba0041cf477..5111f0690ab 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2015, MariaDB + Copyright (c) 2010, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,8 +23,9 @@ */ %{ -#define YYLIP (& thd->m_parser_state->m_lip) -#define YYPS (& thd->m_parser_state->m_yacc) +#define YYLIP (& thd->m_parser_state->m_lip) +#define YYPS (& thd->m_parser_state->m_yacc) +#define YYCSCL (thd->variables.character_set_client) #define MYSQL_YACC #define YYINITDEPTH 100 @@ -32,32 +33,35 @@ #define Lex (thd->lex) #define Select Lex->current_select +#include <my_global.h> #include "sql_priv.h" -#include "unireg.h" // REQUIRED: for other includes #include "sql_parse.h" /* comp_*_creator */ #include "sql_table.h" /* primary_key_name */ #include "sql_partition.h" /* mem_alloc_error, partition_info, HASH_PARTITION */ #include "sql_acl.h" /* *_ACL */ -#include "password.h" /* my_make_scrambled_password_323, my_make_scrambled_password */ #include "sql_class.h" /* Key_part_spec, enum_filetype, Diag_condition_item_name */ #include "slave.h" #include "lex_symbol.h" #include "item_create.h" #include "sp_head.h" -#include "sp_pcontext.h" #include "sp_rcontext.h" #include "sp.h" -#include "sql_alter.h" // Alter_table*_statement -#include "sql_truncate.h" // Truncate_statement -#include "sql_admin.h" // Analyze/Check..._table_stmt -#include "sql_partition_admin.h" // Alter_table_*_partition_stmt +#include "sql_show.h" +#include "sql_alter.h" // Sql_cmd_alter_table* +#include "sql_truncate.h" // Sql_cmd_truncate_table +#include "sql_admin.h" // Sql_cmd_analyze/Check..._table +#include "sql_partition_admin.h" // Sql_cmd_alter_table_*_part. +#include "sql_handler.h" // Sql_cmd_handler_* #include "sql_signal.h" +#include "sql_get_diagnostics.h" // Sql_cmd_get_diagnostics #include "event_parse_data.h" #include "create_options.h" #include <myisam.h> #include <myisammrg.h> #include "keycaches.h" #include "set_var.h" +#include "rpl_mi.h" +#include "lex_token.h" /* this is to get the bison compilation windows warnings out */ #ifdef _MSC_VER @@ -88,35 +92,15 @@ int yylex(void *yylval, void *yythd); YYABORT; \ } while (0) -#define MYSQL_YYABORT_UNLESS(A) \ - if (!(A)) \ - { \ - my_parse_error(ER(ER_SYNTAX_ERROR));\ - MYSQL_YYABORT; \ +#define MYSQL_YYABORT_UNLESS(A) \ + if (!(A)) \ + { \ + my_parse_error(thd, ER_SYNTAX_ERROR); \ + MYSQL_YYABORT; \ } -/* - Work around for broken code generated by bison 1.875. - - The code generated by bison 1.875a and later, bison 2.1 and bison 2.2 is ok. - With bison 1.875 however, the generated code contains: -<pre> - yyerrlab1: - #if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) - __attribute__ ((__unused__)) - #endif -</pre> - This usage of __attribute__ is illegal, so we remove it. - See the following references for details: - http://lists.gnu.org/archive/html/bug-bison/2004-02/msg00014.html - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14273 -*/ - -#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) -#undef __attribute__ -#define __attribute__(X) -#endif - +#define my_yyabort_error(A) \ + do { my_error A; MYSQL_YYABORT; } while(0) #ifndef DBUG_OFF #define YYDEBUG 1 @@ -135,21 +119,34 @@ int yylex(void *yylval, void *yythd); parser. */ -void my_parse_error(const char *s) +static void my_parse_error_intern(THD *thd, const char *err_text, + const char *yytext) { - THD *thd= current_thd; - Lex_input_stream *lip= & thd->m_parser_state->m_lip; - - const char *yytext= lip->get_tok_start(); + Lex_input_stream *lip= &thd->m_parser_state->m_lip; if (!yytext) - yytext= ""; - + { + if (!(yytext= lip->get_tok_start())) + yytext= ""; + } /* Push an error into the error stack */ - ErrConvString err(yytext, strlen(yytext), thd->variables.character_set_client); - my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0), s, - err.ptr(), lip->yylineno); + ErrConvString err(yytext, strlen(yytext), + thd->variables.character_set_client); + my_printf_error(ER_PARSE_ERROR, ER_THD(thd, ER_PARSE_ERROR), MYF(0), + err_text, err.ptr(), lip->yylineno); +} + + +static void my_parse_error(THD *thd, uint err_number, const char *yytext=0) +{ + return my_parse_error_intern(thd, ER_THD(thd, err_number), yytext); +} + +void LEX::parse_error() +{ + my_parse_error(thd, ER_SYNTAX_ERROR); } + /** @brief Bison callback to report a syntax/OOM error @@ -181,8 +178,8 @@ void MYSQLerror(THD *thd, const char *s) /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */ if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0) - s= ER(ER_SYNTAX_ERROR); - my_parse_error(s); + s= ER_THD(thd, ER_SYNTAX_ERROR); + my_parse_error_intern(thd, s, 0); } @@ -220,59 +217,67 @@ static bool is_native_function(THD *thd, const LEX_STRING *name) } -/** - Helper action for a case statement (entering the CASE). - This helper is used for both 'simple' and 'searched' cases. - This helper, with the other case_stmt_action_..., is executed when - the following SQL code is parsed: -<pre> -CREATE PROCEDURE proc_19194_simple(i int) -BEGIN - DECLARE str CHAR(10); - - CASE i - WHEN 1 THEN SET str="1"; - WHEN 2 THEN SET str="2"; - WHEN 3 THEN SET str="3"; - ELSE SET str="unknown"; - END CASE; - - SELECT str; -END -</pre> - The actions are used to generate the following code: -<pre> -SHOW PROCEDURE CODE proc_19194_simple; -Pos Instruction -0 set str@1 NULL -1 set_case_expr (12) 0 i@0 -2 jump_if_not 5(12) (case_expr@0 = 1) -3 set str@1 _latin1'1' -4 jump 12 -5 jump_if_not 8(12) (case_expr@0 = 2) -6 set str@1 _latin1'2' -7 jump 12 -8 jump_if_not 11(12) (case_expr@0 = 3) -9 set str@1 _latin1'3' -10 jump 12 -11 set str@1 _latin1'unknown' -12 stmt 0 "SELECT str" -</pre> +static sp_head *make_sp_head(THD *thd, sp_name *name, + enum stored_procedure_type type) +{ + LEX *lex= thd->lex; + sp_head *sp; - @param lex the parser lex context -*/ + /* Order is important here: new - reset - init */ + if ((sp= new sp_head())) + { + sp->reset_thd_mem_root(thd); + sp->init(lex); + sp->m_type= type; + if (name) + sp->init_sp_name(thd, name); + sp->m_chistics= &lex->sp_chistics; + lex->sphead= sp; + } + bzero(&lex->sp_chistics, sizeof(lex->sp_chistics)); + return sp; +} -void case_stmt_action_case(LEX *lex) +static bool maybe_start_compound_statement(THD *thd) { - lex->sphead->new_cont_backpatch(NULL); + if (!thd->lex->sphead) + { + if (!make_sp_head(thd, NULL, TYPE_ENUM_PROCEDURE)) + return 1; - /* - BACKPATCH: Creating target label for the jump to - "case_stmt_action_end_case" - (Instruction 12 in the example) - */ + Lex->sp_chistics.suid= SP_IS_NOT_SUID; + Lex->sphead->set_body_start(thd, YYLIP->get_cpp_ptr()); + } + return 0; +} - lex->spcont->push_label((char *)"", lex->sphead->instructions()); +static bool push_sp_label(THD *thd, LEX_STRING label) +{ + sp_pcontext *ctx= thd->lex->spcont; + sp_label *lab= ctx->find_label(label); + + if (lab) + { + my_error(ER_SP_LABEL_REDEFINE, MYF(0), label.str); + return 1; + } + else + { + lab= thd->lex->spcont->push_label(thd, label, + thd->lex->sphead->instructions()); + lab->type= sp_label::ITERATION; + } + return 0; +} + +static bool push_sp_empty_label(THD *thd) +{ + if (maybe_start_compound_statement(thd)) + return 1; + /* Unlabeled controls get an empty label. */ + thd->lex->spcont->push_label(thd, empty_lex_str, + thd->lex->sphead->instructions()); + return 0; } /** @@ -293,8 +298,9 @@ int case_stmt_action_expr(LEX *lex, Item* expr) if (parsing_ctx->push_case_expr_id(case_expr_id)) return 1; - i= new sp_instr_set_case_expr(sp->instructions(), - parsing_ctx, case_expr_id, expr, lex); + i= new (lex->thd->mem_root) + sp_instr_set_case_expr(sp->instructions(), parsing_ctx, case_expr_id, expr, + lex); sp->add_cont_backpatch(i); return sp->add_instr(i); @@ -316,10 +322,12 @@ int case_stmt_action_when(LEX *lex, Item *when, bool simple) sp_instr_jump_if_not *i; Item_case_expr *var; Item *expr; + THD *thd= lex->thd; if (simple) { - var= new Item_case_expr(ctx->get_current_case_expr_id()); + var= new (thd->mem_root) + Item_case_expr(thd, ctx->get_current_case_expr_id()); #ifndef DBUG_OFF if (var) @@ -328,11 +336,11 @@ int case_stmt_action_when(LEX *lex, Item *when, bool simple) } #endif - expr= new Item_func_eq(var, when); - i= new sp_instr_jump_if_not(ip, ctx, expr, lex); + expr= new (thd->mem_root) Item_func_eq(thd, var, when); + i= new (thd->mem_root) sp_instr_jump_if_not(ip, ctx, expr, lex); } else - i= new sp_instr_jump_if_not(ip, ctx, when, lex); + i= new (thd->mem_root) sp_instr_jump_if_not(ip, ctx, when, lex); /* BACKPATCH: Registering forward jump from @@ -340,8 +348,8 @@ int case_stmt_action_when(LEX *lex, Item *when, bool simple) (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example) */ - return !test(i) || - sp->push_backpatch(i, ctx->push_label((char *)"", 0)) || + return !MY_TEST(i) || + sp->push_backpatch(i, ctx->push_label(thd, empty_lex_str, 0)) || sp->add_cont_backpatch(i) || sp->add_instr(i); } @@ -357,8 +365,8 @@ int case_stmt_action_then(LEX *lex) sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; uint ip= sp->instructions(); - sp_instr_jump *i = new sp_instr_jump(ip, ctx); - if (!test(i) || sp->add_instr(i)) + sp_instr_jump *i= new (lex->thd->mem_root) sp_instr_jump(ip, ctx); + if (!MY_TEST(i) || sp->add_instr(i)) return 1; /* @@ -371,44 +379,19 @@ int case_stmt_action_then(LEX *lex) /* BACKPATCH: Registering forward jump from - "case_stmt_action_then" to "case_stmt_action_end_case" + "case_stmt_action_then" to after END CASE (jump from instruction 4 to 12, 7 to 12 ... in the example) */ return sp->push_backpatch(i, ctx->last_label()); } -/** - Helper action for an end case. - This helper is used for both 'simple' and 'searched' cases. - @param lex the parser lex context - @param simple true for simple cases, false for searched cases -*/ - -void case_stmt_action_end_case(LEX *lex, bool simple) -{ - /* - BACKPATCH: Resolving forward jump from - "case_stmt_action_then" to "case_stmt_action_end_case" - (jump from instruction 4 to 12, 7 to 12 ... in the example) - */ - lex->sphead->backpatch(lex->spcont->pop_label()); - - if (simple) - lex->spcont->pop_case_expr_id(); - - lex->sphead->do_cont_backpatch(); -} - - static bool find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp) { tmp->var= find_sys_var(thd, tmp->base_name.str, tmp->base_name.length); - if (tmp->var == NULL) - my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), tmp->base_name.str); - else + if (tmp->var != NULL) tmp->base_name= null_lex_str; return thd->is_error(); @@ -445,10 +428,11 @@ set_system_variable(THD *thd, struct sys_var_with_base *tmp, return TRUE; } - if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val))) + if (! (var= new (thd->mem_root) + set_var(thd, var_type, tmp->var, &tmp->base_name, val))) return TRUE; - return lex->var_list.push_back(var); + return lex->var_list.push_back(var, thd->mem_root); } @@ -464,7 +448,7 @@ set_system_variable(THD *thd, struct sys_var_with_base *tmp, */ static bool -set_local_variable(THD *thd, sp_variable_t *spv, Item *val) +set_local_variable(THD *thd, sp_variable *spv, Item *val) { Item *it; LEX *lex= thd->lex; @@ -472,17 +456,18 @@ set_local_variable(THD *thd, sp_variable_t *spv, Item *val) if (val) it= val; - else if (spv->dflt) - it= spv->dflt; + else if (spv->default_value) + it= spv->default_value; else { - it= new (thd->mem_root) Item_null(); + it= new (thd->mem_root) Item_null(thd); if (it == NULL) return TRUE; } - sp_set= new sp_instr_set(lex->sphead->instructions(), lex->spcont, - spv->offset, it, spv->type, lex, TRUE); + sp_set= new (thd->mem_root) + sp_instr_set(lex->sphead->instructions(), lex->spcont, + spv->offset, it, spv->type, lex, TRUE); return (sp_set == NULL || lex->sphead->add_instr(sp_set)); } @@ -508,22 +493,24 @@ set_trigger_new_row(THD *thd, LEX_STRING *name, Item *val) /* QQ: Shouldn't this be field's default value ? */ if (! val) - val= new Item_null(); + val= new (thd->mem_root) Item_null(thd); DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE && (lex->trg_chistics.event == TRG_EVENT_INSERT || lex->trg_chistics.event == TRG_EVENT_UPDATE)); trg_fld= new (thd->mem_root) - Item_trigger_field(lex->current_context(), + Item_trigger_field(thd, lex->current_context(), Item_trigger_field::NEW_ROW, name->str, UPDATE_ACL, FALSE); if (trg_fld == NULL) return TRUE; - sp_fld= new sp_instr_set_trigger_field(lex->sphead->instructions(), - lex->spcont, trg_fld, val, lex); + sp_fld= new (thd->mem_root) + sp_instr_set_trigger_field(lex->sphead->instructions(), + lex->spcont, trg_fld, val, + lex); if (sp_fld == NULL) return TRUE; @@ -539,6 +526,57 @@ set_trigger_new_row(THD *thd, LEX_STRING *name, Item *val) /** + Create an object to represent a SP variable in the Item-hierarchy. + + @param thd The current thread. + @param name The SP variable name. + @param spvar The SP variable (optional). + @param start_in_q Start position of the SP variable name in the query. + @param end_in_q End position of the SP variable name in the query. + + @remark If spvar is not specified, the name is used to search for the + variable in the parse-time context. If the variable does not + exist, a error is set and NULL is returned to the caller. + + @return An Item_splocal object representing the SP variable, or NULL on error. +*/ +static Item_splocal* +create_item_for_sp_var(THD *thd, LEX_STRING name, sp_variable *spvar, + const char *start_in_q, const char *end_in_q) +{ + Item_splocal *item; + LEX *lex= thd->lex; + uint pos_in_q, len_in_q; + sp_pcontext *spc = lex->spcont; + + /* If necessary, look for the variable. */ + if (spc && !spvar) + spvar= spc->find_variable(name, false); + + if (!spvar) + { + my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str); + return NULL; + } + + DBUG_ASSERT(spc && spvar); + + /* Position and length of the SP variable name in the query. */ + pos_in_q= start_in_q - lex->sphead->m_tmp_query; + len_in_q= end_in_q - start_in_q; + + item= new (thd->mem_root) + Item_splocal(thd, name, spvar->offset, spvar->type, pos_in_q, len_in_q); + +#ifndef DBUG_OFF + if (item) + item->m_sp= lex->sphead; +#endif + + return item; +} + +/** Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>. See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383. This function returns the proper item for the SQL expression @@ -596,7 +634,7 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, Item_in_subselect(left, subselect) */ subselect= expr3->invalidate_and_restore_select_lex(); - result= new (thd->mem_root) Item_in_subselect(left, subselect); + result= new (thd->mem_root) Item_in_subselect(thd, left, subselect); if (! equal) result = negate_expression(thd, result); @@ -606,9 +644,9 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, } if (equal) - result= new (thd->mem_root) Item_func_eq(left, expr); + result= new (thd->mem_root) Item_func_eq(thd, left, expr); else - result= new (thd->mem_root) Item_func_ne(left, expr); + result= new (thd->mem_root) Item_func_ne(thd, left, expr); DBUG_RETURN(result); } @@ -622,11 +660,11 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, @param lex The parser state. - @param is_union_distinct True if the union preceding the new select statement - uses UNION DISTINCT. + @param is_union_distinct True if the union preceding the new select + statement uses UNION DISTINCT. @param is_top_level This should be @c TRUE if the newly created SELECT_LEX - is a non-nested statement. + is a non-nested statement. @return <code>false</code> if successful, <code>true</code> if an error was reported. In the latter case parsing should stop. @@ -643,9 +681,20 @@ bool add_select_to_union_list(LEX *lex, bool is_union_distinct, my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO"); return TRUE; } + if (lex->current_select->order_list.first && !lex->current_select->braces) + { + my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY"); + return TRUE; + } + + if (lex->current_select->explicit_limit && !lex->current_select->braces) + { + my_error(ER_WRONG_USAGE, MYF(0), "UNION", "LIMIT"); + return TRUE; + } if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(lex->thd, ER_SYNTAX_ERROR); return TRUE; } /* This counter shouldn't be incremented for UNION parts */ @@ -670,17 +719,20 @@ bool add_select_to_union_list(LEX *lex, bool is_union_distinct, bool setup_select_in_parentheses(LEX *lex) { SELECT_LEX * sel= lex->current_select; + /* if (sel->set_braces(1)) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(lex->thd, ER_SYNTAX_ERROR); return TRUE; } + */ + DBUG_ASSERT(sel->braces); if (sel->linkage == UNION_TYPE && !sel->master_unit()->first_select()->braces && sel->master_unit()->first_select()->linkage == UNION_TYPE) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(lex->thd, ER_SYNTAX_ERROR); return TRUE; } if (sel->linkage == UNION_TYPE && @@ -690,110 +742,294 @@ bool setup_select_in_parentheses(LEX *lex) my_error(ER_WRONG_USAGE, MYF(0), "CUBE/ROLLUP", "ORDER BY"); return TRUE; } - /* select in braces, can't contain global parameters */ - if (sel->master_unit()->fake_select_lex) - sel->master_unit()->global_parameters= - sel->master_unit()->fake_select_lex; return FALSE; } -static bool add_create_index_prepare (LEX *lex, Table_ident *table) +static bool add_create_index_prepare(LEX *lex, Table_ident *table) { lex->sql_command= SQLCOM_CREATE_INDEX; if (!lex->current_select->add_table_to_list(lex->thd, table, NULL, TL_OPTION_UPDATING, TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE)) + MDL_SHARED_UPGRADABLE)) return TRUE; lex->alter_info.reset(); - lex->alter_info.flags= ALTER_ADD_INDEX; - lex->col_list.empty(); - lex->change= NullS; + lex->alter_info.flags= Alter_info::ALTER_ADD_INDEX; lex->option_list= NULL; return FALSE; } -static bool add_create_index (LEX *lex, Key::Keytype type, - const LEX_STRING &name, - KEY_CREATE_INFO *info= NULL, bool generated= 0) + +/** + Create a separate LEX for each assignment if in SP. + + If we are in SP we want have own LEX for each assignment. + This is mostly because it is hard for several sp_instr_set + and sp_instr_set_trigger instructions share one LEX. + (Well, it is theoretically possible but adds some extra + overhead on preparation for execution stage and IMO less + robust). + + QQ: May be we should simply prohibit group assignments in SP? + + @see sp_create_assignment_instr + + @param thd Thread context + @param no_lookahead True if the parser has no lookahead +*/ + +static void sp_create_assignment_lex(THD *thd, bool no_lookahead) +{ + LEX *lex= thd->lex; + + if (lex->sphead) + { + Lex_input_stream *lip= &thd->m_parser_state->m_lip; + LEX *old_lex= lex; + lex->sphead->reset_lex(thd); + lex= thd->lex; + + /* Set new LEX as if we at start of set rule. */ + lex->sql_command= SQLCOM_SET_OPTION; + mysql_init_select(lex); + lex->var_list.empty(); + lex->autocommit= 0; + /* get_ptr() is only correct with no lookahead. */ + if (no_lookahead) + lex->sphead->m_tmp_query= lip->get_ptr(); + else + lex->sphead->m_tmp_query= lip->get_tok_end(); + /* Inherit from outer lex. */ + lex->option_type= old_lex->option_type; + } +} + + +/** + Create a SP instruction for a SET assignment. + + @see sp_create_assignment_lex + + @param thd Thread context + @param no_lookahead True if the parser has no lookahead + + @return false if success, true otherwise. +*/ + +static bool sp_create_assignment_instr(THD *thd, bool no_lookahead) +{ + LEX *lex= thd->lex; + + if (lex->sphead) + { + sp_head *sp= lex->sphead; + + if (!lex->var_list.is_empty()) + { + /* + We have assignment to user or system variable or + option setting, so we should construct sp_instr_stmt + for it. + */ + LEX_STRING qbuff; + sp_instr_stmt *i; + Lex_input_stream *lip= &thd->m_parser_state->m_lip; + + if (!(i= new (thd->mem_root) + sp_instr_stmt(sp->instructions(), lex->spcont, lex))) + return true; + + /* + Extract the query statement from the tokenizer. The + end is either lip->ptr, if there was no lookahead, + lip->tok_end otherwise. + */ + if (no_lookahead) + qbuff.length= lip->get_ptr() - sp->m_tmp_query; + else + qbuff.length= lip->get_tok_end() - sp->m_tmp_query; + + if (!(qbuff.str= (char*) alloc_root(thd->mem_root, + qbuff.length + 5))) + return true; + + strmake(strmake(qbuff.str, "SET ", 4), sp->m_tmp_query, + qbuff.length); + qbuff.length+= 4; + i->m_query= qbuff; + if (sp->add_instr(i)) + return true; + } + enum_var_type inner_option_type= lex->option_type; + if (lex->sphead->restore_lex(thd)) + return true; + /* Copy option_type to outer lex in case it has changed. */ + thd->lex->option_type= inner_option_type; + } + return false; +} + + +static void add_key_to_list(LEX *lex, LEX_STRING *field_name, + enum Key::Keytype type, bool check_exists) { Key *key; - key= new Key(type, name, info ? info : &lex->key_create_info, generated, - lex->col_list, lex->option_list); - if (key == NULL) - return TRUE; + MEM_ROOT *mem_root= lex->thd->mem_root; + key= new (mem_root) + Key(type, null_lex_str, HA_KEY_ALG_UNDEF, false, + DDL_options(check_exists ? + DDL_options::OPT_IF_NOT_EXISTS : + DDL_options::OPT_NONE)); + key->columns.push_back(new (mem_root) Key_part_spec(*field_name, 0), + mem_root); + lex->alter_info.key_list.push_back(key, mem_root); +} - lex->alter_info.key_list.push_back(key); - lex->col_list.empty(); - return FALSE; +void LEX::init_last_field(Create_field *field, const char *field_name, + CHARSET_INFO *cs) +{ + last_field= field; + + field->field_name= field_name; + + /* reset LEX fields that are used in Create_field::set_and_check() */ + length= 0; + dec= 0; + charset= cs; +} + +void LEX::set_last_field_type(enum enum_field_types field_type) +{ + last_field->sql_type= field_type; + last_field->create_if_not_exists= check_exists; + last_field->charset= charset; + + if (length) + { + int err; + last_field->length= my_strtoll10(length, NULL, &err); + if (err) + last_field->length= ~0ULL; // safety + } + else + last_field->length= 0; + + last_field->decimals= dec ? (uint)atoi(dec) : 0; +} + +bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin) +{ + /* + if charset is NULL - we're parsing a field declaration. + we cannot call find_bin_collation for a field here, because actual + field charset is determined in get_sql_field_charset() much later. + so we only set a flag. + */ + if (!charset) + { + charset= cs; + last_field->flags|= bin ? BINCMP_FLAG : 0; + return false; + } + + charset= bin ? find_bin_collation(cs ? cs : charset) + : cs ? cs : charset; + return charset == NULL; } +#define bincmp_collation(X,Y) \ + do \ + { \ + if (Lex->set_bincmp(X,Y)) \ + MYSQL_YYABORT; \ + } while(0) + %} %union { int num; ulong ulong_num; ulonglong ulonglong_number; longlong longlong_number; + + /* structs */ LEX_STRING lex_str; - LEX_STRING *lex_str_ptr; LEX_SYMBOL symbol; - LEX_TYPE lex_type; - Table_ident *table; - char *simple_string; + struct sys_var_with_base variable; + struct { int vars, conds, hndlrs, curs; } spblock; + + /* pointers */ + CHARSET_INFO *charset; + Condition_information_item *cond_info_item; + DYNCALL_CREATE_DEF *dyncol_def; + Diagnostics_information *diag_info; Item *item; Item_num *item_num; + Item_param *item_param; + Key_part_spec *key_part; + LEX *lex; + LEX_STRING *lex_str_ptr; + LEX_USER *lex_user; + List<Condition_information_item> *cond_info_list; + List<DYNCALL_CREATE_DEF> *dyncol_def_list; List<Item> *item_list; + List<Statement_information_item> *stmt_info_list; List<String> *string_list; + Statement_information_item *stmt_info_item; String *string; - Key_part_spec *key_part; TABLE_LIST *table_list; - udf_func *udf; - LEX_USER *lex_user; - struct sys_var_with_base variable; - enum enum_var_type var_type; - Key::Keytype key_type; - enum ha_key_alg key_alg; + Table_ident *table; + char *simple_string; + chooser_compare_func_creator boolfunc2creator; + class my_var *myvar; + class sp_condition_value *spcondvalue; + class sp_head *sphead; + class sp_label *splabel; + class sp_name *spname; + class sp_variable *spvar; handlerton *db_type; - enum row_type row_type; - enum ha_rkey_function ha_rkey_mode; - enum enum_tx_isolation tx_isolation; - enum Cast_target cast_type; - enum Item_udftype udf_type; - enum ha_choice choice; - CHARSET_INFO *charset; - thr_lock_type lock_type; - interval_type interval, interval_time_st; - timestamp_type date_time_type; st_select_lex *select_lex; - chooser_compare_func_creator boolfunc2creator; - struct sp_cond_type *spcondtype; - struct { int vars, conds, hndlrs, curs; } spblock; - sp_name *spname; - LEX *lex; - sp_head *sphead; struct p_elem_val *p_elem_value; - enum index_hint_type index_hint; + udf_func *udf; + + /* enums */ + enum Cast_target cast_type; + enum Condition_information_item::Name cond_info_item_name; + enum enum_diag_condition_item_name diag_condition_item_name; + enum Diagnostics_information::Which_area diag_area; + enum Field::geometry_type geom_type; + enum enum_fk_option m_fk_option; + enum Item_udftype udf_type; + enum Key::Keytype key_type; + enum Statement_information_item::Name stmt_info_item_name; + enum enum_field_types field_type; enum enum_filetype filetype; - enum Foreign_key::fk_option m_fk_option; + enum enum_tx_isolation tx_isolation; + enum enum_var_type var_type; enum enum_yes_no_unknown m_yes_no_unk; - Diag_condition_item_name diag_condition_item_name; - DYNCALL_CREATE_DEF *dyncol_def; - List<DYNCALL_CREATE_DEF> *dyncol_def_list; - bool is_not_empty; + enum ha_choice choice; + enum ha_key_alg key_alg; + enum ha_rkey_function ha_rkey_mode; + enum index_hint_type index_hint; + enum interval_type interval, interval_time_st; + enum row_type row_type; + enum sp_variable::enum_mode spvar_mode; + enum thr_lock_type lock_type; + enum enum_mysql_timestamp_type date_time_type; + DDL_options_st object_ddl_options; } %{ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %} -%pure_parser /* We have threads */ +%pure-parser /* We have threads */ %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 175 shift/reduce conflicts. + Currently there are 160 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 175 +%expect 162 /* Comments for TOKENS. @@ -807,15 +1043,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); MYSQL-FUNC : MySQL extention, function INTERNAL : Not a real token, lex optimization OPERATOR : SQL operator - FUTURE-USE : Reserved for futur use + FUTURE-USE : Reserved for future use This makes the code grep-able, and helps maintenance. */ - + %token ABORT_SYM /* INTERNAL (used in lex) */ %token ACCESSIBLE_SYM %token ACTION /* SQL-2003-N */ %token ADD /* SQL-2003-R */ +%token ADMIN_SYM /* SQL-2003-N */ %token ADDDATE_SYM /* MYSQL-FUNC */ %token AFTER_SYM /* SQL-2003-N */ %token AGAINST @@ -833,9 +1070,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token ASCII_SYM /* MYSQL-FUNC */ %token ASENSITIVE_SYM /* FUTURE-USE */ %token AT_SYM /* SQL-2003-R */ +%token ATOMIC_SYM /* SQL-2003-R */ %token AUTHORS_SYM %token AUTOEXTEND_SIZE_SYM %token AUTO_INC +%token AUTO_SYM %token AVG_ROW_LENGTH %token AVG_SYM /* SQL-2003-N */ %token BACKUP_SYM @@ -876,7 +1115,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CIPHER_SYM %token CLASS_ORIGIN_SYM /* SQL-2003-N */ %token CLIENT_SYM -%token CLIENT_STATS_SYM %token CLOSE_SYM /* SQL-2003-R */ %token COALESCE /* SQL-2003-N */ %token CODE_SYM @@ -884,11 +1122,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token COLLATION_SYM /* SQL-2003-N */ %token COLUMNS %token COLUMN_ADD_SYM +%token COLUMN_CHECK_SYM %token COLUMN_CREATE_SYM %token COLUMN_DELETE_SYM -%token COLUMN_EXISTS_SYM %token COLUMN_GET_SYM -%token COLUMN_LIST_SYM %token COLUMN_SYM /* SQL-2003-R */ %token COLUMN_NAME_SYM /* SQL-2003-N */ %token COMMENT_SYM @@ -916,7 +1153,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CROSS /* SQL-2003-R */ %token CUBE_SYM /* SQL-2003-R */ %token CURDATE /* MYSQL-FUNC */ +%token CURRENT_SYM /* SQL-2003-R */ %token CURRENT_USER /* SQL-2003-R */ +%token CURRENT_ROLE /* SQL-2003-R */ +%token CURRENT_POS_SYM %token CURSOR_SYM /* SQL-2003-R */ %token CURSOR_NAME_SYM /* SQL-2003-N */ %token CURTIME /* MYSQL-FUNC */ @@ -942,10 +1182,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token DELAYED_SYM %token DELAY_KEY_WRITE_SYM %token DELETE_SYM /* SQL-2003-R */ +%token DELETE_DOMAIN_ID_SYM %token DESC /* SQL-2003-N */ %token DESCRIBE /* SQL-2003-R */ %token DES_KEY_FILE %token DETERMINISTIC_SYM /* SQL-2003-R */ +%token DIAGNOSTICS_SYM /* SQL-2003-N */ %token DIRECTORY_SYM %token DISABLE_SYM %token DISCARD @@ -953,6 +1195,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token DISTINCT /* SQL-2003-R */ %token DIV_SYM %token DOUBLE_SYM /* SQL-2003-R */ +%token DO_DOMAIN_IDS_SYM %token DO_SYM %token DROP /* SQL-2003-R */ %token DUAL_SYM @@ -978,11 +1221,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token EVENTS_SYM %token EVENT_SYM %token EVERY_SYM /* SQL-2003-N */ +%token EXCHANGE_SYM %token EXAMINED_SYM %token EXECUTE_SYM /* SQL-2003-R */ %token EXISTS /* SQL-2003-R */ %token EXIT_SYM %token EXPANSION_SYM +%token EXPORT_SYM %token EXTENDED_SYM %token EXTENT_SIZE_SYM %token EXTRACT_SYM /* SQL-2003-N */ @@ -999,6 +1244,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token FORCE_SYM %token FOREIGN /* SQL-2003-R */ %token FOR_SYM /* SQL-2003-R */ +%token FORMAT_SYM %token FOUND_SYM /* SQL-2003-R */ %token FROM %token FULL /* SQL-2003-R */ @@ -1010,6 +1256,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token GEOMETRYCOLLECTION %token GEOMETRY_SYM %token GET_FORMAT /* MYSQL-FUNC */ +%token GET_SYM /* SQL-2003-R */ %token GLOBAL_SYM /* SQL-2003-R */ %token GRANT /* SQL-2003-R */ %token GRANTS @@ -1029,16 +1276,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token HOUR_MINUTE_SYM %token HOUR_SECOND_SYM %token HOUR_SYM /* SQL-2003-R */ +%token ID_SYM /* MYSQL */ %token IDENT %token IDENTIFIED_SYM %token IDENT_QUOTED -%token IF +%token IF_SYM +%token IGNORE_DOMAIN_IDS_SYM %token IGNORE_SYM %token IGNORE_SERVER_IDS_SYM %token IMPORT %token INDEXES %token INDEX_SYM -%token INDEX_STATS_SYM %token INFILE %token INITIAL_SIZE_SYM %token INNER_SYM /* SQL-2003-R */ @@ -1094,6 +1342,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token LOOP_SYM %token LOW_PRIORITY %token MASTER_CONNECT_RETRY_SYM +%token MASTER_GTID_POS_SYM %token MASTER_HOST_SYM %token MASTER_LOG_FILE_SYM %token MASTER_LOG_POS_SYM @@ -1104,11 +1353,14 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token MASTER_SSL_CA_SYM %token MASTER_SSL_CERT_SYM %token MASTER_SSL_CIPHER_SYM +%token MASTER_SSL_CRL_SYM +%token MASTER_SSL_CRLPATH_SYM %token MASTER_SSL_KEY_SYM %token MASTER_SSL_SYM %token MASTER_SSL_VERIFY_SERVER_CERT_SYM %token MASTER_SYM %token MASTER_USER_SYM +%token MASTER_USE_GTID_SYM %token MASTER_HEARTBEAT_PERIOD_SYM %token MATCH /* SQL-2003-R */ %token MAX_CONNECTIONS_PER_HOUR @@ -1117,6 +1369,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token MAX_SIZE_SYM %token MAX_SYM /* SQL-2003-N */ %token MAX_UPDATES_PER_HOUR +%token MAX_STATEMENT_TIME_SYM %token MAX_USER_CONNECTIONS_SYM %token MAX_VALUE_SYM /* SQL-2003-N */ %token MEDIUMBLOB @@ -1150,7 +1403,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token NATURAL /* SQL-2003-R */ %token NCHAR_STRING %token NCHAR_SYM /* SQL-2003-R */ -%token NDBCLUSTER_SYM %token NE /* OPERATOR */ %token NEG %token NEW_SYM /* SQL-2003-R */ @@ -1165,13 +1417,14 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token NO_WRITE_TO_BINLOG %token NULL_SYM /* SQL-2003-R */ %token NUM +%token NUMBER_SYM /* SQL-2003-N */ %token NUMERIC_SYM /* SQL-2003-R */ %token NVARCHAR_SYM %token OFFSET_SYM -%token OLD_PASSWORD +%token OLD_PASSWORD_SYM %token ON /* SQL-2003-R */ -%token ONE_SHOT_SYM %token ONE_SYM +%token ONLY_SYM /* SQL-2003-R */ %token ONLINE_SYM %token OPEN_SYM /* SQL-2003-R */ %token OPTIMIZE @@ -1193,10 +1446,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PARSER_SYM %token PARSE_VCOL_EXPR_SYM %token PARTIAL /* SQL-2003-N */ -%token PARTITIONING_SYM -%token PARTITIONS_SYM %token PARTITION_SYM /* SQL-2003-R */ -%token PASSWORD +%token PARTITIONS_SYM +%token PARTITIONING_SYM +%token PASSWORD_SYM %token PERSISTENT_SYM %token PHASE_SYM %token PLUGINS_SYM @@ -1256,16 +1509,21 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token RESTORE_SYM %token RESTRICT %token RESUME_SYM +%token RETURNED_SQLSTATE_SYM /* SQL-2003-N */ +%token RETURNING_SYM %token RETURNS_SYM /* SQL-2003-R */ %token RETURN_SYM /* SQL-2003-R */ +%token REVERSE_SYM %token REVOKE /* SQL-2003-R */ %token RIGHT /* SQL-2003-R */ +%token ROLE_SYM %token ROLLBACK_SYM /* SQL-2003-R */ %token ROLLUP_SYM /* SQL-2003-R */ %token ROUTINE_SYM /* SQL-2003-N */ %token ROWS_SYM /* SQL-2003-R */ %token ROW_FORMAT_SYM %token ROW_SYM /* SQL-2003-R */ +%token ROW_COUNT_SYM /* SQL-2003-N */ %token RTREE_SYM %token SAVEPOINT_SYM /* SQL-2003-R */ %token SCHEDULE_SYM @@ -1292,6 +1550,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SIGNED_SYM %token SIMPLE_SYM /* SQL-2003-N */ %token SLAVE +%token SLAVES +%token SLAVE_POS_SYM %token SLOW %token SMALLINT /* SQL-2003-R */ %token SNAPSHOT_SYM @@ -1313,10 +1573,15 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SQL_SMALL_RESULT %token SQL_SYM /* SQL-2003-R */ %token SQL_THREAD +%token REF_SYSTEM_ID_SYM %token SSL_SYM %token STARTING %token STARTS_SYM %token START_SYM /* SQL-2003-R */ +%token STATEMENT_SYM +%token STATS_AUTO_RECALC_SYM +%token STATS_PERSISTENT_SYM +%token STATS_SAMPLE_PAGES_SYM %token STATUS_SYM %token STDDEV_SAMP_SYM /* SQL-2003-N */ %token STD_SYM @@ -1339,7 +1604,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token TABLES %token TABLESPACE %token TABLE_REF_PRIORITY -%token TABLE_STATS_SYM %token TABLE_SYM /* SQL-2003-R */ %token TABLE_CHECKSUM_SYM %token TABLE_NAME_SYM /* SQL-2003-N */ @@ -1387,8 +1651,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token UPDATE_SYM /* SQL-2003-R */ %token UPGRADE_SYM %token USAGE /* SQL-2003-N */ -%token USER /* SQL-2003-R */ -%token USER_STATS_SYM +%token USER_SYM /* SQL-2003-R */ %token USE_FRM %token USE_SYM %token USING /* SQL-2003-R */ @@ -1409,6 +1672,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token WAIT_SYM %token WARNINGS %token WEEK_SYM +%token WEIGHT_STRING_SYM %token WHEN_SYM /* SQL-2003-R */ %token WHERE /* SQL-2003-R */ %token WHILE_SYM @@ -1450,7 +1714,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <lex_str> IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM - HEX_NUM HEX_STRING hex_num_or_string + HEX_NUM HEX_STRING LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text IDENT_sys TEXT_STRING_sys TEXT_STRING_literal NCHAR_STRING opt_component key_cache_name @@ -1462,29 +1726,47 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <table> table_ident table_ident_nodb references xid - table_ident_opt_wild + table_ident_opt_wild create_like %type <simple_string> - remember_name remember_end opt_db text_or_password + remember_name remember_end opt_db remember_tok_start + wild_and_where %type <string> - text_string opt_gconcat_separator + text_string hex_or_bin_String opt_gconcat_separator -%type <lex_type> field_def +%type <field_type> type_with_opt_collate int_type real_type field_type + +%type <geom_type> spatial_type %type <num> - type type_with_opt_collate int_type real_type order_dir lock_option - udf_type if_exists opt_local opt_table_options table_options - table_option opt_if_not_exists opt_no_write_to_binlog + order_dir lock_option + udf_type opt_local opt_no_write_to_binlog opt_temporary all_or_any opt_distinct - opt_ignore_leaves fulltext_options spatial_type union_option - start_transaction_opts - union_opt select_derived_init option_type2 + opt_ignore_leaves fulltext_options union_option + opt_not opt_union_order_or_limit + union_opt select_derived_init transaction_access_mode_types opt_natural_language_mode opt_query_expansion opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt optional_flush_tables_arguments opt_dyncol_type dyncol_type opt_time_precision kill_type kill_option int_num + opt_default_time_precision + case_stmt_body opt_bin_mod + opt_if_exists_table_element opt_if_not_exists_table_element + opt_into opt_procedure_clause + +%type <object_ddl_options> + create_or_replace + opt_if_not_exists + opt_if_exists + +/* + Bit field of MYSQL_START_TRANS_OPT_* flags. +*/ +%type <num> opt_start_transaction_option_list +%type <num> start_transaction_option_list +%type <num> start_transaction_option %type <m_yes_no_unk> opt_chain opt_release @@ -1494,6 +1776,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <ulong_num> ulong_num real_ulong_num merge_insert_types + ws_nweights + ws_level_flag_desc ws_level_flag_reverse ws_level_flags + opt_ws_levels ws_level_list ws_level_list_item ws_level_number + ws_level_range ws_level_list_or_range %type <ulonglong_number> ulonglong_num real_ulonglong_num size_number @@ -1504,13 +1790,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); replace_lock_option opt_low_priority insert_lock_option load_data_lock %type <item> - literal text_literal insert_ident order_ident + literal text_literal insert_ident order_ident temporal_literal simple_ident expr opt_expr opt_else sum_expr in_sum_expr variable variable_aux bool_pri predicate bit_expr table_wild simple_expr udf_expr expr_or_default set_expr_or_default - param_marker geometry_function + geometry_function signed_literal now_or_signed_literal opt_escape sp_opt_default simple_ident_nospvar simple_ident_q @@ -1521,6 +1807,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); function_call_generic function_call_conflict kill_expr signal_allowed_expr + simple_target_specification + condition_number + +%type <item_param> param_marker %type <item_num> NUM_literal @@ -1533,13 +1823,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); option_type opt_var_type opt_var_ident_type %type <key_type> - normal_key_type opt_unique constraint_key_type fulltext spatial + opt_unique constraint_key_type fulltext spatial %type <key_alg> - btree_or_rtree + btree_or_rtree opt_key_algorithm_clause opt_USING_key_algorithm %type <string_list> - using_list + using_list opt_use_partition use_partition %type <key_part> key_part @@ -1567,11 +1857,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <symbol> keyword keyword_sp -%type <lex_user> user grant_user +%type <lex_user> user grant_user grant_role user_or_role current_role + admin_option_for_role user_maybe_role %type <charset> opt_collate charset_name + charset_or_alias charset_name_or_default old_or_new_charset_name old_or_new_charset_name_or_default @@ -1592,13 +1884,21 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <dyncol_def_list> dyncall_create_list +%type <myvar> select_outvar + %type <NONE> + analyze_stmt_command query verb_clause create change select do drop insert replace insert2 - insert_values update delete truncate rename + insert_values update delete truncate rename compound_statement show describe load alter optimize keycache preload flush reset purge begin commit rollback savepoint release slave master_def master_defs master_file_def slave_until_opts - repair analyze check start checksum + repair analyze opt_with_admin opt_with_admin_option + analyze_table_list analyze_table_elem_spec + opt_persistent_stat_clause persistent_stat_spec + persistent_column_stat_spec persistent_index_stat_spec + table_column_list table_index_list table_index_name + check start checksum field_list field_list_item field_spec kill column_def key_def keycache_list keycache_list_or_parts assign_to_keycache assign_to_keycache_parts @@ -1606,21 +1906,22 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); select_item_list select_item values_list no_braces opt_limit_clause delete_limit_clause fields opt_values values procedure_list procedure_list2 procedure_item - handler + field_def handler opt_generated_always opt_precision opt_ignore opt_column opt_restrict grant revoke set lock unlock string_list field_options field_option - field_opt_list opt_binary ascii unicode table_lock_list table_lock + field_opt_list opt_binary table_lock_list table_lock ref_list opt_match_clause opt_on_update_delete use opt_delete_options opt_delete_option varchar nchar nvarchar opt_outer table_list table_name table_alias_ref_list table_alias_ref - opt_option opt_place + opt_place opt_attribute opt_attribute_list attribute column_list column_list_id opt_column_list grant_privileges grant_ident grant_list grant_option - object_privilege object_privilege_list user_list rename_list + object_privilege object_privilege_list user_list user_and_role_list + rename_list table_or_tables clear_privileges flush_options flush_option - opt_with_read_lock flush_options_list + opt_flush_lock flush_lock flush_options_list equal optional_braces - opt_mi_check_type opt_to mi_check_types normal_join + opt_mi_check_type opt_to mi_check_types table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan single_multi table_wild_list table_wild_one opt_wild @@ -1628,60 +1929,77 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); precision subselect_start opt_and charset subselect_end select_var_list select_var_list_init help field_length opt_field_length - opt_extended_describe + opt_extended_describe shutdown + opt_format_json prepare prepare_src execute deallocate statement sp_suid sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa opt_field_or_var_spec fields_or_vars opt_load_data_set_spec - view_replace_or_algorithm view_replace view_algorithm view_or_trigger_or_sp_or_event definer_tail no_definer_tail view_suid view_tail view_list_opt view_list view_select - view_check_option trigger_tail sp_tail sf_tail udf_tail event_tail + view_check_option trigger_tail sp_tail sf_tail event_tail + udf_tail udf_tail2 install uninstall partition_entry binlog_base64_event - init_key_options normal_key_options normal_key_opts all_key_opt + normal_key_options normal_key_opts all_key_opt spatial_key_options fulltext_key_options normal_key_opt fulltext_key_opt spatial_key_opt fulltext_key_opts spatial_key_opts keep_gcc_happy key_using_alg part_column_list server_def server_options_list server_option - definer_opt no_definer definer + definer_opt no_definer definer get_diagnostics parse_vcol_expr vcol_opt_specifier vcol_opt_attribute vcol_opt_attribute_list vcol_attribute + explainable_command + opt_delete_gtid_domain END_OF_INPUT %type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt %type <NONE> sp_proc_stmt_statement sp_proc_stmt_return +%type <NONE> sp_proc_stmt_compound_ok %type <NONE> sp_proc_stmt_if -%type <NONE> sp_labeled_control sp_proc_stmt_unlabeled -%type <NONE> sp_labeled_block sp_unlabeled_block +%type <NONE> sp_labeled_control sp_unlabeled_control +%type <NONE> sp_labeled_block sp_unlabeled_block sp_unlabeled_block_not_atomic %type <NONE> sp_proc_stmt_leave %type <NONE> sp_proc_stmt_iterate %type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close -%type <NONE> case_stmt_specification simple_case_stmt searched_case_stmt +%type <NONE> case_stmt_specification +%type <NONE> loop_body while_body repeat_body -%type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list -%type <spcondtype> sp_cond sp_hcond sqlstate signal_value opt_signal_value +%type <num> sp_decl_idents sp_handler_type sp_hcond_list +%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value %type <spblock> sp_decls sp_decl %type <lex> sp_cursor_stmt %type <spname> sp_name +%type <splabel> sp_block_content +%type <spvar> sp_param_name_and_type +%type <spvar_mode> sp_opt_inout %type <index_hint> index_hint_type -%type <num> index_hint_clause +%type <num> index_hint_clause normal_join inner_join %type <filetype> data_or_xml %type <NONE> signal_stmt resignal_stmt %type <diag_condition_item_name> signal_condition_information_item_name +%type <diag_area> which_area; +%type <diag_info> diagnostics_information; +%type <stmt_info_item> statement_information_item; +%type <stmt_info_item_name> statement_information_item_name; +%type <stmt_info_list> statement_information; +%type <cond_info_item> condition_information_item; +%type <cond_info_item_name> condition_information_item_name; +%type <cond_info_list> condition_information; + %type <NONE> '-' '+' '*' '/' '%' '(' ')' ',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_SYM BETWEEN_SYM CASE_SYM THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM DELETE_SYM - -%type <is_not_empty> opt_union_order_or_limit + ROLE_SYM %% + /* Indentation of grammar rules: @@ -1708,10 +2026,8 @@ query: { if (!thd->bootstrap && (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT))) - { - my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_EMPTY_QUERY, MYF(0))); + thd->lex->sql_command= SQLCOM_EMPTY_QUERY; YYLIP->found_semicolon= NULL; } @@ -1755,12 +2071,14 @@ opt_end_of_input: verb_clause: statement | begin + | compound_statement ; -/* Verb clauses, except begin */ +/* Verb clauses, except begin and compound_statement */ statement: alter | analyze + | analyze_stmt_command | binlog_base64_event | call | change @@ -1775,6 +2093,7 @@ statement: | drop | execute | flush + | get_diagnostics | grant | handler | help @@ -1804,6 +2123,7 @@ statement: | set | signal_stmt | show + | shutdown | slave | start | truncate @@ -1877,8 +2197,9 @@ execute_var_ident: '@' ident_or_text { LEX *lex=Lex; - LEX_STRING *lexstr= (LEX_STRING*)sql_memdup(&$2, sizeof(LEX_STRING)); - if (!lexstr || lex->prepared_stmt_params.push_back(lexstr)) + LEX_STRING *lexstr= (LEX_STRING*)thd->memdup(&$2, sizeof(LEX_STRING)); + if (!lexstr || lex->prepared_stmt_params.push_back(lexstr, + thd->mem_root)) MYSQL_YYABORT; } ; @@ -1889,10 +2210,7 @@ help: HELP_SYM { if (Lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "HELP"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HELP")); } ident_or_text { @@ -1905,7 +2223,7 @@ help: /* change master */ change: - CHANGE MASTER_SYM TO_SYM + CHANGE MASTER_SYM optional_connection_name TO_SYM { Lex->sql_command = SQLCOM_CHANGE_MASTER; } @@ -1969,32 +2287,36 @@ master_def: Lex->mi.ssl_verify_server_cert= $3 ? LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE; } + | MASTER_SSL_CRL_SYM '=' TEXT_STRING_sys + { + Lex->mi.ssl_crl= $3.str; + } + | MASTER_SSL_CRLPATH_SYM '=' TEXT_STRING_sys + { + Lex->mi.ssl_crlpath= $3.str; + } | MASTER_HEARTBEAT_PERIOD_SYM '=' NUM_literal { Lex->mi.heartbeat_period= (float) $3->val_real(); if (Lex->mi.heartbeat_period > SLAVE_MAX_HEARTBEAT_PERIOD || Lex->mi.heartbeat_period < 0.0) - { - const char format[]= "%d"; - char buf[4*sizeof(SLAVE_MAX_HEARTBEAT_PERIOD) + sizeof(format)]; - sprintf(buf, format, SLAVE_MAX_HEARTBEAT_PERIOD); - my_error(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, MYF(0), buf); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, MYF(0), + SLAVE_MAX_HEARTBEAT_PERIOD)); + if (Lex->mi.heartbeat_period > slave_net_timeout) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX, - ER(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX)); + ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX)); } if (Lex->mi.heartbeat_period < 0.001) { if (Lex->mi.heartbeat_period != 0.0) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN, - ER(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN)); + ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN)); Lex->mi.heartbeat_period= 0.0; } Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_DISABLE; @@ -2005,6 +2327,14 @@ master_def: { Lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; } + | DO_DOMAIN_IDS_SYM '=' '(' do_domain_id_list ')' + { + Lex->mi.repl_do_domain_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; + } + | IGNORE_DOMAIN_IDS_SYM '=' '(' ignore_domain_id_list ')' + { + Lex->mi.repl_ignore_domain_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; + } | master_file_def ; @@ -2020,6 +2350,33 @@ ignore_server_id: { insert_dynamic(&Lex->mi.repl_ignore_server_ids, (uchar*) &($1)); } + ; + +do_domain_id_list: + /* Empty */ + | do_domain_id + | do_domain_id_list ',' do_domain_id + ; + +do_domain_id: + ulong_num + { + insert_dynamic(&Lex->mi.repl_do_domain_ids, (uchar*) &($1)); + } + ; + +ignore_domain_id_list: + /* Empty */ + | ignore_domain_id + | ignore_domain_id_list ',' ignore_domain_id + ; + +ignore_domain_id: + ulong_num + { + insert_dynamic(&Lex->mi.repl_ignore_domain_ids, (uchar*) &($1)); + } + ; master_file_def: MASTER_LOG_FILE_SYM '=' TEXT_STRING_sys @@ -2028,7 +2385,6 @@ master_file_def: } | MASTER_LOG_POS_SYM '=' ulonglong_num { - Lex->mi.pos = $3; /* If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it instead of causing subsequent errors. @@ -2040,7 +2396,7 @@ master_file_def: from 0" (4 in fact), unspecified means "don't change the position (keep the preceding value)"). */ - Lex->mi.pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.pos); + Lex->mi.pos= MY_MAX(BIN_LOG_HEADER_SIZE, $3); } | RELAY_LOG_FILE_SYM '=' TEXT_STRING_sys { @@ -2050,86 +2406,119 @@ master_file_def: { Lex->mi.relay_log_pos = $3; /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */ - Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos); + Lex->mi.relay_log_pos= MY_MAX(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos); + } + | MASTER_USE_GTID_SYM '=' CURRENT_POS_SYM + { + if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid")); + Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_CURRENT_POS; } + | MASTER_USE_GTID_SYM '=' SLAVE_POS_SYM + { + if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid")); + Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_SLAVE_POS; + } + | MASTER_USE_GTID_SYM '=' NO_SYM + { + if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid")); + Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_NO; + } + ; + +optional_connection_name: + /* empty */ + { + LEX *lex= thd->lex; + lex->mi.connection_name= null_lex_str; + } + | connection_name ; +connection_name: + TEXT_STRING_sys + { + Lex->mi.connection_name= $1; +#ifdef HAVE_REPLICATION + if (check_master_connection_name(&$1)) + my_yyabort_error((ER_WRONG_ARGUMENTS, MYF(0), "MASTER_CONNECTION_NAME")); +#endif + } + ; + /* create a table */ create: - CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident + create_or_replace opt_temporary TABLE_SYM opt_if_not_exists table_ident { LEX *lex= thd->lex; - lex->sql_command= SQLCOM_CREATE_TABLE; + lex->create_info.init(); + if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4)) + MYSQL_YYABORT; if (!lex->select_lex.add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; + lex->alter_info.reset(); /* - For CREATE TABLE, an non-existing table is not an error. - Instruct open_tables() to just take an MDL lock if the - table does not exist. + For CREATE TABLE we should not open the table even if it exists. + If the table exists, we should either not create it or replace it */ - lex->query_tables->open_strategy= TABLE_LIST::OPEN_IF_EXISTS; - lex->alter_info.reset(); - lex->col_list.empty(); - lex->change=NullS; - bzero((char*) &lex->create_info,sizeof(lex->create_info)); - lex->create_info.options=$2 | $4; + lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; lex->create_info.default_table_charset= NULL; - lex->name.str= 0; - lex->name.length= 0; + lex->name= null_lex_str; lex->create_last_non_select_table= lex->last_table(); } - create2 + create_body { LEX *lex= thd->lex; lex->current_select= &lex->select_lex; if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && !lex->create_info.db_type) { - lex->create_info.db_type= ha_default_handlerton(thd); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + lex->create_info.use_default_db_type(thd); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WARN_USING_OTHER_HANDLER, - ER(ER_WARN_USING_OTHER_HANDLER), + ER_THD(thd, ER_WARN_USING_OTHER_HANDLER), hton_name(lex->create_info.db_type)->str, $5->table.str); } create_table_set_open_action_and_adjust_tables(lex); } - | CREATE opt_unique INDEX_SYM ident key_alg ON table_ident + | create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident + opt_key_algorithm_clause + ON table_ident { - if (add_create_index_prepare(Lex, $7)) + if (add_create_index_prepare(Lex, $8)) MYSQL_YYABORT; - } - '(' key_list ')' normal_key_options - { - if (add_create_index(Lex, $2, $4)) + if (Lex->add_create_index($2, $5, $6, $1 | $4)) MYSQL_YYABORT; } - | CREATE fulltext INDEX_SYM ident init_key_options ON - table_ident + '(' key_list ')' normal_key_options + opt_index_lock_algorithm { } + | create_or_replace fulltext INDEX_SYM opt_if_not_exists ident + ON table_ident { if (add_create_index_prepare(Lex, $7)) MYSQL_YYABORT; - } - '(' key_list ')' fulltext_key_options - { - if (add_create_index(Lex, $2, $4)) + if (Lex->add_create_index($2, $5, HA_KEY_ALG_UNDEF, $1 | $4)) MYSQL_YYABORT; } - | CREATE spatial INDEX_SYM ident init_key_options ON - table_ident + '(' key_list ')' fulltext_key_options + opt_index_lock_algorithm { } + | create_or_replace spatial INDEX_SYM opt_if_not_exists ident + ON table_ident { if (add_create_index_prepare(Lex, $7)) MYSQL_YYABORT; - } - '(' key_list ')' spatial_key_options - { - if (add_create_index(Lex, $2, $4)) + if (Lex->add_create_index($2, $5, HA_KEY_ALG_UNDEF, $1 | $4)) MYSQL_YYABORT; } - | CREATE DATABASE opt_if_not_exists ident + '(' key_list ')' spatial_key_options + opt_index_lock_algorithm { } + | create_or_replace DATABASE opt_if_not_exists ident { Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; @@ -2137,21 +2526,29 @@ create: opt_create_database_options { LEX *lex=Lex; - lex->sql_command=SQLCOM_CREATE_DB; + if (lex->set_command_with_check(SQLCOM_CREATE_DB, 0, $1 | $3)) + MYSQL_YYABORT; lex->name= $4; - lex->create_info.options=$3; } - | CREATE + | create_or_replace { - Lex->create_view_mode= VIEW_CREATE_NEW; + Lex->create_info.set($1); + Lex->create_view_mode= ($1.or_replace() ? VIEW_CREATE_OR_REPLACE : + VIEW_CREATE_NEW); Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED; Lex->create_view_suid= TRUE; } - view_or_trigger_or_sp_or_event - {} - | CREATE USER clear_privileges grant_list + view_or_trigger_or_sp_or_event { } + | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list { - Lex->sql_command = SQLCOM_CREATE_USER; + if (Lex->set_command_with_check(SQLCOM_CREATE_USER, $1 | $3)) + MYSQL_YYABORT; + } + | create_or_replace ROLE_SYM opt_if_not_exists + clear_privileges role_list opt_with_admin + { + if (Lex->set_command_with_check(SQLCOM_CREATE_ROLE, $1 | $3)) + MYSQL_YYABORT; } | CREATE LOGFILE_SYM GROUP_SYM logfile_group_info { @@ -2161,23 +2558,21 @@ create: { Lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE; } - | CREATE server_def - { - Lex->sql_command= SQLCOM_CREATE_SERVER; - } + | create_or_replace { Lex->set_command(SQLCOM_CREATE_SERVER, $1); } + server_def + { } ; server_def: - SERVER_SYM - ident_or_text - FOREIGN DATA_SYM WRAPPER_SYM - ident_or_text - OPTIONS_SYM '(' server_options_list ')' + SERVER_SYM opt_if_not_exists ident_or_text { - Lex->server_options.server_name= $2.str; - Lex->server_options.server_name_length= $2.length; - Lex->server_options.scheme= $6.str; + if (Lex->add_create_options_with_check($2)) + MYSQL_YYABORT; + Lex->server_options.reset($3); } + FOREIGN DATA_SYM WRAPPER_SYM ident_or_text + OPTIONS_SYM '(' server_options_list ')' + { Lex->server_options.scheme= $8; } ; server_options_list: @@ -2186,29 +2581,35 @@ server_options_list: ; server_option: - USER TEXT_STRING_sys + USER_SYM TEXT_STRING_sys { - Lex->server_options.username= $2.str; + MYSQL_YYABORT_UNLESS(Lex->server_options.username.str == 0); + Lex->server_options.username= $2; } | HOST_SYM TEXT_STRING_sys { - Lex->server_options.host= $2.str; + MYSQL_YYABORT_UNLESS(Lex->server_options.host.str == 0); + Lex->server_options.host= $2; } | DATABASE TEXT_STRING_sys { - Lex->server_options.db= $2.str; + MYSQL_YYABORT_UNLESS(Lex->server_options.db.str == 0); + Lex->server_options.db= $2; } | OWNER_SYM TEXT_STRING_sys { - Lex->server_options.owner= $2.str; + MYSQL_YYABORT_UNLESS(Lex->server_options.owner.str == 0); + Lex->server_options.owner= $2; } - | PASSWORD TEXT_STRING_sys + | PASSWORD_SYM TEXT_STRING_sys { - Lex->server_options.password= $2.str; + MYSQL_YYABORT_UNLESS(Lex->server_options.password.str == 0); + Lex->server_options.password= $2; } | SOCKET_SYM TEXT_STRING_sys { - Lex->server_options.socket= $2.str; + MYSQL_YYABORT_UNLESS(Lex->server_options.socket.str == 0); + Lex->server_options.socket= $2; } | PORT_SYM ulong_num { @@ -2222,7 +2623,8 @@ event_tail: LEX *lex=Lex; lex->stmt_definition_begin= $1; - lex->create_info.options= $3; + if (lex->add_create_options_with_check($3)) + MYSQL_YYABORT; if (!(lex->event_parse_data= Event_parse_data::new_instance(thd))) MYSQL_YYABORT; lex->event_parse_data->identifier= $4; @@ -2285,7 +2687,7 @@ opt_ev_status: ev_starts: /* empty */ { - Item *item= new (thd->mem_root) Item_func_now_local(0); + Item *item= new (thd->mem_root) Item_func_now_local(thd, 0); if (item == NULL) MYSQL_YYABORT; Lex->event_parse_data->item_starts= item; @@ -2310,16 +2712,11 @@ opt_ev_on_completion: ; ev_on_completion: - ON COMPLETION_SYM PRESERVE_SYM + ON COMPLETION_SYM opt_not PRESERVE_SYM { - Lex->event_parse_data->on_completion= - Event_parse_data::ON_COMPLETION_PRESERVE; - $$= 1; - } - | ON COMPLETION_SYM NOT_SYM PRESERVE_SYM - { - Lex->event_parse_data->on_completion= - Event_parse_data::ON_COMPLETION_DROP; + Lex->event_parse_data->on_completion= $3 + ? Event_parse_data::ON_COMPLETION_DROP + : Event_parse_data::ON_COMPLETION_PRESERVE; $$= 1; } ; @@ -2356,26 +2753,15 @@ ev_sql_stmt: - CREATE PROCEDURE ... BEGIN DROP EVENT ... END| */ if (lex->sphead) - { - my_error(ER_EVENT_RECURSION_FORBIDDEN, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0))); - if (!(lex->sphead= new sp_head())) + if (!make_sp_head(thd, lex->event_parse_data->identifier, TYPE_ENUM_PROCEDURE)) MYSQL_YYABORT; - lex->sphead->reset_thd_mem_root(thd); - lex->sphead->init(lex); - lex->sphead->init_sp_name(thd, lex->event_parse_data->identifier); - - lex->sphead->m_type= TYPE_ENUM_PROCEDURE; - - bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); - lex->sphead->m_chistics= &lex->sp_chistics; - + lex->sp_chistics.suid= SP_IS_SUID; //always the definer! lex->sphead->set_body_start(thd, lip->get_cpp_ptr()); } - ev_sql_stmt_inner + sp_proc_stmt { LEX *lex= thd->lex; @@ -2383,28 +2769,10 @@ ev_sql_stmt: lex->sphead->set_stmt_end(thd); lex->sphead->restore_thd_mem_root(thd); - lex->sp_chistics.suid= SP_IS_SUID; //always the definer! - lex->event_parse_data->body_changed= TRUE; } ; -ev_sql_stmt_inner: - sp_proc_stmt_statement - | sp_proc_stmt_return - | sp_proc_stmt_if - | case_stmt_specification - | sp_labeled_block - | sp_unlabeled_block - | sp_labeled_control - | sp_proc_stmt_unlabeled - | sp_proc_stmt_leave - | sp_proc_stmt_iterate - | sp_proc_stmt_open - | sp_proc_stmt_fetch - | sp_proc_stmt_close - ; - clear_privileges: /* Nothing */ { @@ -2424,15 +2792,10 @@ sp_name: ident '.' ident { if (!$1.str || check_db_name(&$1)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $1.str)); if (check_routine_name(&$3)) - { MYSQL_YYABORT; - } - $$= new sp_name($1, $3, true); + $$= new (thd->mem_root) sp_name($1, $3, true); if ($$ == NULL) MYSQL_YYABORT; $$->init_qname(thd); @@ -2447,7 +2810,7 @@ sp_name: } if (lex->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; - $$= new sp_name(db, $1, false); + $$= new (thd->mem_root) sp_name(db, $1, false); if ($$ == NULL) MYSQL_YYABORT; $$->init_qname(thd); @@ -2485,8 +2848,7 @@ sp_chistic: /* Create characteristics */ sp_c_chistic: sp_chistic { } - | DETERMINISTIC_SYM { Lex->sp_chistics.detistic= TRUE; } - | not DETERMINISTIC_SYM { Lex->sp_chistics.detistic= FALSE; } + | opt_not DETERMINISTIC_SYM { Lex->sp_chistics.detistic= ! $1; } ; sp_suid: @@ -2527,11 +2889,11 @@ opt_sp_cparams: sp_cparams: sp_cparams ',' expr { - Lex->value_list.push_back($3); + Lex->value_list.push_back($3, thd->mem_root); } | expr { - Lex->value_list.push_back($1); + Lex->value_list.push_back($1, thd->mem_root); } ; @@ -2542,54 +2904,40 @@ sp_fdparam_list: ; sp_fdparams: - sp_fdparams ',' sp_fdparam - | sp_fdparam + sp_fdparams ',' sp_param_name_and_type + | sp_param_name_and_type ; -sp_init_param: - /* Empty */ +sp_param_name_and_type: + ident { LEX *lex= Lex; + sp_pcontext *spc= lex->spcont; - lex->length= 0; - lex->dec= 0; - lex->type= 0; - - lex->default_value= 0; - lex->on_update_value= 0; + if (spc->find_variable($1, TRUE)) + my_yyabort_error((ER_SP_DUP_PARAM, MYF(0), $1.str)); - lex->comment= null_lex_str; - lex->charset= NULL; + sp_variable *spvar= spc->add_variable(thd, $1); - lex->interval_list.empty(); - lex->uint_geom_type= 0; - lex->vcol_info= 0; + lex->init_last_field(&spvar->field_def, $1.str, + thd->variables.collation_database); + $<spvar>$= spvar; } - ; - -sp_fdparam: - ident sp_init_param type_with_opt_collate + type_with_opt_collate { LEX *lex= Lex; - sp_pcontext *spc= lex->spcont; - - if (spc->find_variable(&$1, TRUE)) - { - my_error(ER_SP_DUP_PARAM, MYF(0), $1.str); - MYSQL_YYABORT; - } - sp_variable_t *spvar= spc->push_variable(&$1, - (enum enum_field_types)$3, - sp_param_in); + sp_variable *spvar= $<spvar>2; - if (lex->sphead->fill_field_definition(thd, lex, - (enum enum_field_types) $3, - &spvar->field_def)) + spvar->type= $3; + if (lex->sphead->fill_field_definition(thd, lex, $3, + lex->last_field)) { MYSQL_YYABORT; } spvar->field_def.field_name= spvar->name.str; spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; + + $$= spvar; } ; @@ -2605,36 +2953,14 @@ sp_pdparams: ; sp_pdparam: - sp_opt_inout sp_init_param ident type_with_opt_collate - { - LEX *lex= Lex; - sp_pcontext *spc= lex->spcont; - - if (spc->find_variable(&$3, TRUE)) - { - my_error(ER_SP_DUP_PARAM, MYF(0), $3.str); - MYSQL_YYABORT; - } - sp_variable_t *spvar= spc->push_variable(&$3, - (enum enum_field_types)$4, - (sp_param_mode_t)$1); - - if (lex->sphead->fill_field_definition(thd, lex, - (enum enum_field_types) $4, - &spvar->field_def)) - { - MYSQL_YYABORT; - } - spvar->field_def.field_name= spvar->name.str; - spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; - } + sp_opt_inout sp_param_name_and_type { $2->mode=$1; } ; sp_opt_inout: - /* Empty */ { $$= sp_param_in; } - | IN_SYM { $$= sp_param_in; } - | OUT_SYM { $$= sp_param_out; } - | INOUT_SYM { $$= sp_param_inout; } + /* Empty */ { $$= sp_variable::MODE_IN; } + | IN_SYM { $$= sp_variable::MODE_IN; } + | OUT_SYM { $$= sp_variable::MODE_OUT; } + | INOUT_SYM { $$= sp_variable::MODE_INOUT; } ; sp_proc_stmts: @@ -2659,17 +2985,9 @@ sp_decls: shift/reduce conflicts with the wrong result. (And we get better error handling this way.) */ if (($2.vars || $2.conds) && ($1.curs || $1.hndlrs)) - { /* Variable or condition following cursor or handler */ - my_message(ER_SP_VARCOND_AFTER_CURSHNDLR, - ER(ER_SP_VARCOND_AFTER_CURSHNDLR), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_VARCOND_AFTER_CURSHNDLR, MYF(0))); if ($2.curs && $1.hndlrs) - { /* Cursor following handler */ - my_message(ER_SP_CURSOR_AFTER_HANDLER, - ER(ER_SP_CURSOR_AFTER_HANDLER), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_CURSOR_AFTER_HANDLER, MYF(0))); $$.vars= $1.vars + $2.vars; $$.conds= $1.conds + $2.conds; $$.hndlrs= $1.hndlrs + $2.hndlrs; @@ -2681,9 +2999,17 @@ sp_decl: DECLARE_SYM sp_decl_idents { LEX *lex= Lex; + sp_pcontext *pctx= lex->spcont; + + // get the last variable: + uint num_vars= pctx->context_var_count(); + uint var_idx= pctx->var_context2runtime(num_vars - 1); + sp_variable *spvar= pctx->find_variable(var_idx); lex->sphead->reset_lex(thd); - lex->spcont->declare_var_boundary($2); + pctx->declare_var_boundary($2); + thd->lex->init_last_field(&spvar->field_def, spvar->name.str, + thd->variables.collation_database); } type_with_opt_collate sp_opt_default @@ -2691,12 +3017,12 @@ sp_decl: LEX *lex= Lex; sp_pcontext *pctx= lex->spcont; uint num_vars= pctx->context_var_count(); - enum enum_field_types var_type= (enum enum_field_types) $4; + enum enum_field_types var_type= $4; Item *dflt_value_item= $5; if (!dflt_value_item) { - dflt_value_item= new (thd->mem_root) Item_null(); + dflt_value_item= new (thd->mem_root) Item_null(thd); if (dflt_value_item == NULL) MYSQL_YYABORT; /* QQ Set to the var_type with null_value? */ @@ -2705,13 +3031,18 @@ sp_decl: for (uint i = num_vars-$2 ; i < num_vars ; i++) { uint var_idx= pctx->var_context2runtime(i); - sp_variable_t *spvar= pctx->find_variable(var_idx); + sp_variable *spvar= pctx->find_variable(var_idx); + bool last= i == num_vars - 1; if (!spvar) MYSQL_YYABORT; + if (!last) + spvar->field_def= *lex->last_field; + spvar->type= var_type; - spvar->dflt= dflt_value_item; + spvar->default_value= dflt_value_item; + spvar->field_def.field_name= spvar->name.str; if (lex->sphead->fill_field_definition(thd, lex, var_type, &spvar->field_def)) @@ -2719,20 +3050,15 @@ sp_decl: MYSQL_YYABORT; } - spvar->field_def.field_name= spvar->name.str; spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; /* The last instruction is responsible for freeing LEX. */ - sp_instr_set *is= new sp_instr_set(lex->sphead->instructions(), - pctx, - var_idx, - dflt_value_item, - var_type, - lex, - (i == num_vars - 1)); - if (is == NULL || - lex->sphead->add_instr(is)) + sp_instr_set *is= new (thd->mem_root) + sp_instr_set(lex->sphead->instructions(), + pctx, var_idx, dflt_value_item, + var_type, lex, last); + if (is == NULL || lex->sphead->add_instr(is)) MYSQL_YYABORT; } @@ -2747,12 +3073,9 @@ sp_decl: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_cond(&$2, TRUE)) - { - my_error(ER_SP_DUP_COND, MYF(0), $2.str); - MYSQL_YYABORT; - } - if(thd->lex->spcont->push_cond(&$2, $5)) + if (spc->find_condition($2, TRUE)) + my_yyabort_error((ER_SP_DUP_COND, MYF(0), $2.str)); + if(spc->add_condition(thd, $2, $5)) MYSQL_YYABORT; $$.vars= $$.hndlrs= $$.curs= 0; $$.conds= 1; @@ -2762,21 +3085,26 @@ sp_decl: LEX *lex= Lex; sp_head *sp= lex->sphead; - lex->spcont= lex->spcont->push_context(LABEL_HANDLER_SCOPE); + sp_handler *h= lex->spcont->add_handler(thd, + (sp_handler::enum_type) $2); + + lex->spcont= lex->spcont->push_context(thd, + sp_pcontext::HANDLER_SCOPE); sp_pcontext *ctx= lex->spcont; sp_instr_hpush_jump *i= - new sp_instr_hpush_jump(sp->instructions(), ctx, $2, - ctx->current_var_count()); + new (thd->mem_root) sp_instr_hpush_jump(sp->instructions(), + ctx, h); + if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; /* For continue handlers, mark end of handler scope. */ - if ($2 == SP_HANDLER_CONTINUE && + if ($2 == sp_handler::CONTINUE && sp->push_backpatch(i, ctx->last_label())) MYSQL_YYABORT; - if (sp->push_backpatch(i, ctx->push_label(empty_c_string, 0))) + if (sp->push_backpatch(i, ctx->push_label(thd, empty_lex_str, 0))) MYSQL_YYABORT; } sp_hcond_list sp_proc_stmt @@ -2784,20 +3112,21 @@ sp_decl: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; - sp_label_t *hlab= lex->spcont->pop_label(); /* After this hdlr */ + sp_label *hlab= lex->spcont->pop_label(); /* After this hdlr */ sp_instr_hreturn *i; - if ($2 == SP_HANDLER_CONTINUE) + if ($2 == sp_handler::CONTINUE) { - i= new sp_instr_hreturn(sp->instructions(), ctx, - ctx->current_var_count()); + i= new (thd->mem_root) + sp_instr_hreturn(sp->instructions(), ctx); if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; } else { /* EXIT or UNDO handler, just jump to the end of the block */ - i= new sp_instr_hreturn(sp->instructions(), ctx, 0); + i= new (thd->mem_root) + sp_instr_hreturn(sp->instructions(), ctx); if (i == NULL || sp->add_instr(i) || sp->push_backpatch(i, lex->spcont->last_label())) /* Block end */ @@ -2808,8 +3137,7 @@ sp_decl: lex->spcont= ctx->pop_context(); $$.vars= $$.conds= $$.curs= 0; - $$.hndlrs= $6; - lex->spcont->add_handlers($6); + $$.hndlrs= 1; } | DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt { @@ -2819,17 +3147,13 @@ sp_decl: uint offp; sp_instr_cpush *i; - if (ctx->find_cursor(&$2, &offp, TRUE)) - { - my_error(ER_SP_DUP_CURS, MYF(0), $2.str); - delete $5; - MYSQL_YYABORT; - } - i= new sp_instr_cpush(sp->instructions(), ctx, $5, - ctx->current_cursor_count()); - if (i == NULL || - sp->add_instr(i) || - ctx->push_cursor(&$2)) + if (ctx->find_cursor($2, &offp, TRUE)) + my_yyabort_error((ER_SP_DUP_CURS, MYF(0), $2.str)); + + i= new (thd->mem_root) + sp_instr_cpush(sp->instructions(), ctx, $5, + ctx->current_cursor_count()); + if (i == NULL || sp->add_instr(i) || ctx->add_cursor($2)) MYSQL_YYABORT; $$.vars= $$.conds= $$.hndlrs= 0; $$.curs= 1; @@ -2847,11 +3171,7 @@ sp_cursor_stmt: DBUG_ASSERT(lex->sql_command == SQLCOM_SELECT); if (lex->result) - { - my_message(ER_SP_BAD_CURSOR_SELECT, ER(ER_SP_BAD_CURSOR_SELECT), - MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BAD_CURSOR_SELECT, MYF(0))); lex->sp_lex_in_use= TRUE; $$= lex; if (lex->sphead->restore_lex(thd)) @@ -2860,9 +3180,9 @@ sp_cursor_stmt: ; sp_handler_type: - EXIT_SYM { $$= SP_HANDLER_EXIT; } - | CONTINUE_SYM { $$= SP_HANDLER_CONTINUE; } - /*| UNDO_SYM { QQ No yet } */ + EXIT_SYM { $$= sp_handler::EXIT; } + | CONTINUE_SYM { $$= sp_handler::CONTINUE; } + /*| UNDO_SYM { QQ No yet } */ ; sp_hcond_list: @@ -2879,19 +3199,11 @@ sp_hcond_element: sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont->parent_context(); - if (ctx->find_handler($1)) - { - my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0)); - MYSQL_YYABORT; - } - else - { - sp_instr_hpush_jump *i= - (sp_instr_hpush_jump *)sp->last_instruction(); + if (ctx->check_duplicate_handler($1)) + my_yyabort_error((ER_SP_DUP_HANDLER, MYF(0))); - i->add_condition($1); - ctx->push_handler($1); - } + sp_instr_hpush_jump *i= (sp_instr_hpush_jump *)sp->last_instruction(); + i->add_condition($1); } ; @@ -2899,15 +3211,10 @@ sp_cond: ulong_num { /* mysql errno */ if ($1 == 0) - { - my_error(ER_WRONG_VALUE, MYF(0), "CONDITION", "0"); - MYSQL_YYABORT; - } - $$= (sp_cond_type_t *) thd->alloc(sizeof(sp_cond_type_t)); + my_yyabort_error((ER_WRONG_VALUE, MYF(0), "CONDITION", "0")); + $$= new (thd->mem_root) sp_condition_value($1); if ($$ == NULL) MYSQL_YYABORT; - $$->type= sp_cond_type_t::number; - $$->mysqlerr= $1; } | sqlstate ; @@ -2915,17 +3222,19 @@ sp_cond: sqlstate: SQLSTATE_SYM opt_value TEXT_STRING_literal { /* SQLSTATE */ - if (!sp_cond_check(&$3)) - { - my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str); - MYSQL_YYABORT; - } - $$= (sp_cond_type_t *) thd->alloc(sizeof(sp_cond_type_t)); + + /* + An error is triggered: + - if the specified string is not a valid SQLSTATE, + - or if it represents the completion condition -- it is not + allowed to SIGNAL, or declare a handler for the completion + condition. + */ + if (!is_sqlstate_valid(&$3) || is_sqlstate_completion($3.str)) + my_yyabort_error((ER_SP_BAD_SQLSTATE, MYF(0), $3.str)); + $$= new (thd->mem_root) sp_condition_value($3.str); if ($$ == NULL) MYSQL_YYABORT; - $$->type= sp_cond_type_t::state; - memcpy($$->sqlstate, $3.str, SQLSTATE_LENGTH); - $$->sqlstate[SQLSTATE_LENGTH]= '\0'; } ; @@ -2941,33 +3250,27 @@ sp_hcond: } | ident /* CONDITION name */ { - $$= Lex->spcont->find_cond(&$1); + $$= Lex->spcont->find_condition($1, false); if ($$ == NULL) - { - my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str)); } | SQLWARNING_SYM /* SQLSTATEs 01??? */ { - $$= (sp_cond_type_t *) thd->alloc(sizeof(sp_cond_type_t)); + $$= new (thd->mem_root) sp_condition_value(sp_condition_value::WARNING); if ($$ == NULL) MYSQL_YYABORT; - $$->type= sp_cond_type_t::warning; } | not FOUND_SYM /* SQLSTATEs 02??? */ { - $$= (sp_cond_type_t *) thd->alloc(sizeof(sp_cond_type_t)); + $$= new (thd->mem_root) sp_condition_value(sp_condition_value::NOT_FOUND); if ($$ == NULL) MYSQL_YYABORT; - $$->type= sp_cond_type_t::notfound; } | SQLEXCEPTION_SYM /* All other SQLSTATEs */ { - $$= (sp_cond_type_t *) thd->alloc(sizeof(sp_cond_type_t)); + $$= new (thd->mem_root) sp_condition_value(sp_condition_value::EXCEPTION); if ($$ == NULL) MYSQL_YYABORT; - $$->type= sp_cond_type_t::exception; } ; @@ -2978,9 +3281,9 @@ signal_stmt: Yacc_state *state= & thd->m_parser_state->m_yacc; lex->sql_command= SQLCOM_SIGNAL; - lex->m_stmt= new (thd->mem_root) Signal_statement(lex, $2, - state->m_set_signal_info); - if (lex->m_stmt == NULL) + lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_signal($2, state->m_set_signal_info); + if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; } ; @@ -2989,24 +3292,16 @@ signal_value: ident { LEX *lex= Lex; - sp_cond_type_t *cond; + sp_condition_value *cond; + + /* SIGNAL foo cannot be used outside of stored programs */ if (lex->spcont == NULL) - { - /* SIGNAL foo cannot be used outside of stored programs */ - my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str); - MYSQL_YYABORT; - } - cond= lex->spcont->find_cond(&$1); + my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str)); + cond= lex->spcont->find_condition($1, false); if (cond == NULL) - { - my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str); - MYSQL_YYABORT; - } - if (cond->type != sp_cond_type_t::state) - { - my_error(ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str)); + if (cond->type != sp_condition_value::SQLSTATE) + my_yyabort_error((ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0))); $$= cond; } | sqlstate @@ -3044,11 +3339,8 @@ signal_information_item_list: info= &thd->m_parser_state->m_yacc.m_set_signal_info; int index= (int) $3; if (info->m_item[index] != NULL) - { - my_error(ER_DUP_SIGNAL_SET, MYF(0), - Diag_condition_item_names[index].str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_SIGNAL_SET, MYF(0), + Diag_condition_item_names[index].str)); info->m_item[index]= $5; } ; @@ -3071,7 +3363,7 @@ signal_allowed_expr: SIGNAL/RESIGNAL ... SET <signal condition item name> = @foo := expr */ - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } } @@ -3116,13 +3408,160 @@ resignal_stmt: Yacc_state *state= & thd->m_parser_state->m_yacc; lex->sql_command= SQLCOM_RESIGNAL; - lex->m_stmt= new (thd->mem_root) Resignal_statement(lex, $2, - state->m_set_signal_info); - if (lex->m_stmt == NULL) + lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_resignal($2, + state->m_set_signal_info); + if (lex->m_sql_cmd == NULL) + MYSQL_YYABORT; + } + ; + +get_diagnostics: + GET_SYM which_area DIAGNOSTICS_SYM diagnostics_information + { + Diagnostics_information *info= $4; + + info->set_which_da($2); + + Lex->sql_command= SQLCOM_GET_DIAGNOSTICS; + Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_get_diagnostics(info); + + if (Lex->m_sql_cmd == NULL) + MYSQL_YYABORT; + } + ; + +which_area: + /* If <which area> is not specified, then CURRENT is implicit. */ + { $$= Diagnostics_information::CURRENT_AREA; } + | CURRENT_SYM + { $$= Diagnostics_information::CURRENT_AREA; } + ; + +diagnostics_information: + statement_information + { + $$= new (thd->mem_root) Statement_information($1); + if ($$ == NULL) + MYSQL_YYABORT; + } + | CONDITION_SYM condition_number condition_information + { + $$= new (thd->mem_root) Condition_information($2, $3); + if ($$ == NULL) MYSQL_YYABORT; } ; +statement_information: + statement_information_item + { + $$= new (thd->mem_root) List<Statement_information_item>; + if ($$ == NULL || $$->push_back($1, thd->mem_root)) + MYSQL_YYABORT; + } + | statement_information ',' statement_information_item + { + if ($1->push_back($3, thd->mem_root)) + MYSQL_YYABORT; + $$= $1; + } + ; + +statement_information_item: + simple_target_specification '=' statement_information_item_name + { + $$= new (thd->mem_root) Statement_information_item($3, $1); + if ($$ == NULL) + MYSQL_YYABORT; + } + +simple_target_specification: + ident + { + Lex_input_stream *lip= &thd->m_parser_state->m_lip; + $$= create_item_for_sp_var(thd, $1, NULL, + lip->get_tok_start(), lip->get_ptr()); + + if ($$ == NULL) + MYSQL_YYABORT; + } + | '@' ident_or_text + { + $$= new (thd->mem_root) Item_func_get_user_var(thd, $2); + if ($$ == NULL) + MYSQL_YYABORT; + } + ; + +statement_information_item_name: + NUMBER_SYM + { $$= Statement_information_item::NUMBER; } + | ROW_COUNT_SYM + { $$= Statement_information_item::ROW_COUNT; } + ; + +/* + Only a limited subset of <expr> are allowed in GET DIAGNOSTICS + <condition number>, same subset as for SIGNAL/RESIGNAL. +*/ +condition_number: + signal_allowed_expr + { $$= $1; } + ; + +condition_information: + condition_information_item + { + $$= new (thd->mem_root) List<Condition_information_item>; + if ($$ == NULL || $$->push_back($1, thd->mem_root)) + MYSQL_YYABORT; + } + | condition_information ',' condition_information_item + { + if ($1->push_back($3, thd->mem_root)) + MYSQL_YYABORT; + $$= $1; + } + ; + +condition_information_item: + simple_target_specification '=' condition_information_item_name + { + $$= new (thd->mem_root) Condition_information_item($3, $1); + if ($$ == NULL) + MYSQL_YYABORT; + } + +condition_information_item_name: + CLASS_ORIGIN_SYM + { $$= Condition_information_item::CLASS_ORIGIN; } + | SUBCLASS_ORIGIN_SYM + { $$= Condition_information_item::SUBCLASS_ORIGIN; } + | CONSTRAINT_CATALOG_SYM + { $$= Condition_information_item::CONSTRAINT_CATALOG; } + | CONSTRAINT_SCHEMA_SYM + { $$= Condition_information_item::CONSTRAINT_SCHEMA; } + | CONSTRAINT_NAME_SYM + { $$= Condition_information_item::CONSTRAINT_NAME; } + | CATALOG_NAME_SYM + { $$= Condition_information_item::CATALOG_NAME; } + | SCHEMA_NAME_SYM + { $$= Condition_information_item::SCHEMA_NAME; } + | TABLE_NAME_SYM + { $$= Condition_information_item::TABLE_NAME; } + | COLUMN_NAME_SYM + { $$= Condition_information_item::COLUMN_NAME; } + | CURSOR_NAME_SYM + { $$= Condition_information_item::CURSOR_NAME; } + | MESSAGE_TEXT_SYM + { $$= Condition_information_item::MESSAGE_TEXT; } + | MYSQL_ERRNO_SYM + { $$= Condition_information_item::MYSQL_ERRNO; } + | RETURNED_SQLSTATE_SYM + { $$= Condition_information_item::RETURNED_SQLSTATE; } + ; + sp_decl_idents: ident { @@ -3131,12 +3570,9 @@ sp_decl_idents: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_variable(&$1, TRUE)) - { - my_error(ER_SP_DUP_VAR, MYF(0), $1.str); - MYSQL_YYABORT; - } - spc->push_variable(&$1, (enum_field_types)0, sp_param_in); + if (spc->find_variable($1, TRUE)) + my_yyabort_error((ER_SP_DUP_VAR, MYF(0), $1.str)); + spc->add_variable(thd, $1); $$= 1; } | sp_decl_idents ',' ident @@ -3146,12 +3582,9 @@ sp_decl_idents: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_variable(&$3, TRUE)) - { - my_error(ER_SP_DUP_VAR, MYF(0), $3.str); - MYSQL_YYABORT; - } - spc->push_variable(&$3, (enum_field_types)0, sp_param_in); + if (spc->find_variable($3, TRUE)) + my_yyabort_error((ER_SP_DUP_VAR, MYF(0), $3.str)); + spc->add_variable(thd, $3); $$= $1 + 1; } ; @@ -3164,23 +3597,32 @@ sp_opt_default: sp_proc_stmt: sp_proc_stmt_statement | sp_proc_stmt_return - | sp_proc_stmt_if - | case_stmt_specification | sp_labeled_block | sp_unlabeled_block | sp_labeled_control - | sp_proc_stmt_unlabeled | sp_proc_stmt_leave | sp_proc_stmt_iterate | sp_proc_stmt_open | sp_proc_stmt_fetch | sp_proc_stmt_close + | sp_proc_stmt_compound_ok + ; + +sp_proc_stmt_compound_ok: + sp_proc_stmt_if + | case_stmt_specification + | sp_unlabeled_block_not_atomic + | sp_unlabeled_control ; sp_proc_stmt_if: - IF - { Lex->sphead->new_cont_backpatch(NULL); } - sp_if END IF + IF_SYM + { + if (maybe_start_compound_statement(thd)) + MYSQL_YYABORT; + Lex->sphead->new_cont_backpatch(NULL); + } + sp_if END IF_SYM { Lex->sphead->do_cont_backpatch(); } ; @@ -3199,11 +3641,9 @@ sp_proc_stmt_statement: sp_head *sp= lex->sphead; sp->m_flags|= sp_get_flags_for_command(lex); + /* "USE db" doesn't work in a procedure */ if (lex->sql_command == SQLCOM_CHANGE_DB) - { /* "USE db" doesn't work in a procedure */ - my_error(ER_SP_BADSTATEMENT, MYF(0), "USE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "USE")); /* Don't add an instruction for SET statements, since all instructions for them were already added during processing @@ -3213,8 +3653,8 @@ sp_proc_stmt_statement: lex->var_list.is_empty()); if (lex->sql_command != SQLCOM_SET_OPTION) { - sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(), - lex->spcont, lex); + sp_instr_stmt *i=new (thd->mem_root) + sp_instr_stmt(sp->instructions(), lex->spcont, lex); if (i == NULL) MYSQL_YYABORT; @@ -3226,7 +3666,7 @@ sp_proc_stmt_statement: if (yychar == YYEMPTY) i->m_query.length= lip->get_ptr() - sp->m_tmp_query; else - i->m_query.length= lip->get_tok_end() - sp->m_tmp_query; + i->m_query.length= lip->get_tok_start() - sp->m_tmp_query;; if (!(i->m_query.str= strmake_root(thd->mem_root, sp->m_tmp_query, i->m_query.length)) || @@ -3247,90 +3687,69 @@ sp_proc_stmt_return: sp_head *sp= lex->sphead; if (sp->m_type != TYPE_ENUM_FUNCTION) - { - my_message(ER_SP_BADRETURN, ER(ER_SP_BADRETURN), MYF(0)); + my_yyabort_error((ER_SP_BADRETURN, MYF(0))); + + sp_instr_freturn *i; + + i= new (thd->mem_root) + sp_instr_freturn(sp->instructions(), lex->spcont, $3, + sp->m_return_field_def.sql_type, lex); + if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; - } - else - { - sp_instr_freturn *i; + sp->m_flags|= sp_head::HAS_RETURN; - i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3, - sp->m_return_field_def.sql_type, lex); - if (i == NULL || - sp->add_instr(i)) - MYSQL_YYABORT; - sp->m_flags|= sp_head::HAS_RETURN; - } if (sp->restore_lex(thd)) MYSQL_YYABORT; } ; -sp_proc_stmt_unlabeled: - { /* 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()); - } - ; - sp_proc_stmt_leave: LEAVE_SYM label_ident { LEX *lex= Lex; sp_head *sp = lex->sphead; sp_pcontext *ctx= lex->spcont; - sp_label_t *lab= ctx->find_label($2.str); + sp_label *lab= ctx->find_label($2); if (! lab) + my_yyabort_error((ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", $2.str)); + + sp_instr_jump *i; + uint ip= sp->instructions(); + uint n; + /* + When jumping to a BEGIN-END block end, the target jump + points to the block hpop/cpop cleanup instructions, + so we should exclude the block context here. + When jumping to something else (i.e., SP_LAB_ITER), + there are no hpop/cpop at the jump destination, + so we should include the block context here for cleanup. + */ + bool exclusive= (lab->type == sp_label::BEGIN); + + n= ctx->diff_handlers(lab->ctx, exclusive); + if (n) { - my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", $2.str); - MYSQL_YYABORT; + sp_instr_hpop *hpop= new (thd->mem_root) + sp_instr_hpop(ip++, ctx, n); + if (hpop == NULL) + MYSQL_YYABORT; + sp->add_instr(hpop); } - else + n= ctx->diff_cursors(lab->ctx, exclusive); + if (n) { - sp_instr_jump *i; - uint ip= sp->instructions(); - uint n; - /* - When jumping to a BEGIN-END block end, the target jump - points to the block hpop/cpop cleanup instructions, - so we should exclude the block context here. - When jumping to something else (i.e., SP_LAB_ITER), - there are no hpop/cpop at the jump destination, - so we should include the block context here for cleanup. - */ - bool exclusive= (lab->type == SP_LAB_BEGIN); - - n= ctx->diff_handlers(lab->ctx, exclusive); - if (n) - { - sp_instr_hpop *hpop= new sp_instr_hpop(ip++, ctx, n); - if (hpop == NULL) - MYSQL_YYABORT; - sp->add_instr(hpop); - } - n= ctx->diff_cursors(lab->ctx, exclusive); - if (n) - { - sp_instr_cpop *cpop= new sp_instr_cpop(ip++, ctx, n); - if (cpop == NULL) - MYSQL_YYABORT; - sp->add_instr(cpop); - } - i= new sp_instr_jump(ip, ctx); - if (i == NULL) + sp_instr_cpop *cpop= new (thd->mem_root) + sp_instr_cpop(ip++, ctx, n); + if (cpop == NULL) MYSQL_YYABORT; - sp->push_backpatch(i, lab); /* Jumping forward */ - sp->add_instr(i); + sp->add_instr(cpop); } + i= new (thd->mem_root) sp_instr_jump(ip, ctx); + if (i == NULL) + MYSQL_YYABORT; + sp->push_backpatch(i, lab); /* Jumping forward */ + sp->add_instr(i); } ; @@ -3340,40 +3759,38 @@ sp_proc_stmt_iterate: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; - sp_label_t *lab= ctx->find_label($2.str); + sp_label *lab= ctx->find_label($2); + + if (! lab || lab->type != sp_label::ITERATION) + my_yyabort_error((ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", $2.str)); + + sp_instr_jump *i; + uint ip= sp->instructions(); + uint n; - if (! lab || lab->type != SP_LAB_ITER) + n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */ + if (n) { - my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", $2.str); - MYSQL_YYABORT; + sp_instr_hpop *hpop= new (thd->mem_root) + sp_instr_hpop(ip++, ctx, n); + if (hpop == NULL || + sp->add_instr(hpop)) + MYSQL_YYABORT; } - else + n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */ + if (n) { - sp_instr_jump *i; - uint ip= sp->instructions(); - uint n; - - n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */ - if (n) - { - sp_instr_hpop *hpop= new sp_instr_hpop(ip++, ctx, n); - if (hpop == NULL || - sp->add_instr(hpop)) - MYSQL_YYABORT; - } - n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */ - if (n) - { - sp_instr_cpop *cpop= new sp_instr_cpop(ip++, ctx, n); - if (cpop == NULL || - sp->add_instr(cpop)) - MYSQL_YYABORT; - } - i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ - if (i == NULL || - sp->add_instr(i)) + sp_instr_cpop *cpop= new (thd->mem_root) + sp_instr_cpop(ip++, ctx, n); + if (cpop == NULL || + sp->add_instr(cpop)) MYSQL_YYABORT; } + i= new (thd->mem_root) + sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ + if (i == NULL || + sp->add_instr(i)) + MYSQL_YYABORT; } ; @@ -3385,12 +3802,10 @@ sp_proc_stmt_open: uint offset; sp_instr_copen *i; - if (! lex->spcont->find_cursor(&$2, &offset)) - { - my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str); - MYSQL_YYABORT; - } - i= new sp_instr_copen(sp->instructions(), lex->spcont, offset); + if (! lex->spcont->find_cursor($2, &offset, false)) + my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $2.str)); + i= new (thd->mem_root) + sp_instr_copen(sp->instructions(), lex->spcont, offset); if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; @@ -3405,12 +3820,10 @@ sp_proc_stmt_fetch: uint offset; sp_instr_cfetch *i; - if (! lex->spcont->find_cursor(&$3, &offset)) - { - my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $3.str); - MYSQL_YYABORT; - } - i= new sp_instr_cfetch(sp->instructions(), lex->spcont, offset); + if (! lex->spcont->find_cursor($3, &offset, false)) + my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $3.str)); + i= new (thd->mem_root) + sp_instr_cfetch(sp->instructions(), lex->spcont, offset); if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; @@ -3427,12 +3840,10 @@ sp_proc_stmt_close: uint offset; sp_instr_cclose *i; - if (! lex->spcont->find_cursor(&$2, &offset)) - { - my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str); - MYSQL_YYABORT; - } - i= new sp_instr_cclose(sp->instructions(), lex->spcont, offset); + if (! lex->spcont->find_cursor($2, &offset, false)) + my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $2.str)); + i= new (thd->mem_root) + sp_instr_cclose(sp->instructions(), lex->spcont, offset); if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; @@ -3451,40 +3862,28 @@ sp_fetch_list: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_variable_t *spv; + sp_variable *spv; - if (!spc || !(spv = spc->find_variable(&$1))) - { - my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); - MYSQL_YYABORT; - } - else - { - /* An SP local variable */ - sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + if (!spc || !(spv = spc->find_variable($1, false))) + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); - i->add_to_varlist(spv); - } + /* An SP local variable */ + sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + i->add_to_varlist(spv); } | sp_fetch_list ',' ident { LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_variable_t *spv; + sp_variable *spv; - if (!spc || !(spv = spc->find_variable(&$3))) - { - my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str); - MYSQL_YYABORT; - } - else - { - /* An SP local variable */ - sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + if (!spc || !(spv = spc->find_variable($3, false))) + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $3.str)); - i->add_to_varlist(spv); - } + /* An SP local variable */ + sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + i->add_to_varlist(spv); } ; @@ -3496,10 +3895,10 @@ sp_if: 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, ctx, - $2, lex); + sp_instr_jump_if_not *i= new (thd->mem_root) + sp_instr_jump_if_not(ip, ctx, $2, lex); if (i == NULL || - sp->push_backpatch(i, ctx->push_label((char *)"", 0)) || + sp->push_backpatch(i, ctx->push_label(thd, empty_lex_str, 0)) || sp->add_cont_backpatch(i) || sp->add_instr(i)) MYSQL_YYABORT; @@ -3511,12 +3910,12 @@ sp_if: sp_head *sp= Lex->sphead; sp_pcontext *ctx= Lex->spcont; uint ip= sp->instructions(); - sp_instr_jump *i = new sp_instr_jump(ip, ctx); + sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, ctx); if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; sp->backpatch(ctx->pop_label()); - sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->push_backpatch(i, ctx->push_label(thd, empty_lex_str, 0)); } sp_elseifs { @@ -3533,51 +3932,89 @@ sp_elseifs: ; case_stmt_specification: - simple_case_stmt - | searched_case_stmt - ; - -simple_case_stmt: CASE_SYM { - LEX *lex= Lex; - case_stmt_action_case(lex); - lex->sphead->reset_lex(thd); /* For expr $3 */ - } - expr - { - LEX *lex= Lex; - if (case_stmt_action_expr(lex, $3)) - MYSQL_YYABORT; + if (maybe_start_compound_statement(thd)) + MYSQL_YYABORT; + + /** + An example of the CASE statement in use is + <pre> + CREATE PROCEDURE proc_19194_simple(i int) + BEGIN + DECLARE str CHAR(10); + + CASE i + WHEN 1 THEN SET str="1"; + WHEN 2 THEN SET str="2"; + WHEN 3 THEN SET str="3"; + ELSE SET str="unknown"; + END CASE; + + SELECT str; + END + </pre> + The actions are used to generate the following code: + <pre> + SHOW PROCEDURE CODE proc_19194_simple; + Pos Instruction + 0 set str@1 NULL + 1 set_case_expr (12) 0 i@0 + 2 jump_if_not 5(12) (case_expr@0 = 1) + 3 set str@1 _latin1'1' + 4 jump 12 + 5 jump_if_not 8(12) (case_expr@0 = 2) + 6 set str@1 _latin1'2' + 7 jump 12 + 8 jump_if_not 11(12) (case_expr@0 = 3) + 9 set str@1 _latin1'3' + 10 jump 12 + 11 set str@1 _latin1'unknown' + 12 stmt 0 "SELECT str" + </pre> + */ - /* For expr $3 */ - if (lex->sphead->restore_lex(thd)) - MYSQL_YYABORT; + Lex->sphead->new_cont_backpatch(NULL); + + /* + BACKPATCH: Creating target label for the jump to after END CASE + (instruction 12 in the example) + */ + Lex->spcont->push_label(thd, empty_lex_str, Lex->sphead->instructions()); } - simple_when_clause_list + case_stmt_body else_clause_opt END CASE_SYM { - LEX *lex= Lex; - case_stmt_action_end_case(lex, true); + /* + BACKPATCH: Resolving forward jump from + "case_stmt_action_then" to after END CASE + (jump from instruction 4 to 12, 7 to 12 ... in the example) + */ + Lex->sphead->backpatch(Lex->spcont->pop_label()); + + if ($3) + Lex->spcont->pop_case_expr_id(); + + Lex->sphead->do_cont_backpatch(); } ; -searched_case_stmt: - CASE_SYM - { - LEX *lex= Lex; - case_stmt_action_case(lex); - } - searched_when_clause_list - else_clause_opt - END - CASE_SYM +case_stmt_body: + { Lex->sphead->reset_lex(thd); /* For expr $2 */ } + expr { - LEX *lex= Lex; - case_stmt_action_end_case(lex, false); + if (case_stmt_action_expr(Lex, $2)) + MYSQL_YYABORT; + + if (Lex->sphead->restore_lex(thd)) + MYSQL_YYABORT; } + simple_when_clause_list + { $$= 1; } + | searched_when_clause_list + { $$= 0; } ; simple_when_clause_list: @@ -3644,8 +4081,8 @@ else_clause_opt: LEX *lex= Lex; sp_head *sp= lex->sphead; uint ip= sp->instructions(); - sp_instr_error *i= new sp_instr_error(ip, lex->spcont, - ER_SP_CASE_NOT_FOUND); + sp_instr_error *i= new (thd->mem_root) + sp_instr_error(ip, lex->spcont, ER_SP_CASE_NOT_FOUND); if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; @@ -3653,101 +4090,60 @@ else_clause_opt: | ELSE sp_proc_stmts1 ; -sp_labeled_control: - label_ident ':' - { - LEX *lex= Lex; - sp_pcontext *ctx= lex->spcont; - sp_label_t *lab= ctx->find_label($1.str); - - if (lab) - { - my_error(ER_SP_LABEL_REDEFINE, MYF(0), $1.str); - MYSQL_YYABORT; - } - else - { - lab= lex->spcont->push_label($1.str, - lex->sphead->instructions()); - lab->type= SP_LAB_ITER; - } - } - sp_unlabeled_control sp_opt_label - { - LEX *lex= Lex; - sp_label_t *lab= lex->spcont->pop_label(); - - if ($5.str) - { - if (my_strcasecmp(system_charset_info, $5.str, lab->name) != 0) - { - my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str); - MYSQL_YYABORT; - } - } - lex->sphead->backpatch(lab); - } - ; - sp_opt_label: /* Empty */ { $$= null_lex_str; } | label_ident { $$= $1; } ; sp_labeled_block: - label_ident ':' + label_ident ':' BEGIN_SYM { LEX *lex= Lex; sp_pcontext *ctx= lex->spcont; - sp_label_t *lab= ctx->find_label($1.str); + sp_label *lab= ctx->find_label($1); if (lab) - { - my_error(ER_SP_LABEL_REDEFINE, MYF(0), $1.str); - MYSQL_YYABORT; - } - - lab= lex->spcont->push_label($1.str, - lex->sphead->instructions()); - lab->type= SP_LAB_BEGIN; + my_yyabort_error((ER_SP_LABEL_REDEFINE, MYF(0), $1.str)); + lex->name= $1; } sp_block_content sp_opt_label { - LEX *lex= Lex; - sp_label_t *lab= lex->spcont->pop_label(); - - if ($5.str) + if ($6.str) { - if (my_strcasecmp(system_charset_info, $5.str, lab->name) != 0) - { - my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str); - MYSQL_YYABORT; - } + if (my_strcasecmp(system_charset_info, $6.str, $5->name.str) != 0) + my_yyabort_error((ER_SP_LABEL_MISMATCH, MYF(0), $6.str)); } } ; sp_unlabeled_block: - { /* Unlabeled blocks get a secret label. */ - LEX *lex= Lex; - uint ip= lex->sphead->instructions(); - sp_label_t *lab= lex->spcont->push_label((char *)"", ip); - lab->type= SP_LAB_BEGIN; + BEGIN_SYM + { + Lex->name= empty_lex_str; // Unlabeled blocks get an empty label } sp_block_content + { } + ; + +sp_unlabeled_block_not_atomic: + BEGIN_SYM not ATOMIC_SYM /* TODO: BEGIN ATOMIC (not -> opt_not) */ { - LEX *lex= Lex; - lex->spcont->pop_label(); + if (maybe_start_compound_statement(thd)) + MYSQL_YYABORT; + Lex->name= empty_lex_str; // Unlabeled blocks get an empty label } + sp_block_content + { } ; sp_block_content: - BEGIN_SYM - { /* 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 *lex= Lex; - lex->spcont= lex->spcont->push_context(LABEL_DEFAULT_SCOPE); + sp_label *lab= lex->spcont->push_label(thd, lex->name, + lex->sphead->instructions()); + lab->type= sp_label::BEGIN; + lex->spcont= lex->spcont->push_context(thd, + sp_pcontext::REGULAR_SCOPE); } sp_decls sp_proc_stmts @@ -3759,45 +4155,49 @@ sp_block_content: sp_instr *i; sp->backpatch(ctx->last_label()); /* We always have a label */ - if ($3.hndlrs) + if ($2.hndlrs) { - i= new sp_instr_hpop(sp->instructions(), ctx, $3.hndlrs); + i= new (thd->mem_root) + sp_instr_hpop(sp->instructions(), ctx, $2.hndlrs); if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; } - if ($3.curs) + if ($2.curs) { - i= new sp_instr_cpop(sp->instructions(), ctx, $3.curs); + i= new (thd->mem_root) + sp_instr_cpop(sp->instructions(), ctx, $2.curs); if (i == NULL || sp->add_instr(i)) MYSQL_YYABORT; } lex->spcont= ctx->pop_context(); + $$ = lex->spcont->pop_label(); } ; -sp_unlabeled_control: - LOOP_SYM +loop_body: sp_proc_stmts1 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, lex->spcont, lab->ip); + sp_label *lab= lex->spcont->last_label(); /* Jumping back */ + sp_instr_jump *i= new (thd->mem_root) + sp_instr_jump(ip, lex->spcont, lab->ip); if (i == NULL || lex->sphead->add_instr(i)) MYSQL_YYABORT; } - | WHILE_SYM - { Lex->sphead->reset_lex(thd); } + ; + +while_body: 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, lex->spcont, - $3, lex); + sp_instr_jump_if_not *i= new (thd->mem_root) + sp_instr_jump_if_not(ip, lex->spcont, $1, lex); if (i == NULL || /* Jumping forward */ sp->push_backpatch(i, lex->spcont->last_label()) || @@ -3811,23 +4211,26 @@ sp_unlabeled_control: { 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, lex->spcont, lab->ip); + sp_label *lab= lex->spcont->last_label(); /* Jumping back */ + sp_instr_jump *i= new (thd->mem_root) + sp_instr_jump(ip, lex->spcont, lab->ip); if (i == NULL || lex->sphead->add_instr(i)) MYSQL_YYABORT; lex->sphead->do_cont_backpatch(); } - | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM + ; + +repeat_body: + sp_proc_stmts1 UNTIL_SYM { Lex->sphead->reset_lex(thd); } 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, lex->spcont, - $5, lab->ip, - lex); + sp_label *lab= lex->spcont->last_label(); /* Jumping back */ + sp_instr_jump_if_not *i= new (thd->mem_root) + sp_instr_jump_if_not(ip, lex->spcont, $4, lab->ip, lex); if (i == NULL || lex->sphead->add_instr(i)) MYSQL_YYABORT; @@ -3838,6 +4241,81 @@ sp_unlabeled_control: } ; +pop_sp_label: + sp_opt_label + { + sp_label *lab; + Lex->sphead->backpatch(lab= Lex->spcont->pop_label()); + if ($1.str) + { + if (my_strcasecmp(system_charset_info, $1.str, + lab->name.str) != 0) + my_yyabort_error((ER_SP_LABEL_MISMATCH, MYF(0), $1.str)); + } + } + ; + +pop_sp_empty_label: + { + sp_label *lab; + Lex->sphead->backpatch(lab= Lex->spcont->pop_label()); + DBUG_ASSERT(lab->name.length == 0); + } + ; + +sp_labeled_control: + label_ident ':' LOOP_SYM + { + if (push_sp_label(thd, $1)) + MYSQL_YYABORT; + } + loop_body pop_sp_label + { } + | label_ident ':' WHILE_SYM + { + if (push_sp_label(thd, $1)) + MYSQL_YYABORT; + Lex->sphead->reset_lex(thd); + } + while_body pop_sp_label + { } + | label_ident ':' REPEAT_SYM + { + if (push_sp_label(thd, $1)) + MYSQL_YYABORT; + } + repeat_body pop_sp_label + { } + ; + +sp_unlabeled_control: + LOOP_SYM + { + if (push_sp_empty_label(thd)) + MYSQL_YYABORT; + } + loop_body + pop_sp_empty_label + { } + | WHILE_SYM + { + if (push_sp_empty_label(thd)) + MYSQL_YYABORT; + Lex->sphead->reset_lex(thd); + } + while_body + pop_sp_empty_label + { } + | REPEAT_SYM + { + if (push_sp_empty_label(thd)) + MYSQL_YYABORT; + } + repeat_body + pop_sp_empty_label + { } + ; + trg_action_time: BEFORE_SYM { Lex->trg_chistics.action_time= TRG_ACTION_BEFORE; } @@ -4046,7 +4524,8 @@ tablespace_name: ident { LEX *lex= Lex; - lex->alter_tablespace_info= new st_alter_tablespace(); + lex->alter_tablespace_info= (new (thd->mem_root) + st_alter_tablespace()); if (lex->alter_tablespace_info == NULL) MYSQL_YYABORT; lex->alter_tablespace_info->tablespace_name= $1.str; @@ -4058,7 +4537,8 @@ logfile_group_name: ident { LEX *lex= Lex; - lex->alter_tablespace_info= new st_alter_tablespace(); + lex->alter_tablespace_info= (new (thd->mem_root) + st_alter_tablespace()); if (lex->alter_tablespace_info == NULL) MYSQL_YYABORT; lex->alter_tablespace_info->logfile_group_name= $1.str; @@ -4137,10 +4617,7 @@ opt_ts_nodegroup: { LEX *lex= Lex; if (lex->alter_tablespace_info->nodegroup_id != UNDEF_NODEGROUP) - { - my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP")); lex->alter_tablespace_info->nodegroup_id= $3; } ; @@ -4150,10 +4627,7 @@ opt_ts_comment: { LEX *lex= Lex; if (lex->alter_tablespace_info->ts_comment != NULL) - { - my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"COMMENT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"COMMENT")); lex->alter_tablespace_info->ts_comment= $3.str; } ; @@ -4163,11 +4637,8 @@ opt_ts_engine: { LEX *lex= Lex; if (lex->alter_tablespace_info->storage_engine != NULL) - { - my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0), - "STORAGE ENGINE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE, MYF(0), + "STORAGE ENGINE")); lex->alter_tablespace_info->storage_engine= $4; } ; @@ -4187,10 +4658,7 @@ ts_wait: { LEX *lex= Lex; if (!(lex->alter_tablespace_info->wait_until_completed)) - { - my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT")); lex->alter_tablespace_info->wait_until_completed= FALSE; } ; @@ -4218,23 +4686,14 @@ size_number: case 'k': case 'K': text_shift_number+=10; break; default: - { - my_error(ER_WRONG_SIZE_NUMBER, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_SIZE_NUMBER, MYF(0))); } if (prefix_number >> 31) - { - my_error(ER_SIZE_OVERFLOW_ERROR, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SIZE_OVERFLOW_ERROR, MYF(0))); number= prefix_number << text_shift_number; } else - { - my_error(ER_WRONG_SIZE_NUMBER, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_SIZE_NUMBER, MYF(0))); $$= number; } ; @@ -4243,34 +4702,23 @@ size_number: End tablespace part */ -create2: - '(' create2a {} - | opt_create_table_options - opt_create_partitioning - create3 {} - | LIKE table_ident - { - TABLE_LIST *src_table; - LEX *lex= thd->lex; - - lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE; - src_table= lex->select_lex.add_table_to_list(thd, $2, NULL, 0, - TL_READ, - MDL_SHARED_READ); - if (! src_table) - MYSQL_YYABORT; - /* CREATE TABLE ... LIKE is not allowed for views. */ - src_table->required_type= FRMTYPE_TABLE; - } - | '(' LIKE table_ident ')' +create_body: + '(' create_field_list ')' + { Lex->create_info.option_list= NULL; } + opt_create_table_options opt_create_partitioning opt_create_select {} + | opt_create_table_options opt_create_partitioning opt_create_select {} + /* + the following rule is redundant, but there's a shift/reduce + conflict that prevents the rule above from parsing a syntax like + CREATE TABLE t1 (SELECT 1); + */ + | '(' create_select ')' { Select->set_braces(1);} union_opt {} + | create_like { - TABLE_LIST *src_table; - LEX *lex= thd->lex; - lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE; - src_table= lex->select_lex.add_table_to_list(thd, $3, NULL, 0, - TL_READ, - MDL_SHARED_READ); + Lex->create_info.add(DDL_options_st::OPT_LIKE); + TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd, + $1, NULL, 0, TL_READ, MDL_SHARED_READ); if (! src_table) MYSQL_YYABORT; /* CREATE TABLE ... LIKE is not allowed for views. */ @@ -4278,21 +4726,12 @@ create2: } ; -create2a: - create_field_list ')' - { - Lex->create_info.option_list= NULL; - } - opt_create_table_options - opt_create_partitioning - create3 {} - | opt_create_partitioning - create_select ')' - { Select->set_braces(1);} - union_opt {} +create_like: + LIKE table_ident { $$= $2; } + | '(' LIKE table_ident ')' { $$= $3; } ; -create3: +opt_create_select: /* empty */ {} | opt_duplicate opt_as create_select { Select->set_braces(0);} @@ -4348,7 +4787,7 @@ partitioning: PARTITION_SYM have_partitioning { LEX *lex= Lex; - lex->part_info= new partition_info(); + lex->part_info= new (thd->mem_root) partition_info(); if (!lex->part_info) { mem_alloc_error(sizeof(partition_info)); @@ -4356,7 +4795,7 @@ partitioning: } if (lex->sql_command == SQLCOM_ALTER_TABLE) { - lex->alter_info.flags|= ALTER_PARTITION; + lex->alter_info.flags|= Alter_info::ALTER_PARTITION; } } partition @@ -4368,15 +4807,11 @@ have_partitioning: #ifdef WITH_PARTITION_STORAGE_ENGINE LEX_STRING partition_name={C_STRING_WITH_LEN("partition")}; if (!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN)) - { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), - "--skip-partition"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_OPTION_PREVENTS_STATEMENT, MYF(0), + "--skip-partition")); #else - my_error(ER_FEATURE_DISABLED, MYF(0), "partitioning", - "--with-plugin-partition"); - MYSQL_YYABORT; + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), "partitioning", + "--with-plugin-partition")); #endif } ; @@ -4387,7 +4822,7 @@ partition_entry: LEX *lex= Lex; if (!lex->part_info) { - my_parse_error(ER(ER_PARTITION_ENTRY_ERROR)); + my_parse_error(thd, ER_PARTITION_ENTRY_ERROR); MYSQL_YYABORT; } /* @@ -4442,7 +4877,7 @@ opt_key_algo: Lex->part_info->key_algorithm= partition_info::KEY_ALGORITHM_55; break; default: - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } } @@ -4463,17 +4898,14 @@ part_field_item: { partition_info *part_info= Lex->part_info; part_info->num_columns++; - if (part_info->part_field_list.push_back($1.str)) + if (part_info->part_field_list.push_back($1.str, thd->mem_root)) { mem_alloc_error(1); MYSQL_YYABORT; } if (part_info->num_columns > MAX_REF_PARTS) - { - my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), - "list of partition fields"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of partition fields")); } ; @@ -4514,10 +4946,7 @@ opt_num_parts: uint num_parts= $2; partition_info *part_info= Lex->part_info; if (num_parts == 0) - { - my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_NO_PARTS_ERROR, MYF(0), "partitions")); part_info->num_parts= num_parts; part_info->use_default_num_partitions= FALSE; @@ -4548,17 +4977,14 @@ sub_part_field_item: ident { partition_info *part_info= Lex->part_info; - if (part_info->subpart_field_list.push_back($1.str)) + if (part_info->subpart_field_list.push_back($1.str, thd->mem_root)) { mem_alloc_error(1); MYSQL_YYABORT; } if (part_info->subpart_field_list.elements > MAX_REF_PARTS) - { - my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), - "list of subpartition fields"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of subpartition fields")); } ; @@ -4571,7 +4997,7 @@ part_func_expr: lex->safe_to_cache_query= 1; if (not_corr_func) { - my_parse_error(ER(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR)); + my_parse_error(thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR); MYSQL_YYABORT; } $$=$1; @@ -4585,10 +5011,7 @@ opt_num_subparts: uint num_parts= $2; LEX *lex= Lex; if (num_parts == 0) - { - my_error(ER_NO_PARTS_ERROR, MYF(0), "subpartitions"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_NO_PARTS_ERROR, MYF(0), "subpartitions")); lex->part_info->num_subparts= num_parts; lex->part_info->use_default_num_subpartitions= FALSE; } @@ -4599,17 +5022,11 @@ part_defs: { partition_info *part_info= Lex->part_info; if (part_info->part_type == RANGE_PARTITION) - { - my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), - "RANGE"); - MYSQL_YYABORT; - } - else if (part_info->part_type == LIST_PARTITION) - { - my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), - "LIST"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), + "RANGE")); + if (part_info->part_type == LIST_PARTITION) + my_yyabort_error((ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), + "LIST")); } | '(' part_def_list ')' { @@ -4620,7 +5037,7 @@ part_defs: if (part_info->num_parts != count_curr_parts) { - my_parse_error(ER(ER_PARTITION_WRONG_NO_PART_ERROR)); + my_parse_error(thd, ER_PARTITION_WRONG_NO_PART_ERROR); MYSQL_YYABORT; } } @@ -4641,9 +5058,10 @@ part_definition: PARTITION_SYM { partition_info *part_info= Lex->part_info; - partition_element *p_elem= new partition_element(); + partition_element *p_elem= new (thd->mem_root) partition_element(); - if (!p_elem || part_info->partitions.push_back(p_elem)) + if (!p_elem || + part_info->partitions.push_back(p_elem, thd->mem_root)) { mem_alloc_error(sizeof(partition_element)); MYSQL_YYABORT; @@ -4692,11 +5110,8 @@ opt_part_values: if (! lex->is_partition_management()) { if (part_info->part_type != RANGE_PARTITION) - { - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN")); } else part_info->part_type= RANGE_PARTITION; @@ -4709,11 +5124,8 @@ opt_part_values: if (! lex->is_partition_management()) { if (part_info->part_type != LIST_PARTITION) - { - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "LIST", "IN"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "LIST", "IN")); } else part_info->part_type= LIST_PARTITION; @@ -4730,16 +5142,16 @@ part_func_max: part_info->num_columns != 1U) { part_info->print_debug("Kilroy II", NULL); - my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + my_parse_error(thd, ER_PARTITION_COLUMN_LIST_ERROR); MYSQL_YYABORT; } else part_info->num_columns= 1U; - if (part_info->init_column_part()) + if (part_info->init_column_part(thd)) { MYSQL_YYABORT; } - if (part_info->add_max_value()) + if (part_info->add_max_value(thd)) { MYSQL_YYABORT; } @@ -4761,7 +5173,7 @@ part_values_in: part_info->num_columns > MAX_REF_PARTS) { part_info->print_debug("Kilroy III", NULL); - my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + my_parse_error(thd, ER_PARTITION_COLUMN_LIST_ERROR); MYSQL_YYABORT; } /* @@ -4771,7 +5183,7 @@ part_values_in: we ADD or REORGANIZE partitions. Also can only happen for LIST partitions. */ - if (part_info->reorganize_into_single_field_col_val()) + if (part_info->reorganize_into_single_field_col_val(thd)) { MYSQL_YYABORT; } @@ -4782,7 +5194,7 @@ part_values_in: partition_info *part_info= Lex->part_info; if (part_info->num_columns < 2U) { - my_parse_error(ER(ER_ROW_SINGLE_PARTITION_FIELD_ERROR)); + my_parse_error(thd, ER_ROW_SINGLE_PARTITION_FIELD_ERROR); MYSQL_YYABORT; } } @@ -4801,7 +5213,7 @@ part_value_item: /* Initialisation code needed for each list of value expressions */ if (!(part_info->part_type == LIST_PARTITION && part_info->num_columns == 1U) && - part_info->init_column_part()) + part_info->init_column_part(thd)) { MYSQL_YYABORT; } @@ -4823,7 +5235,7 @@ part_value_item: error. */ part_info->print_debug("Kilroy I", NULL); - my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + my_parse_error(thd, ER_PARTITION_COLUMN_LIST_ERROR); MYSQL_YYABORT; } part_info->curr_list_object= 0; @@ -4841,10 +5253,10 @@ part_value_expr_item: partition_info *part_info= Lex->part_info; if (part_info->part_type == LIST_PARTITION) { - my_parse_error(ER(ER_MAXVALUE_IN_VALUES_IN)); + my_parse_error(thd, ER_MAXVALUE_IN_VALUES_IN); MYSQL_YYABORT; } - if (part_info->add_max_value()) + if (part_info->add_max_value(thd)) { MYSQL_YYABORT; } @@ -4857,7 +5269,7 @@ part_value_expr_item: if (!lex->safe_to_cache_query) { - my_parse_error(ER(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR)); + my_parse_error(thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR); MYSQL_YYABORT; } if (part_info->add_column_list_value(thd, part_expr)) @@ -4879,7 +5291,7 @@ opt_sub_partition: We come here when we have defined subpartitions on the first partition but not on all the subsequent partitions. */ - my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR)); + my_parse_error(thd, ER_PARTITION_WRONG_NO_SUBPART_ERROR); MYSQL_YYABORT; } } @@ -4891,7 +5303,7 @@ opt_sub_partition: if (part_info->num_subparts != part_info->count_curr_subparts) { - my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR)); + my_parse_error(thd, ER_PARTITION_WRONG_NO_SUBPART_ERROR); MYSQL_YYABORT; } } @@ -4899,7 +5311,7 @@ opt_sub_partition: { if (part_info->partitions.elements > 1) { - my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR)); + my_parse_error(thd, ER_PARTITION_WRONG_NO_SUBPART_ERROR); MYSQL_YYABORT; } part_info->num_subparts= part_info->count_curr_subparts; @@ -4918,7 +5330,8 @@ sub_part_definition: { partition_info *part_info= Lex->part_info; partition_element *curr_part= part_info->current_partition; - partition_element *sub_p_elem= new partition_element(curr_part); + partition_element *sub_p_elem= new (thd->mem_root) + partition_element(curr_part); if (part_info->use_default_subpartitions && part_info->partitions.elements >= 2) { @@ -4933,11 +5346,11 @@ sub_part_definition: the second partition (the current partition processed have already been put into the partitions list. */ - my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR)); + my_parse_error(thd, ER_PARTITION_WRONG_NO_SUBPART_ERROR); MYSQL_YYABORT; } if (!sub_p_elem || - curr_part->subpartitions.push_back(sub_p_elem)) + curr_part->subpartitions.push_back(sub_p_elem, thd->mem_root)) { mem_alloc_error(sizeof(partition_element)); MYSQL_YYABORT; @@ -5022,7 +5435,7 @@ create_select: { Select->parsing_place= NO_MATTER; } - opt_select_from + table_expression { /* The following work only with the local list, the global list @@ -5052,24 +5465,38 @@ create_database_option: | default_charset {} ; -opt_table_options: - /* empty */ { $$= 0; } - | table_options { $$= $1;} - ; - -table_options: - table_option { $$=$1; } - | table_option table_options { $$= $1 | $2; } - ; - -table_option: - TEMPORARY { $$=HA_LEX_CREATE_TMP_TABLE; } - ; +opt_if_not_exists_table_element: + /* empty */ + { + Lex->check_exists= FALSE; + } + | IF_SYM not EXISTS + { + Lex->check_exists= TRUE; + } + ; opt_if_not_exists: - /* empty */ { $$= 0; } - | IF not EXISTS { $$=HA_LEX_CREATE_IF_NOT_EXISTS; } - ; + /* empty */ + { + $$.init(); + } + | IF_SYM not EXISTS + { + $$.set(DDL_options_st::OPT_IF_NOT_EXISTS); + } + ; + +create_or_replace: + CREATE /* empty */ + { + $$.init(); + } + | CREATE OR_SYM REPLACE + { + $$.set(DDL_options_st::OPT_OR_REPLACE); + } + ; opt_create_table_options: /* empty */ @@ -5108,7 +5535,7 @@ create_table_option: Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH; } - | PASSWORD opt_equal TEXT_STRING_sys + | PASSWORD_SYM opt_equal TEXT_STRING_sys { Lex->create_info.password=$3.str; Lex->create_info.used_fields|= HA_CREATE_USED_PASSWORD; @@ -5133,7 +5560,7 @@ create_table_option: Lex->create_info.table_options|= HA_OPTION_PACK_KEYS; break; default: - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS; @@ -5144,6 +5571,70 @@ create_table_option: ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS; } + | STATS_AUTO_RECALC_SYM opt_equal ulong_num + { + switch($3) { + case 0: + Lex->create_info.stats_auto_recalc= HA_STATS_AUTO_RECALC_OFF; + break; + case 1: + Lex->create_info.stats_auto_recalc= HA_STATS_AUTO_RECALC_ON; + break; + default: + my_parse_error(thd, ER_SYNTAX_ERROR); + MYSQL_YYABORT; + } + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_AUTO_RECALC; + } + | STATS_AUTO_RECALC_SYM opt_equal DEFAULT + { + Lex->create_info.stats_auto_recalc= HA_STATS_AUTO_RECALC_DEFAULT; + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_AUTO_RECALC; + } + | STATS_PERSISTENT_SYM opt_equal ulong_num + { + switch($3) { + case 0: + Lex->create_info.table_options|= HA_OPTION_NO_STATS_PERSISTENT; + break; + case 1: + Lex->create_info.table_options|= HA_OPTION_STATS_PERSISTENT; + break; + default: + my_parse_error(thd, ER_SYNTAX_ERROR); + MYSQL_YYABORT; + } + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_PERSISTENT; + } + | STATS_PERSISTENT_SYM opt_equal DEFAULT + { + Lex->create_info.table_options&= + ~(HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT); + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_PERSISTENT; + } + | STATS_SAMPLE_PAGES_SYM opt_equal ulong_num + { + /* From user point of view STATS_SAMPLE_PAGES can be specified as + STATS_SAMPLE_PAGES=N (where 0<N<=65535, it does not make sense to + scan 0 pages) or STATS_SAMPLE_PAGES=default. Internally we record + =default as 0. See create_frm() in sql/table.cc, we use only two + bytes for stats_sample_pages and this is why we do not allow + larger values. 65535 pages, 16kb each means to sample 1GB, which + is impractical. If at some point this needs to be extended, then + we can store the higher bits from stats_sample_pages in .frm too. */ + if ($3 == 0 || $3 > 0xffff) + { + my_parse_error(thd, ER_SYNTAX_ERROR); + MYSQL_YYABORT; + } + Lex->create_info.stats_sample_pages=$3; + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_SAMPLE_PAGES; + } + | STATS_SAMPLE_PAGES_SYM opt_equal DEFAULT + { + Lex->create_info.stats_sample_pages=0; + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_SAMPLE_PAGES; + } | CHECKSUM_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; @@ -5180,7 +5671,7 @@ create_table_option: from the global list. */ LEX *lex=Lex; - lex->create_info.merge_list= lex->select_lex.table_list; + lex->create_info.merge_list= lex->select_lex.table_list.first; lex->select_lex.table_list= lex->save_list; /* When excluding union list from the global list we assume that @@ -5189,7 +5680,7 @@ create_table_option: */ TABLE_LIST *last_non_sel_table= lex->create_last_non_select_table; DBUG_ASSERT(last_non_sel_table->next_global == - lex->create_info.merge_list.first); + lex->create_info.merge_list); last_non_sel_table->next_global= 0; Lex->query_tables_last= &last_non_sel_table->next_global; @@ -5236,12 +5727,16 @@ create_table_option: } | IDENT_sys equal TEXT_STRING_sys { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, true, &Lex->create_info.option_list, &Lex->option_list_last); } | IDENT_sys equal ident { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, false, &Lex->create_info.option_list, &Lex->option_list_last); @@ -5263,18 +5758,8 @@ create_table_option: default_charset: opt_default charset opt_equal charset_name_or_default { - HA_CREATE_INFO *cinfo= &Lex->create_info; - if ((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) && - cinfo->default_table_charset && $4 && - !my_charset_same(cinfo->default_table_charset,$4)) - { - my_error(ER_CONFLICTING_DECLARATIONS, MYF(0), - "CHARACTER SET ", cinfo->default_table_charset->csname, - "CHARACTER SET ", $4->csname); + if (Lex->create_info.add_table_option_default_charset($4)) MYSQL_YYABORT; - } - Lex->create_info.default_table_charset= $4; - Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET; } ; @@ -5298,21 +5783,19 @@ default_collation: storage_engines: ident_or_text { - plugin_ref plugin= ha_resolve_by_name(thd, &$1); + plugin_ref plugin= ha_resolve_by_name(thd, &$1, + thd->lex->create_info.tmp_table()); if (plugin) - $$= plugin_data(plugin, handlerton*); + $$= plugin_hton(plugin); else { if (thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION) - { - my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str)); $$= 0; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_STORAGE_ENGINE, - ER(ER_UNKNOWN_STORAGE_ENGINE), + ER_THD(thd, ER_UNKNOWN_STORAGE_ENGINE), $1.str); } } @@ -5322,13 +5805,10 @@ known_storage_engines: ident_or_text { plugin_ref plugin; - if ((plugin= ha_resolve_by_name(thd, &$1))) - $$= plugin_data(plugin, handlerton*); + if ((plugin= ha_resolve_by_name(thd, &$1, false))) + $$= plugin_hton(plugin); else - { - my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str)); } ; @@ -5348,11 +5828,6 @@ merge_insert_types: | LAST_SYM { $$= MERGE_INSERT_TO_LAST; } ; -opt_select_from: - opt_limit_clause {} - | select_from select_lock_type - ; - udf_type: STRING_SYM {$$ = (int) STRING_RESULT; } | REAL {$$ = (int) REAL_RESULT; } @@ -5381,66 +5856,90 @@ field_list_item: column_def: field_spec opt_check_constraint | field_spec references - { - Lex->col_list.empty(); /* Alloced by sql_alloc */ - } ; key_def: - normal_key_type opt_ident key_alg '(' key_list ')' - { Lex->option_list= NULL; } - normal_key_options + key_or_index opt_if_not_exists opt_ident opt_USING_key_algorithm + { + Lex->option_list= NULL; + if (Lex->add_key(Key::MULTIPLE, $3, $4, $2)) + MYSQL_YYABORT; + } + '(' key_list ')' normal_key_options { } + | key_or_index opt_if_not_exists ident TYPE_SYM btree_or_rtree + { + Lex->option_list= NULL; + if (Lex->add_key(Key::MULTIPLE, $3, $5, $2)) + MYSQL_YYABORT; + } + '(' key_list ')' normal_key_options { } + | fulltext opt_key_or_index opt_if_not_exists opt_ident { - if (add_create_index (Lex, $1, $2)) + Lex->option_list= NULL; + if (Lex->add_key($1, $4, HA_KEY_ALG_UNDEF, $3)) MYSQL_YYABORT; } - | fulltext opt_key_or_index opt_ident init_key_options - '(' key_list ')' - { Lex->option_list= NULL; } - fulltext_key_options + '(' key_list ')' fulltext_key_options { } + | spatial opt_key_or_index opt_if_not_exists opt_ident { - if (add_create_index (Lex, $1, $3)) + Lex->option_list= NULL; + if (Lex->add_key($1, $4, HA_KEY_ALG_UNDEF, $3)) MYSQL_YYABORT; } - | spatial opt_key_or_index opt_ident init_key_options - '(' key_list ')' - { Lex->option_list= NULL; } - spatial_key_options + '(' key_list ')' spatial_key_options { } + | opt_constraint constraint_key_type + opt_if_not_exists opt_ident + opt_USING_key_algorithm { - if (add_create_index (Lex, $1, $3)) + Lex->option_list= NULL; + if (Lex->add_key($2, $4.str ? $4 : $1, $5, $3)) MYSQL_YYABORT; } - | opt_constraint constraint_key_type opt_ident key_alg - '(' key_list ')' - { Lex->option_list= NULL; } - normal_key_options + '(' key_list ')' normal_key_options { } + | opt_constraint constraint_key_type opt_if_not_exists ident + TYPE_SYM btree_or_rtree { - if (add_create_index (Lex, $2, $3.str ? $3 : $1)) + Lex->option_list= NULL; + if (Lex->add_key($2, $4.str ? $4 : $1, $6, $3)) MYSQL_YYABORT; } - | opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references + '(' key_list ')' normal_key_options { } + | opt_constraint FOREIGN KEY_SYM opt_if_not_exists opt_ident + { + if (Lex->check_add_key($4) || + !(Lex->last_key= (new (thd->mem_root) + Key(Key::MULTIPLE, $1.str ? $1 : $5, + HA_KEY_ALG_UNDEF, true, $4)))) + MYSQL_YYABORT; + Lex->option_list= NULL; + } + '(' key_list ')' references { LEX *lex=Lex; - Key *key= new Foreign_key($4.str ? $4 : $1, lex->col_list, - $8, - lex->ref_list, - lex->fk_delete_opt, - lex->fk_update_opt, - lex->fk_match_option); + Key *key= (new (thd->mem_root) + Foreign_key($5.str ? $5 : $1, + lex->last_key->columns, + $10->db, + $10->table, + lex->ref_list, + lex->fk_delete_opt, + lex->fk_update_opt, + lex->fk_match_option, + $4)); if (key == NULL) MYSQL_YYABORT; - lex->alter_info.key_list.push_back(key); + /* + handle_if_exists_options() expectes the two keys in this order: + the Foreign_key, followed by its auto-generated Key. + */ + lex->alter_info.key_list.push_back(key, thd->mem_root); + lex->alter_info.key_list.push_back(Lex->last_key, thd->mem_root); lex->option_list= NULL; - if (add_create_index (lex, Key::MULTIPLE, $1.str ? $1 : $4, - &default_key_create_info, 1)) - MYSQL_YYABORT; + /* Only used for ALTER TABLE. Ignored otherwise. */ - lex->alter_info.flags|= ALTER_FOREIGN_KEY; - } - | opt_constraint check_constraint - { - Lex->col_list.empty(); /* Alloced by sql_alloc */ + lex->alter_info.flags|= Alter_info::ADD_FOREIGN_KEY; } + | opt_constraint check_constraint { } ; opt_check_constraint: @@ -5465,58 +5964,59 @@ field_spec: field_ident { LEX *lex=Lex; - lex->length=lex->dec=0; - lex->type=0; - lex->default_value= lex->on_update_value= 0; - lex->comment=null_lex_str; - lex->charset=NULL; - lex->vcol_info= 0; - lex->option_list= NULL; + Create_field *f= new (thd->mem_root) Create_field(); + + if (check_string_char_length(&$1, 0, NAME_CHAR_LEN, + system_charset_info, 1)) + my_yyabort_error((ER_TOO_LONG_IDENT, MYF(0), $1.str)); + + if (!f) + MYSQL_YYABORT; + + lex->init_last_field(f, $1.str, NULL); } + field_type { Lex->set_last_field_type($3); } field_def { LEX *lex=Lex; - if (add_field_to_list(lex->thd, &$1, $3.type, - $3.length, $3.dec, lex->type, - lex->default_value, lex->on_update_value, - &lex->comment, - lex->change, &lex->interval_list, $3.charset, - lex->uint_geom_type, - lex->vcol_info, lex->option_list)) + Create_field *f= lex->last_field; + + if (f->check(thd)) MYSQL_YYABORT; + + lex->alter_info.create_list.push_back(f, thd->mem_root); + + if (f->flags & PRI_KEY_FLAG) + add_key_to_list(lex, &$1, Key::PRIMARY, Lex->check_exists); + else if (f->flags & (UNIQUE_FLAG | UNIQUE_KEY_FLAG)) + add_key_to_list(lex, &$1, Key::UNIQUE, Lex->check_exists); } ; field_def: - type opt_attribute - { $$.set($1, Lex->length, Lex->dec, Lex->charset); } - | type opt_generated_always AS - { $<lex_type>$.set($1, Lex->length, Lex->dec, Lex->charset); } - '(' virtual_column_func ')' vcol_opt_specifier vcol_opt_attribute - { - $$= $<lex_type>4; - Lex->vcol_info->set_field_type($$.type); - $$.type= (enum enum_field_types)MYSQL_TYPE_VIRTUAL; - } + opt_attribute + | opt_generated_always AS + '(' virtual_column_func ')' + vcol_opt_specifier vcol_opt_attribute ; opt_generated_always: - /* empty */ + /* empty */ {} | GENERATED_SYM ALWAYS_SYM {} ; vcol_opt_specifier: /* empty */ { - Lex->vcol_info->set_stored_in_db_flag(FALSE); + Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE); } | VIRTUAL_SYM { - Lex->vcol_info->set_stored_in_db_flag(FALSE); + Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE); } | PERSISTENT_SYM { - Lex->vcol_info->set_stored_in_db_flag(TRUE); + Lex->last_field->vcol_info->set_stored_in_db_flag(TRUE); } ; @@ -5534,16 +6034,16 @@ vcol_attribute: UNIQUE_SYM { LEX *lex=Lex; - lex->type|= UNIQUE_FLAG; - lex->alter_info.flags|= ALTER_ADD_INDEX; + lex->last_field->flags|= UNIQUE_FLAG; + lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } | UNIQUE_SYM KEY_SYM { LEX *lex=Lex; - lex->type|= UNIQUE_KEY_FLAG; - lex->alter_info.flags|= ALTER_ADD_INDEX; + lex->last_field->flags|= UNIQUE_FLAG; + lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } - | COMMENT_SYM TEXT_STRING_sys { Lex->comment= $2; } + | COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; } ; parse_vcol_expr: @@ -5555,33 +6055,45 @@ parse_vcol_expr: Prevent the end user from invoking this command. */ if (!Lex->parse_vcol_expr) - { - my_message(ER_SYNTAX_ERROR, ER(ER_SYNTAX_ERROR), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SYNTAX_ERROR, MYF(0))); } ; virtual_column_func: remember_name expr remember_end { - Lex->vcol_info= new Virtual_column_info(); - if (!Lex->vcol_info) + Virtual_column_info *v= new (thd->mem_root) Virtual_column_info(); + if (!v) { mem_alloc_error(sizeof(Virtual_column_info)); MYSQL_YYABORT; } uint expr_len= (uint)($3 - $1) - 1; - Lex->vcol_info->expr_str.str= (char* ) sql_memdup($1 + 1, expr_len); - Lex->vcol_info->expr_str.length= expr_len; - Lex->vcol_info->expr_item= $2; + v->expr_str.str= (char* ) thd->memdup($1 + 1, expr_len); + v->expr_str.length= expr_len; + v->expr_item= $2; + Lex->last_field->vcol_info= v; } ; -type: +field_type: int_type opt_field_length field_options { $$=$1; } | real_type opt_precision field_options { $$=$1; } - | FLOAT_SYM float_options field_options { $$=MYSQL_TYPE_FLOAT; } + | FLOAT_SYM float_options field_options + { + $$=MYSQL_TYPE_FLOAT; + if (Lex->length && !Lex->dec) + { + int err; + ulonglong tmp_length= my_strtoll10(Lex->length, NULL, &err); + if (err || tmp_length > PRECISION_FOR_DOUBLE) + my_yyabort_error((ER_WRONG_FIELD_SPEC, MYF(0), + Lex->last_field->field_name)); + if (tmp_length > PRECISION_FOR_FLOAT) + $$= MYSQL_TYPE_DOUBLE; + Lex->length= 0; + } + } | BIT_SYM { Lex->length= (char*) "1"; @@ -5613,13 +6125,13 @@ type: | nchar field_length opt_bin_mod { $$=MYSQL_TYPE_STRING; - Lex->charset=national_charset_info; + bincmp_collation(national_charset_info, $3); } | nchar opt_bin_mod { Lex->length= (char*) "1"; $$=MYSQL_TYPE_STRING; - Lex->charset=national_charset_info; + bincmp_collation(national_charset_info, $2); } | BINARY field_length { @@ -5639,7 +6151,7 @@ type: | nvarchar field_length opt_bin_mod { $$= MYSQL_TYPE_VARCHAR; - Lex->charset=national_charset_info; + bincmp_collation(national_charset_info, $3); } | VARBINARY field_length { @@ -5656,9 +6168,9 @@ type: { char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_WARN_DEPRECATED_SYNTAX, - ER(ER_WARN_DEPRECATED_SYNTAX), + ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX), buff, "YEAR(4)"); } } @@ -5667,22 +6179,28 @@ type: | DATE_SYM { $$=MYSQL_TYPE_DATE; } | TIME_SYM opt_field_length - { $$=MYSQL_TYPE_TIME; } + { $$= opt_mysql56_temporal_format ? + MYSQL_TYPE_TIME2 : MYSQL_TYPE_TIME; } | TIMESTAMP opt_field_length { if (thd->variables.sql_mode & MODE_MAXDB) - $$=MYSQL_TYPE_DATETIME; + $$= opt_mysql56_temporal_format ? + MYSQL_TYPE_DATETIME2 : MYSQL_TYPE_DATETIME; else { /* Unlike other types TIMESTAMP fields are NOT NULL by default. + Unless --explicit-defaults-for-timestamp is given. */ - Lex->type|= NOT_NULL_FLAG; - $$=MYSQL_TYPE_TIMESTAMP; + if (!opt_explicit_defaults_for_timestamp) + Lex->last_field->flags|= NOT_NULL_FLAG; + $$= opt_mysql56_temporal_format ? MYSQL_TYPE_TIMESTAMP2 + : MYSQL_TYPE_TIMESTAMP; } } | DATETIME opt_field_length - { $$=MYSQL_TYPE_DATETIME; } + { $$= opt_mysql56_temporal_format ? + MYSQL_TYPE_DATETIME2 : MYSQL_TYPE_DATETIME; } | TINYBLOB { Lex->charset=&my_charset_bin; @@ -5693,16 +6211,15 @@ type: Lex->charset=&my_charset_bin; $$=MYSQL_TYPE_BLOB; } - | spatial_type + | spatial_type float_options srid_option { #ifdef HAVE_SPATIAL Lex->charset=&my_charset_bin; - Lex->uint_geom_type= (uint)$1; + Lex->last_field->geom_type= $1; $$=MYSQL_TYPE_GEOMETRY; #else - my_error(ER_FEATURE_DISABLED, MYF(0), - sym_group_geom.name, sym_group_geom.needed_define); - MYSQL_YYABORT; + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, + sym_group_geom.needed_define)); #endif } | MEDIUMBLOB @@ -5736,20 +6253,16 @@ type: { $$=MYSQL_TYPE_NEWDECIMAL;} | FIXED_SYM float_options field_options { $$=MYSQL_TYPE_NEWDECIMAL;} - | ENUM - {Lex->interval_list.empty();} - '(' string_list ')' opt_binary + | ENUM '(' string_list ')' opt_binary { $$=MYSQL_TYPE_ENUM; } - | SET - { Lex->interval_list.empty();} - '(' string_list ')' opt_binary + | SET '(' string_list ')' opt_binary { $$=MYSQL_TYPE_SET; } | LONG_SYM opt_binary { $$=MYSQL_TYPE_MEDIUM_BLOB; } | SERIAL_SYM { $$=MYSQL_TYPE_LONGLONG; - Lex->type|= (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG | + Lex->last_field->flags|= (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG | UNIQUE_FLAG); } ; @@ -5812,6 +6325,16 @@ real_type: { $$=MYSQL_TYPE_DOUBLE; } ; +srid_option: + /* empty */ + { Lex->last_field->srid= 0; } + | + REF_SYSTEM_ID_SYM '=' NUM + { + Lex->last_field->srid=atoi($3.str); + } + ; + float_options: /* empty */ { Lex->dec=Lex->length= (char*)0; } @@ -5842,8 +6365,8 @@ field_opt_list: field_option: SIGNED_SYM {} - | UNSIGNED { Lex->type|= UNSIGNED_FLAG;} - | ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; } + | UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG;} + | ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; } ; field_length: @@ -5873,106 +6396,98 @@ opt_attribute_list: ; attribute: - NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; } - | not NULL_SYM { Lex->type|= NOT_NULL_FLAG; } - | DEFAULT now_or_signed_literal { Lex->default_value=$2; } - | ON UPDATE_SYM NOW_SYM optional_braces + NULL_SYM { Lex->last_field->flags&= ~ NOT_NULL_FLAG; } + | not NULL_SYM { Lex->last_field->flags|= NOT_NULL_FLAG; } + | DEFAULT now_or_signed_literal { Lex->last_field->def= $2; } + | ON UPDATE_SYM NOW_SYM opt_default_time_precision { - Item *item= new (thd->mem_root) Item_func_now_local(6); + Item *item= new (thd->mem_root) Item_func_now_local(thd, $4); if (item == NULL) MYSQL_YYABORT; - Lex->on_update_value= item; + Lex->last_field->on_update= item; } - | AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; } + | AUTO_INC { Lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; } | SERIAL_SYM DEFAULT VALUE_SYM { LEX *lex=Lex; - lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_FLAG; - lex->alter_info.flags|= ALTER_ADD_INDEX; + lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_FLAG; + lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } | opt_primary KEY_SYM { LEX *lex=Lex; - lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG; - lex->alter_info.flags|= ALTER_ADD_INDEX; + lex->last_field->flags|= PRI_KEY_FLAG | NOT_NULL_FLAG; + lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } | UNIQUE_SYM { LEX *lex=Lex; - lex->type|= UNIQUE_FLAG; - lex->alter_info.flags|= ALTER_ADD_INDEX; + lex->last_field->flags|= UNIQUE_FLAG; + lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } | UNIQUE_SYM KEY_SYM { LEX *lex=Lex; - lex->type|= UNIQUE_KEY_FLAG; - lex->alter_info.flags|= ALTER_ADD_INDEX; + lex->last_field->flags|= UNIQUE_KEY_FLAG; + lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } - | COMMENT_SYM TEXT_STRING_sys { Lex->comment= $2; } + | COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; } | COLLATE_SYM collation_name { if (Lex->charset && !my_charset_same(Lex->charset,$2)) - { - my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), - $2->name,Lex->charset->csname); - MYSQL_YYABORT; - } - else - { - Lex->charset=$2; - } + my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0), + $2->name,Lex->charset->csname)); + Lex->last_field->charset= $2; } | IDENT_sys equal TEXT_STRING_sys { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) - engine_option_value($1, $3, true, &Lex->option_list, + engine_option_value($1, $3, true, &Lex->last_field->option_list, &Lex->option_list_last); } | IDENT_sys equal ident { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) - engine_option_value($1, $3, false, &Lex->option_list, + engine_option_value($1, $3, false, &Lex->last_field->option_list, &Lex->option_list_last); } | IDENT_sys equal real_ulonglong_num { new (thd->mem_root) - engine_option_value($1, $3, &Lex->option_list, + engine_option_value($1, $3, &Lex->last_field->option_list, &Lex->option_list_last, thd->mem_root); } | IDENT_sys equal DEFAULT { new (thd->mem_root) - engine_option_value($1, &Lex->option_list, &Lex->option_list_last); + engine_option_value($1, &Lex->last_field->option_list, &Lex->option_list_last); } ; type_with_opt_collate: - type opt_collate + field_type opt_collate { $$= $1; - if (Lex->charset) /* Lex->charset is scanned in "type" */ + if ($2) { if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2))) MYSQL_YYABORT; } - else if ($2) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), - "COLLATE with no CHARACTER SET " - "in SP parameters, RETURNS, DECLARE"); - MYSQL_YYABORT; - } + Lex->set_last_field_type($1); } ; now_or_signed_literal: - NOW_SYM optional_braces + NOW_SYM opt_default_time_precision { - $$= new (thd->mem_root) Item_func_now_local(6); + $$= new (thd->mem_root) Item_func_now_local(thd, $2); if ($$ == NULL) MYSQL_YYABORT; } @@ -5980,11 +6495,6 @@ now_or_signed_literal: { $$=$1; } ; -hex_num_or_string: - HEX_NUM {} - | HEX_STRING {} - ; - charset: CHAR_SYM SET {} | CHARSET {} @@ -5994,10 +6504,7 @@ charset_name: ident_or_text { if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0)))) - { - my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str)); } | BINARY { $$= &my_charset_bin; } ; @@ -6017,10 +6524,7 @@ old_or_new_charset_name: { if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0))) && !($$=get_old_charset_by_name($1.str))) - { - my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str)); } | BINARY { $$= &my_charset_bin; } ; @@ -6033,11 +6537,8 @@ old_or_new_charset_name_or_default: collation_name: ident_or_text { - if (!($$=get_charset_by_name($1.str,MYF(0)))) - { - my_error(ER_UNKNOWN_COLLATION, MYF(0), $1.str); + if (!($$= mysqld_collation_get_by_name($1.str))) MYSQL_YYABORT; - } } ; @@ -6056,70 +6557,96 @@ opt_default: | DEFAULT {} ; - -ascii: - ASCII_SYM { Lex->charset= &my_charset_latin1; } - | BINARY ASCII_SYM - { - Lex->charset= &my_charset_latin1_bin; - } - | ASCII_SYM BINARY +charset_or_alias: + charset charset_name { $$= $2; } + | ASCII_SYM { $$= &my_charset_latin1; } + | UNICODE_SYM { - Lex->charset= &my_charset_latin1_bin; + if (!($$= get_charset_by_csname("ucs2", MY_CS_PRIMARY,MYF(0)))) + my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2")); } ; -unicode: - UNICODE_SYM - { - if (!(Lex->charset=get_charset_by_csname("ucs2", - MY_CS_PRIMARY,MYF(0)))) - { - my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2"); - MYSQL_YYABORT; - } - } - | UNICODE_SYM BINARY - { - if (!(Lex->charset=get_charset_by_name("ucs2_bin", MYF(0)))) - { - my_error(ER_UNKNOWN_COLLATION, MYF(0), "ucs2_bin"); - MYSQL_YYABORT; - } - } - | BINARY UNICODE_SYM - { - if (!(Lex->charset=get_charset_by_name("ucs2_bin", MYF(0)))) - { - my_error(ER_UNKNOWN_COLLATION, MYF(0), "ucs2_bin"); - MYSQL_YYABORT; - } - } +opt_binary: + /* empty */ { bincmp_collation(NULL, false); } + | BYTE_SYM { bincmp_collation(&my_charset_bin, false); } + | charset_or_alias opt_bin_mod { bincmp_collation($1, $2); } + | BINARY { bincmp_collation(NULL, true); } + | BINARY charset_or_alias { bincmp_collation($2, true); } ; -opt_binary: - /* empty */ { Lex->charset=NULL; } - | ascii - | unicode - | BYTE_SYM { Lex->charset=&my_charset_bin; } - | charset charset_name opt_bin_mod { Lex->charset=$2; } - | BINARY - { - Lex->charset= NULL; - Lex->type|= BINCMP_FLAG; - } - | BINARY charset charset_name +opt_bin_mod: + /* empty */ { $$= false; } + | BINARY { $$= true; } + ; + +ws_nweights: + '(' real_ulong_num + { + if ($2 == 0) { - Lex->charset= $3; - Lex->type|= BINCMP_FLAG; + my_parse_error(thd, ER_SYNTAX_ERROR); + MYSQL_YYABORT; } + } + ')' + { $$= $2; } ; -opt_bin_mod: - /* empty */ { } - | BINARY { Lex->type|= BINCMP_FLAG; } +ws_level_flag_desc: + ASC { $$= 0; } + | DESC { $$= 1 << MY_STRXFRM_DESC_SHIFT; } + ; + +ws_level_flag_reverse: + REVERSE_SYM { $$= 1 << MY_STRXFRM_REVERSE_SHIFT; } ; + +ws_level_flags: + /* empty */ { $$= 0; } + | ws_level_flag_desc { $$= $1; } + | ws_level_flag_desc ws_level_flag_reverse { $$= $1 | $2; } + | ws_level_flag_reverse { $$= $1 ; } ; +ws_level_number: + real_ulong_num + { + $$= $1 < 1 ? 1 : ($1 > MY_STRXFRM_NLEVELS ? MY_STRXFRM_NLEVELS : $1); + $$--; + } + ; + +ws_level_list_item: + ws_level_number ws_level_flags + { + $$= (1 | $2) << $1; + } + ; + +ws_level_list: + ws_level_list_item { $$= $1; } + | ws_level_list ',' ws_level_list_item { $$|= $3; } + ; + +ws_level_range: + ws_level_number '-' ws_level_number + { + uint start= $1; + uint end= $3; + for ($$= 0; start <= end; start++) + $$|= (1 << start); + } + ; + +ws_level_list_or_range: + ws_level_list { $$= $1; } + | ws_level_range { $$= $1; } + ; + +opt_ws_levels: + /* empty*/ { $$= 0; } + | LEVEL_SYM ws_level_list_or_range { $$= $2; } + ; opt_primary: /* empty */ @@ -6146,19 +6673,19 @@ opt_ref_list: ref_list: ref_list ',' ident { - Key_part_spec *key= new Key_part_spec($3, 0); + Key_part_spec *key= new (thd->mem_root) Key_part_spec($3, 0); if (key == NULL) MYSQL_YYABORT; - Lex->ref_list.push_back(key); + Lex->ref_list.push_back(key, thd->mem_root); } | ident { - Key_part_spec *key= new Key_part_spec($1, 0); + Key_part_spec *key= new (thd->mem_root) Key_part_spec($1, 0); if (key == NULL) MYSQL_YYABORT; LEX *lex= Lex; lex->ref_list.empty(); - lex->ref_list.push_back(key); + lex->ref_list.push_back(key, thd->mem_root); } ; @@ -6177,19 +6704,19 @@ opt_on_update_delete: /* empty */ { LEX *lex= Lex; - lex->fk_update_opt= Foreign_key::FK_OPTION_UNDEF; - lex->fk_delete_opt= Foreign_key::FK_OPTION_UNDEF; + lex->fk_update_opt= FK_OPTION_UNDEF; + lex->fk_delete_opt= FK_OPTION_UNDEF; } | ON UPDATE_SYM delete_option { LEX *lex= Lex; lex->fk_update_opt= $3; - lex->fk_delete_opt= Foreign_key::FK_OPTION_UNDEF; + lex->fk_delete_opt= FK_OPTION_UNDEF; } | ON DELETE_SYM delete_option { LEX *lex= Lex; - lex->fk_update_opt= Foreign_key::FK_OPTION_UNDEF; + lex->fk_update_opt= FK_OPTION_UNDEF; lex->fk_delete_opt= $3; } | ON UPDATE_SYM delete_option @@ -6209,15 +6736,11 @@ opt_on_update_delete: ; delete_option: - RESTRICT { $$= Foreign_key::FK_OPTION_RESTRICT; } - | CASCADE { $$= Foreign_key::FK_OPTION_CASCADE; } - | SET NULL_SYM { $$= Foreign_key::FK_OPTION_SET_NULL; } - | NO_SYM ACTION { $$= Foreign_key::FK_OPTION_NO_ACTION; } - | SET DEFAULT { $$= Foreign_key::FK_OPTION_DEFAULT; } - ; - -normal_key_type: - key_or_index { $$= Key::MULTIPLE; } + RESTRICT { $$= FK_OPTION_RESTRICT; } + | CASCADE { $$= FK_OPTION_CASCADE; } + | SET NULL_SYM { $$= FK_OPTION_SET_NULL; } + | NO_SYM ACTION { $$= FK_OPTION_NO_ACTION; } + | SET DEFAULT { $$= FK_OPTION_SET_DEFAULT; } ; constraint_key_type: @@ -6256,43 +6779,25 @@ spatial: #ifdef HAVE_SPATIAL $$= Key::SPATIAL; #else - my_error(ER_FEATURE_DISABLED, MYF(0), - sym_group_geom.name, sym_group_geom.needed_define); - MYSQL_YYABORT; + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, + sym_group_geom.needed_define)); #endif } ; -init_key_options: - { - Lex->key_create_info= default_key_create_info; - } - ; - -/* - For now, key_alg initializies lex->key_create_info. - In the future, when all key options are after key definition, - we can remove key_alg and move init_key_options to key_options -*/ - -key_alg: - init_key_options - | init_key_options key_using_alg - ; - normal_key_options: /* empty */ {} - | normal_key_opts + | normal_key_opts { Lex->last_key->option_list= Lex->option_list; } ; fulltext_key_options: /* empty */ {} - | fulltext_key_opts + | fulltext_key_opts { Lex->last_key->option_list= Lex->option_list; } ; spatial_key_options: /* empty */ {} - | spatial_key_opts + | spatial_key_opts { Lex->last_key->option_list= Lex->option_list; } ; normal_key_opts: @@ -6310,23 +6815,40 @@ fulltext_key_opts: | fulltext_key_opts fulltext_key_opt ; +opt_USING_key_algorithm: + /* Empty*/ { $$= HA_KEY_ALG_UNDEF; } + | USING btree_or_rtree { $$= $2; } + +/* TYPE is a valid identifier, so it's handled differently than USING */ +opt_key_algorithm_clause: + /* Empty*/ { $$= HA_KEY_ALG_UNDEF; } + | USING btree_or_rtree { $$= $2; } + | TYPE_SYM btree_or_rtree { $$= $2; } + key_using_alg: - USING btree_or_rtree { Lex->key_create_info.algorithm= $2; } - | TYPE_SYM btree_or_rtree { Lex->key_create_info.algorithm= $2; } + USING btree_or_rtree + { Lex->last_key->key_create_info.algorithm= $2; } + | TYPE_SYM btree_or_rtree + { Lex->last_key->key_create_info.algorithm= $2; } ; all_key_opt: KEY_BLOCK_SIZE opt_equal ulong_num - { Lex->key_create_info.block_size= $3; } - | COMMENT_SYM TEXT_STRING_sys { Lex->key_create_info.comment= $2; } + { Lex->last_key->key_create_info.block_size= $3; } + | COMMENT_SYM TEXT_STRING_sys + { Lex->last_key->key_create_info.comment= $2; } | IDENT_sys equal TEXT_STRING_sys { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, true, &Lex->option_list, &Lex->option_list_last); } | IDENT_sys equal ident { + if ($3.length > ENGINE_OPTION_MAX_LENGTH) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); new (thd->mem_root) engine_option_value($1, $3, false, &Lex->option_list, &Lex->option_list_last); @@ -6358,12 +6880,9 @@ fulltext_key_opt: | WITH PARSER_SYM IDENT_sys { if (plugin_is_ready(&$3, MYSQL_FTPARSER_PLUGIN)) - Lex->key_create_info.parser_name= $3; + Lex->last_key->key_create_info.parser_name= $3; else - { - my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str)); } ; @@ -6374,14 +6893,20 @@ btree_or_rtree: ; key_list: - key_list ',' key_part order_dir { Lex->col_list.push_back($3); } - | key_part order_dir { Lex->col_list.push_back($1); } + key_list ',' key_part order_dir + { + Lex->last_key->columns.push_back($3, thd->mem_root); + } + | key_part order_dir + { + Lex->last_key->columns.push_back($1, thd->mem_root); + } ; key_part: ident { - $$= new Key_part_spec($1, 0); + $$= new (thd->mem_root) Key_part_spec($1, 0); if ($$ == NULL) MYSQL_YYABORT; } @@ -6389,10 +6914,8 @@ key_part: { int key_part_len= atoi($3.str); if (!key_part_len) - { - my_error(ER_KEY_PART_0, MYF(0), $1.str); - } - $$= new Key_part_spec($1, (uint) key_part_len); + my_yyabort_error((ER_KEY_PART_0, MYF(0), $1.str)); + $$= new (thd->mem_root) Key_part_spec($1, (uint) key_part_len); if ($$ == NULL) MYSQL_YYABORT; } @@ -6409,47 +6932,47 @@ opt_component: ; string_list: - text_string { Lex->interval_list.push_back($1); } - | string_list ',' text_string { Lex->interval_list.push_back($3); }; + text_string + { Lex->last_field->interval_list.push_back($1, thd->mem_root); } + | string_list ',' text_string + { Lex->last_field->interval_list.push_back($3, thd->mem_root); }; /* ** Alter table */ alter: - ALTER alter_options TABLE_SYM table_ident + ALTER + { + Lex->name= null_lex_str; + Lex->only_view= FALSE; + Lex->sql_command= SQLCOM_ALTER_TABLE; + Lex->duplicates= DUP_ERROR; + Lex->select_lex.init_order(); + Lex->create_info.init(); + Lex->create_info.row_type= ROW_TYPE_NOT_USED; + Lex->alter_info.reset(); + Lex->no_write_to_binlog= 0; + Lex->create_info.storage_media= HA_SM_DEFAULT; + DBUG_ASSERT(!Lex->m_sql_cmd); + } + alter_options TABLE_SYM table_ident { - LEX *lex= thd->lex; - lex->name.str= 0; - lex->name.length= 0; - lex->sql_command= SQLCOM_ALTER_TABLE; - lex->duplicates= DUP_ERROR; - if (!lex->select_lex.add_table_to_list(thd, $4, NULL, + if (!Lex->select_lex.add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE)) + MDL_SHARED_UPGRADABLE)) MYSQL_YYABORT; - lex->col_list.empty(); - lex->select_lex.init_order(); - lex->select_lex.db= (lex->select_lex.table_list.first)->db; - bzero((char*) &lex->create_info,sizeof(lex->create_info)); - lex->create_info.db_type= 0; - lex->create_info.default_table_charset= NULL; - lex->create_info.row_type= ROW_TYPE_NOT_USED; - lex->alter_info.reset(); - lex->no_write_to_binlog= 0; - lex->create_info.storage_media= HA_SM_DEFAULT; - lex->create_last_non_select_table= lex->last_table(); - DBUG_ASSERT(!lex->m_stmt); + Lex->select_lex.db= (Lex->select_lex.table_list.first)->db; + Lex->create_last_non_select_table= Lex->last_table(); } alter_commands { - LEX *lex= thd->lex; - if (!lex->m_stmt) + if (!Lex->m_sql_cmd) { /* Create a generic ALTER TABLE statment. */ - lex->m_stmt= new (thd->mem_root) Alter_table_statement(lex); - if (lex->m_stmt == NULL) + Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table(); + if (Lex->m_sql_cmd == NULL) MYSQL_YYABORT; } } @@ -6471,10 +6994,7 @@ alter: { LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "DATABASE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "DATABASE")); lex->sql_command= SQLCOM_ALTER_DB_UPGRADE; lex->name= $3; } @@ -6483,10 +7003,7 @@ alter: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE")); bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); } sp_a_chistics @@ -6501,10 +7018,7 @@ alter: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION")); bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); } sp_a_chistics @@ -6519,10 +7033,7 @@ alter: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "ALTER VIEW"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "ALTER VIEW")); lex->create_view_mode= VIEW_ALTER; } view_tail @@ -6537,16 +7048,13 @@ alter: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "ALTER VIEW"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "ALTER VIEW")); lex->create_view_algorithm= VIEW_ALGORITHM_INHERIT; lex->create_view_mode= VIEW_ALTER; } view_tail {} - | ALTER definer_opt EVENT_SYM sp_name + | ALTER definer_opt remember_name EVENT_SYM sp_name { /* It is safe to use Lex->spname because @@ -6558,9 +7066,10 @@ alter: if (!(Lex->event_parse_data= Event_parse_data::new_instance(thd))) MYSQL_YYABORT; - Lex->event_parse_data->identifier= $4; + Lex->event_parse_data->identifier= $5; Lex->sql_command= SQLCOM_ALTER_EVENT; + Lex->stmt_definition_begin= $3; } ev_alter_on_schedule_completion opt_ev_rename_to @@ -6568,9 +7077,9 @@ alter: opt_ev_comment opt_ev_sql_stmt { - if (!($6 || $7 || $8 || $9 || $10)) + if (!($7 || $8 || $9 || $10 || $11)) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } /* @@ -6578,6 +7087,7 @@ alter: can overwrite it */ Lex->sql_command= SQLCOM_ALTER_EVENT; + Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr(); } | ALTER TABLESPACE alter_tablespace_info { @@ -6599,13 +7109,12 @@ alter: LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= ALTER_ACCESS_MODE_TABLESPACE; } - | ALTER SERVER_SYM ident_or_text OPTIONS_SYM '(' server_options_list ')' + | ALTER SERVER_SYM ident_or_text { LEX *lex= Lex; lex->sql_command= SQLCOM_ALTER_SERVER; - lex->server_options.server_name= $3.str; - lex->server_options.server_name_length= $3.length; - } + lex->server_options.reset($3); + } OPTIONS_SYM '(' server_options_list ')' { } ; ev_alter_on_schedule_completion: @@ -6634,14 +7143,28 @@ opt_ev_sql_stmt: ; ident_or_empty: - /* empty */ { $$.str= 0; $$.length= 0; } + /* empty */ { $$= null_lex_str; } | ident { $$= $1; } ; alter_commands: /* empty */ - | DISCARD TABLESPACE { Lex->alter_info.tablespace_op= DISCARD_TABLESPACE; } - | IMPORT TABLESPACE { Lex->alter_info.tablespace_op= IMPORT_TABLESPACE; } + | DISCARD TABLESPACE + { + Lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_discard_import_tablespace( + Sql_cmd_discard_import_tablespace::DISCARD_TABLESPACE); + if (Lex->m_sql_cmd == NULL) + MYSQL_YYABORT; + } + | IMPORT TABLESPACE + { + Lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_discard_import_tablespace( + Sql_cmd_discard_import_tablespace::IMPORT_TABLESPACE); + if (Lex->m_sql_cmd == NULL) + MYSQL_YYABORT; + } | alter_list opt_partitioning | alter_list @@ -6653,19 +7176,20 @@ alter_commands: From here we insert a number of commands to manage the partitions of a partitioned table such as adding partitions, dropping partitions, reorganising partitions in various manners. In future releases the list - will be longer and also include moving partitions to a - new table and so forth. + will be longer. */ | add_partition_rule - | DROP PARTITION_SYM alt_part_name_list + | DROP PARTITION_SYM opt_if_exists alt_part_name_list { - Lex->alter_info.flags|= ALTER_DROP_PARTITION; + Lex->alter_info.flags|= Alter_info::ALTER_DROP_PARTITION; + DBUG_ASSERT(!Lex->if_exists()); + Lex->create_info.add($3); } | REBUILD_SYM PARTITION_SYM opt_no_write_to_binlog all_or_alt_part_name_list { LEX *lex= Lex; - lex->alter_info.flags|= ALTER_REBUILD_PARTITION; + lex->alter_info.flags|= Alter_info::ALTER_REBUILD_PARTITION; lex->no_write_to_binlog= $3; } | OPTIMIZE PARTITION_SYM opt_no_write_to_binlog @@ -6674,10 +7198,10 @@ alter_commands: LEX *lex= thd->lex; lex->no_write_to_binlog= $3; lex->check_opt.init(); - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) - Alter_table_optimize_partition_statement(lex); - if (lex->m_stmt == NULL) + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_optimize_partition(); + if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; } opt_no_write_to_binlog @@ -6687,20 +7211,20 @@ alter_commands: LEX *lex= thd->lex; lex->no_write_to_binlog= $3; lex->check_opt.init(); - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) - Alter_table_analyze_partition_statement(lex); - if (lex->m_stmt == NULL) - MYSQL_YYABORT; + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_analyze_partition(); + if (lex->m_sql_cmd == NULL) + MYSQL_YYABORT; } | CHECK_SYM PARTITION_SYM all_or_alt_part_name_list { LEX *lex= thd->lex; lex->check_opt.init(); - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) - Alter_table_check_partition_statement(lex); - if (lex->m_stmt == NULL) + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_check_partition(); + if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; } opt_mi_check_type @@ -6710,17 +7234,17 @@ alter_commands: LEX *lex= thd->lex; lex->no_write_to_binlog= $3; lex->check_opt.init(); - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) - Alter_table_repair_partition_statement(lex); - if (lex->m_stmt == NULL) + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_repair_partition(); + if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; } opt_mi_repair_type | COALESCE PARTITION_SYM opt_no_write_to_binlog real_ulong_num { LEX *lex= Lex; - lex->alter_info.flags|= ALTER_COALESCE_PARTITION; + lex->alter_info.flags|= Alter_info::ALTER_COALESCE_PARTITION; lex->no_write_to_binlog= $3; lex->alter_info.num_parts= $4; } @@ -6728,42 +7252,69 @@ alter_commands: { LEX *lex= thd->lex; lex->check_opt.init(); - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) - Alter_table_truncate_partition_statement(lex); - if (lex->m_stmt == NULL) + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_truncate_partition(); + if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; } | reorg_partition_rule + | EXCHANGE_SYM PARTITION_SYM alt_part_name_item + WITH TABLE_SYM table_ident have_partitioning + { + LEX *lex= thd->lex; + size_t dummy; + lex->select_lex.db=$6->db.str; + if (lex->select_lex.db == NULL && + lex->copy_db_to(&lex->select_lex.db, &dummy)) + { + MYSQL_YYABORT; + } + lex->name= $6->table; + lex->alter_info.flags|= Alter_info::ALTER_EXCHANGE_PARTITION; + if (!lex->select_lex.add_table_to_list(thd, $6, NULL, + TL_OPTION_UPDATING, + TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) + MYSQL_YYABORT; + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_exchange_partition(); + if (lex->m_sql_cmd == NULL) + MYSQL_YYABORT; + } ; remove_partitioning: REMOVE_SYM PARTITIONING_SYM { - Lex->alter_info.flags|= ALTER_REMOVE_PARTITIONING; + Lex->alter_info.flags|= Alter_info::ALTER_REMOVE_PARTITIONING; } ; all_or_alt_part_name_list: ALL { - Lex->alter_info.flags|= ALTER_ALL_PARTITION; + Lex->alter_info.flags|= Alter_info::ALTER_ALL_PARTITION; } | alt_part_name_list ; add_partition_rule: - ADD PARTITION_SYM opt_no_write_to_binlog + ADD PARTITION_SYM opt_if_not_exists + opt_no_write_to_binlog { LEX *lex= Lex; - lex->part_info= new partition_info(); + lex->part_info= new (thd->mem_root) partition_info(); if (!lex->part_info) { mem_alloc_error(sizeof(partition_info)); MYSQL_YYABORT; } - lex->alter_info.flags|= ALTER_ADD_PARTITION; - lex->no_write_to_binlog= $3; + lex->alter_info.flags|= Alter_info::ALTER_ADD_PARTITION; + DBUG_ASSERT(!Lex->create_info.if_not_exists()); + lex->create_info.set($3); + lex->no_write_to_binlog= $4; } add_part_extra {} @@ -6786,7 +7337,7 @@ reorg_partition_rule: REORGANIZE_SYM PARTITION_SYM opt_no_write_to_binlog { LEX *lex= Lex; - lex->part_info= new partition_info(); + lex->part_info= new (thd->mem_root) partition_info(); if (!lex->part_info) { mem_alloc_error(sizeof(partition_info)); @@ -6800,11 +7351,11 @@ reorg_partition_rule: reorg_parts_rule: /* empty */ { - Lex->alter_info.flags|= ALTER_TABLE_REORG; + Lex->alter_info.flags|= Alter_info::ALTER_TABLE_REORG; } | alt_part_name_list { - Lex->alter_info.flags|= ALTER_REORGANIZE_PARTITION; + Lex->alter_info.flags|= Alter_info::ALTER_REORGANIZE_PARTITION; } INTO '(' part_def_list ')' { @@ -6821,7 +7372,8 @@ alt_part_name_list: alt_part_name_item: ident { - if (Lex->alter_info.partition_names.push_back($1.str)) + if (Lex->alter_info.partition_names.push_back($1.str, + thd->mem_root)) { mem_alloc_error(1); MYSQL_YYABORT; @@ -6839,11 +7391,10 @@ alter_list: ; add_column: - ADD opt_column + ADD opt_column opt_if_not_exists_table_element { LEX *lex=Lex; - lex->change=0; - lex->alter_info.flags|= ALTER_ADD_COLUMN; + lex->alter_info.flags|= Alter_info::ALTER_ADD_COLUMN; } ; @@ -6855,111 +7406,98 @@ alter_list_item: | ADD key_def { Lex->create_last_non_select_table= Lex->last_table(); - Lex->alter_info.flags|= ALTER_ADD_INDEX; + Lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } | add_column '(' create_field_list ')' { - Lex->alter_info.flags|= ALTER_ADD_COLUMN | ALTER_ADD_INDEX; - } - | CHANGE opt_column field_ident - { - LEX *lex=Lex; - lex->change= $3.str; - lex->alter_info.flags|= ALTER_CHANGE_COLUMN; - lex->option_list= NULL; + Lex->alter_info.flags|= Alter_info::ALTER_ADD_COLUMN | + Alter_info::ALTER_ADD_INDEX; } + | CHANGE opt_column opt_if_exists_table_element field_ident field_spec opt_place { + Lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN; Lex->create_last_non_select_table= Lex->last_table(); + Lex->last_field->change= $4.str; } - | MODIFY_SYM opt_column field_ident + | MODIFY_SYM opt_column opt_if_exists_table_element + field_spec opt_place { - LEX *lex=Lex; - lex->length=lex->dec=0; lex->type=0; - lex->default_value= lex->on_update_value= 0; - lex->comment=null_lex_str; - lex->charset= NULL; - lex->alter_info.flags|= ALTER_CHANGE_COLUMN; - lex->vcol_info= 0; - lex->option_list= NULL; + Lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN; + Lex->create_last_non_select_table= Lex->last_table(); + Lex->last_field->change= Lex->last_field->field_name; } - field_def + | DROP opt_column opt_if_exists_table_element field_ident opt_restrict { LEX *lex=Lex; - if (add_field_to_list(lex->thd,&$3, - $5.type, - $5.length, $5.dec, lex->type, - lex->default_value, lex->on_update_value, - &lex->comment, - $3.str, &lex->interval_list, $5.charset, - lex->uint_geom_type, - lex->vcol_info, lex->option_list)) + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::COLUMN, $4.str, $3)); + if (ad == NULL) MYSQL_YYABORT; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + lex->alter_info.flags|= Alter_info::ALTER_DROP_COLUMN; } - opt_place - { - Lex->create_last_non_select_table= Lex->last_table(); - } - | DROP opt_column field_ident opt_restrict + | DROP FOREIGN KEY_SYM opt_if_exists_table_element field_ident { LEX *lex=Lex; - Alter_drop *ad= new Alter_drop(Alter_drop::COLUMN, $3.str); + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::FOREIGN_KEY, $5.str, $4)); if (ad == NULL) MYSQL_YYABORT; - lex->alter_info.drop_list.push_back(ad); - lex->alter_info.flags|= ALTER_DROP_COLUMN; - } - | DROP FOREIGN KEY_SYM opt_ident - { - Lex->alter_info.flags|= ALTER_DROP_INDEX | ALTER_FOREIGN_KEY; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + lex->alter_info.flags|= Alter_info::DROP_FOREIGN_KEY; } | DROP PRIMARY_SYM KEY_SYM { LEX *lex=Lex; - Alter_drop *ad= new Alter_drop(Alter_drop::KEY, primary_key_name); + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::KEY, primary_key_name, + FALSE)); if (ad == NULL) MYSQL_YYABORT; - lex->alter_info.drop_list.push_back(ad); - lex->alter_info.flags|= ALTER_DROP_INDEX; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + lex->alter_info.flags|= Alter_info::ALTER_DROP_INDEX; } - | DROP key_or_index field_ident + | DROP key_or_index opt_if_exists_table_element field_ident { LEX *lex=Lex; - Alter_drop *ad= new Alter_drop(Alter_drop::KEY, $3.str); + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::KEY, $4.str, $3)); if (ad == NULL) MYSQL_YYABORT; - lex->alter_info.drop_list.push_back(ad); - lex->alter_info.flags|= ALTER_DROP_INDEX; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + lex->alter_info.flags|= Alter_info::ALTER_DROP_INDEX; } | DISABLE_SYM KEYS { LEX *lex=Lex; - lex->alter_info.keys_onoff= DISABLE; - lex->alter_info.flags|= ALTER_KEYS_ONOFF; + lex->alter_info.keys_onoff= Alter_info::DISABLE; + lex->alter_info.flags|= Alter_info::ALTER_KEYS_ONOFF; } | ENABLE_SYM KEYS { LEX *lex=Lex; - lex->alter_info.keys_onoff= ENABLE; - lex->alter_info.flags|= ALTER_KEYS_ONOFF; + lex->alter_info.keys_onoff= Alter_info::ENABLE; + lex->alter_info.flags|= Alter_info::ALTER_KEYS_ONOFF; } | ALTER opt_column field_ident SET DEFAULT signed_literal { LEX *lex=Lex; - Alter_column *ac= new Alter_column($3.str,$6); + Alter_column *ac= new (thd->mem_root) Alter_column($3.str,$6); if (ac == NULL) MYSQL_YYABORT; - lex->alter_info.alter_list.push_back(ac); - lex->alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT; + lex->alter_info.alter_list.push_back(ac, thd->mem_root); + lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN_DEFAULT; } | ALTER opt_column field_ident DROP DEFAULT { LEX *lex=Lex; - Alter_column *ac= new Alter_column($3.str, (Item*) 0); + Alter_column *ac= (new (thd->mem_root) + Alter_column($3.str, (Item*) 0)); if (ac == NULL) MYSQL_YYABORT; - lex->alter_info.alter_list.push_back(ac); - lex->alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT; + lex->alter_info.alter_list.push_back(ac, thd->mem_root); + lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN_DEFAULT; } | RENAME opt_to table_ident { @@ -6973,12 +7511,9 @@ alter_list_item: } if (check_table_name($3->table.str,$3->table.length, FALSE) || ($3->db.str && check_db_name(&$3->db))) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $3->table.str)); lex->name= $3->table; - lex->alter_info.flags|= ALTER_RENAME; + lex->alter_info.flags|= Alter_info::ALTER_RENAME; } | CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate { @@ -6988,22 +7523,16 @@ alter_list_item: } $5= $5 ? $5 : $4; if (!my_charset_same($4,$5)) - { - my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), - $5->name, $4->csname); + my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0), + $5->name, $4->csname)); + if (Lex->create_info.add_alter_list_item_convert_to_charset($5)) MYSQL_YYABORT; - } - LEX *lex= Lex; - lex->create_info.table_charset= - lex->create_info.default_table_charset= $5; - lex->create_info.used_fields|= (HA_CREATE_USED_CHARSET | - HA_CREATE_USED_DEFAULT_CHARSET); - lex->alter_info.flags|= ALTER_CONVERT; + Lex->alter_info.flags|= Alter_info::ALTER_OPTIONS; } | create_table_options_space_separated { LEX *lex=Lex; - lex->alter_info.flags|= ALTER_OPTIONS; + lex->alter_info.flags|= Alter_info::ALTER_OPTIONS; if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && !lex->create_info.db_type) { @@ -7012,12 +7541,47 @@ alter_list_item: } | FORCE_SYM { - Lex->alter_info.flags|= ALTER_RECREATE; + Lex->alter_info.flags|= Alter_info::ALTER_RECREATE; } | alter_order_clause { LEX *lex=Lex; - lex->alter_info.flags|= ALTER_ORDER; + lex->alter_info.flags|= Alter_info::ALTER_ORDER; + } + | alter_algorithm_option + | alter_lock_option + ; + +opt_index_lock_algorithm: + /* empty */ + | alter_lock_option + | alter_algorithm_option + | alter_lock_option alter_algorithm_option + | alter_algorithm_option alter_lock_option + +alter_algorithm_option: + ALGORITHM_SYM opt_equal DEFAULT + { + Lex->alter_info.requested_algorithm= + Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT; + } + | ALGORITHM_SYM opt_equal ident + { + if (Lex->alter_info.set_requested_algorithm(&$3)) + my_yyabort_error((ER_UNKNOWN_ALTER_ALGORITHM, MYF(0), $3.str)); + } + ; + +alter_lock_option: + LOCK_SYM opt_equal DEFAULT + { + Lex->alter_info.requested_lock= + Alter_info::ALTER_TABLE_LOCK_DEFAULT; + } + | LOCK_SYM opt_equal ident + { + if (Lex->alter_info.set_requested_lock(&$3)) + my_yyabort_error((ER_UNKNOWN_ALTER_LOCK, MYF(0), $3.str)); } ; @@ -7032,7 +7596,7 @@ opt_ignore: ; alter_options: - { Lex->ignore= Lex->online= 0;} alter_options_part2 + { Lex->ignore= 0;} alter_options_part2 ; alter_options_part2: @@ -7047,7 +7611,11 @@ alter_option_list: alter_option: IGNORE_SYM { Lex->ignore= 1;} - | ONLINE_SYM { Lex->online= 1;} + | ONLINE_SYM + { + Lex->alter_info.requested_lock= + Alter_info::ALTER_TABLE_LOCK_NONE; + } opt_restrict: @@ -7058,8 +7626,16 @@ opt_restrict: opt_place: /* empty */ {} - | AFTER_SYM ident { store_position_for_column($2.str); } - | FIRST_SYM { store_position_for_column(first_keyword); } + | AFTER_SYM ident + { + store_position_for_column($2.str); + Lex->alter_info.flags |= Alter_info::ALTER_COLUMN_ORDER; + } + | FIRST_SYM + { + store_position_for_column(first_keyword); + Lex->alter_info.flags |= Alter_info::ALTER_COLUMN_ORDER; + } ; opt_to: @@ -7069,12 +7645,8 @@ opt_to: | AS {} ; -/* - SLAVE START and SLAVE STOP are deprecated. We keep them for compatibility. -*/ - slave: - START_SYM SLAVE slave_thread_opts + START_SYM SLAVE optional_connection_name slave_thread_opts { LEX *lex=Lex; lex->sql_command = SQLCOM_SLAVE_START; @@ -7083,44 +7655,80 @@ slave: } slave_until {} - | STOP_SYM SLAVE slave_thread_opts + | START_SYM ALL SLAVES slave_thread_opts { LEX *lex=Lex; - lex->sql_command = SQLCOM_SLAVE_STOP; + lex->sql_command = SQLCOM_SLAVE_ALL_START; lex->type = 0; - /* If you change this code don't forget to update SLAVE STOP too */ } - | SLAVE START_SYM slave_thread_opts + {} + | STOP_SYM SLAVE optional_connection_name slave_thread_opts { LEX *lex=Lex; - lex->sql_command = SQLCOM_SLAVE_START; + lex->sql_command = SQLCOM_SLAVE_STOP; lex->type = 0; + /* If you change this code don't forget to update SLAVE STOP too */ } - slave_until - {} - | SLAVE STOP_SYM slave_thread_opts + | STOP_SYM ALL SLAVES slave_thread_opts { LEX *lex=Lex; - lex->sql_command = SQLCOM_SLAVE_STOP; + lex->sql_command = SQLCOM_SLAVE_ALL_STOP; lex->type = 0; + /* If you change this code don't forget to update SLAVE STOP too */ } ; start: - START_SYM TRANSACTION_SYM start_transaction_opts + START_SYM TRANSACTION_SYM opt_start_transaction_option_list { LEX *lex= Lex; lex->sql_command= SQLCOM_BEGIN; + /* READ ONLY and READ WRITE are mutually exclusive. */ + if (($3 & MYSQL_START_TRANS_OPT_READ_WRITE) && + ($3 & MYSQL_START_TRANS_OPT_READ_ONLY)) + { + my_parse_error(thd, ER_SYNTAX_ERROR); + MYSQL_YYABORT; + } lex->start_transaction_opt= $3; } ; -start_transaction_opts: - /*empty*/ { $$ = 0; } - | WITH CONSISTENT_SYM SNAPSHOT_SYM +opt_start_transaction_option_list: + /* empty */ + { + $$= 0; + } + | start_transaction_option_list + { + $$= $1; + } + ; + +start_transaction_option_list: + start_transaction_option + { + $$= $1; + } + | start_transaction_option_list ',' start_transaction_option + { + $$= $1 | $3; + } + ; + +start_transaction_option: + WITH CONSISTENT_SYM SNAPSHOT_SYM { $$= MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT; } + | READ_SYM ONLY_SYM + { + $$= MYSQL_START_TRANS_OPT_READ_ONLY; + } + | READ_SYM WRITE_SYM + { + $$= MYSQL_START_TRANS_OPT_READ_WRITE; + } ; slave_thread_opts: @@ -7149,11 +7757,11 @@ slave_until: (lex->mi.relay_log_name || lex->mi.relay_log_pos)) || !((lex->mi.log_file_name && lex->mi.pos) || (lex->mi.relay_log_name && lex->mi.relay_log_pos))) - { - my_message(ER_BAD_SLAVE_UNTIL_COND, - ER(ER_BAD_SLAVE_UNTIL_COND), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_BAD_SLAVE_UNTIL_COND, MYF(0))); + } + | UNTIL_SYM MASTER_GTID_POS_SYM '=' TEXT_STRING_sys + { + Lex->mi.gtid_pos_str = $4; } ; @@ -7199,9 +7807,9 @@ repair: repair_table_or_view { LEX* lex= thd->lex; - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) Repair_table_statement(lex); - if (lex->m_stmt == NULL) + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_repair_table(); + if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; } ; @@ -7238,23 +7846,121 @@ analyze: /* Will be overriden during execution. */ YYPS->m_lock_type= TL_UNLOCK; } - table_list + analyze_table_list { LEX* lex= thd->lex; - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) Analyze_table_statement(lex); - if (lex->m_stmt == NULL) + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_analyze_table(); + if (lex->m_sql_cmd == NULL) + MYSQL_YYABORT; + } + ; + +analyze_table_list: + analyze_table_elem_spec + | analyze_table_list ',' analyze_table_elem_spec + ; + +analyze_table_elem_spec: + table_name opt_persistent_stat_clause + ; + +opt_persistent_stat_clause: + /* empty */ + {} + | PERSISTENT_SYM FOR_SYM persistent_stat_spec + { + thd->lex->with_persistent_for_clause= TRUE; + } + ; + +persistent_stat_spec: + ALL + {} + | COLUMNS persistent_column_stat_spec INDEXES persistent_index_stat_spec + {} + +persistent_column_stat_spec: + ALL {} + | '(' + { + LEX* lex= thd->lex; + lex->column_list= new (thd->mem_root) List<LEX_STRING>; + if (lex->column_list == NULL) + MYSQL_YYABORT; + } + table_column_list + ')' + ; + +persistent_index_stat_spec: + ALL {} + | '(' + { + LEX* lex= thd->lex; + lex->index_list= new (thd->mem_root) List<LEX_STRING>; + if (lex->index_list == NULL) MYSQL_YYABORT; } + table_index_list + ')' + ; + +table_column_list: + /* empty */ + {} + | ident + { + Lex->column_list->push_back((LEX_STRING*) + thd->memdup(&$1, sizeof(LEX_STRING)), thd->mem_root); + } + | table_column_list ',' ident + { + Lex->column_list->push_back((LEX_STRING*) + thd->memdup(&$3, sizeof(LEX_STRING)), thd->mem_root); + } + ; + +table_index_list: + /* empty */ + {} + | table_index_name + | table_index_list ',' table_index_name ; +table_index_name: + ident + { + Lex->index_list->push_back((LEX_STRING*) + thd->memdup(&$1, sizeof(LEX_STRING)), + thd->mem_root); + } + | + PRIMARY_SYM + { + LEX_STRING str= {(char*) "PRIMARY", 7}; + Lex->index_list->push_back((LEX_STRING*) + thd->memdup(&str, sizeof(LEX_STRING)), + thd->mem_root); + } + ; + binlog_base64_event: BINLOG_SYM TEXT_STRING_sys { Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT; Lex->comment= $2; + Lex->ident.str= NULL; + Lex->ident.length= 0; } - ; + | + BINLOG_SYM '@' ident_or_text ',' '@' ident_or_text + { + Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT; + Lex->comment= $3; + Lex->ident= $6; + } + ; check_view_or_table: table_or_tables table_list opt_mi_check_type @@ -7275,13 +7981,10 @@ check: CHECK_SYM { LEX* lex= thd->lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "CHECK"); - MYSQL_YYABORT; - } - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) Check_table_statement(lex); - if (lex->m_stmt == NULL) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "CHECK")); + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_check_table(); + if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; } ; @@ -7324,9 +8027,9 @@ optimize: table_list { LEX* lex= thd->lex; - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) Optimize_table_statement(lex); - if (lex->m_stmt == NULL) + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_optimize_table(); + if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; } ; @@ -7344,7 +8047,7 @@ rename: } table_to_table_list {} - | RENAME USER clear_privileges rename_list + | RENAME USER_SYM clear_privileges rename_list { Lex->sql_command = SQLCOM_RENAME_USER; } @@ -7353,12 +8056,14 @@ rename: rename_list: user TO_SYM user { - if (Lex->users_list.push_back($1) || Lex->users_list.push_back($3)) + if (Lex->users_list.push_back($1, thd->mem_root) || + Lex->users_list.push_back($3, thd->mem_root)) MYSQL_YYABORT; } | rename_list ',' user TO_SYM user { - if (Lex->users_list.push_back($3) || Lex->users_list.push_back($5)) + if (Lex->users_list.push_back($3, thd->mem_root) || + Lex->users_list.push_back($5, thd->mem_root)) MYSQL_YYABORT; } ; @@ -7373,9 +8078,9 @@ table_to_table: { LEX *lex=Lex; SELECT_LEX *sl= lex->current_select; - if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING, + if (!sl->add_table_to_list(thd, $1,NULL,TL_OPTION_UPDATING, TL_IGNORE, MDL_EXCLUSIVE) || - !sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING, + !sl->add_table_to_list(thd, $3,NULL,TL_OPTION_UPDATING, TL_IGNORE, MDL_EXCLUSIVE)) MYSQL_YYABORT; } @@ -7473,7 +8178,7 @@ preload_keys_parts: adm_partition: PARTITION_SYM have_partitioning { - Lex->alter_info.flags|= ALTER_ADMIN_PARTITION; + Lex->alter_info.flags|= Alter_info::ALTER_ADMIN_PARTITION; } '(' all_or_alt_part_name_list ')' ; @@ -7518,6 +8223,13 @@ select_init: ; select_paren: + { + /* + In order to correctly parse UNION's global ORDER BY we need to + set braces before parsing the clause. + */ + Lex->current_select->set_braces(true); + } SELECT_SYM select_part2 { if (setup_select_in_parentheses(Lex)) @@ -7528,7 +8240,11 @@ select_paren: /* The equivalent of select_paren for nested queries. */ select_paren_derived: + { + Lex->current_select->set_braces(true); + } SELECT_SYM select_part2_derived + table_expression { if (setup_select_in_parentheses(Lex)) MYSQL_YYABORT; @@ -7540,23 +8256,44 @@ select_init2: select_part2 { LEX *lex= Lex; - SELECT_LEX * sel= lex->current_select; - if (lex->current_select->set_braces(0)) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; - } - if (sel->linkage == UNION_TYPE && - sel->master_unit()->first_select()->braces) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; - } + /* Parentheses carry no meaning here */ + lex->current_select->set_braces(false); } union_clause ; +/* + Theoretically we can merge all 3 right hand sides of the select_part2 + rule into one, however such a transformation adds one shift/reduce + conflict more. +*/ select_part2: + select_options_and_item_list + opt_order_clause + opt_limit_clause + opt_select_lock_type + | select_options_and_item_list into opt_select_lock_type + | select_options_and_item_list + opt_into + from_clause + opt_where_clause + opt_group_clause + opt_having_clause + opt_order_clause + opt_limit_clause + opt_procedure_clause + opt_into + opt_select_lock_type + { + if ($2 && $10) /* double "INTO" clause */ + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "INTO", "INTO")); + + if ($9 && ($2 || $10)) /* "INTO" with "PROCEDURE ANALYSE" */ + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "PROCEDURE", "INTO")); + } + ; + +select_options_and_item_list: { LEX *lex= Lex; SELECT_LEX *sel= lex->current_select; @@ -7568,26 +8305,36 @@ select_part2: { Select->parsing_place= NO_MATTER; } - select_into select_lock_type ; -select_into: - opt_order_clause opt_limit_clause {} - | into - | select_from - | into select_from - | select_from into +table_expression: + opt_from_clause + opt_where_clause + opt_group_clause + opt_having_clause + opt_order_clause + opt_limit_clause + opt_procedure_clause + opt_select_lock_type + ; + +from_clause: + FROM table_reference_list + ; + +opt_from_clause: + /* empty */ + | from_clause ; -select_from: - FROM join_table_list where_clause group_clause having_clause - opt_order_clause opt_limit_clause procedure_clause +table_reference_list: + join_table_list { Select->context.table_list= Select->context.first_name_resolution_table= Select->table_list.first; } - | FROM DUAL_SYM where_clause opt_limit_clause + | DUAL_SYM /* oracle compatibility: oracle always requires FROM clause, and DUAL is system table without fields. Is "SELECT 1 FROM DUAL" any better than "SELECT 1" ? @@ -7599,10 +8346,7 @@ select_options: | select_option_list { if (Select->options & SELECT_DISTINCT && Select->options & SELECT_ALL) - { - my_error(ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT")); } ; @@ -7620,26 +8364,15 @@ select_option: SQL_CACHE wasn't specified, and only once per query. */ if (Lex->current_select != &Lex->select_lex) - { - my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE"); - MYSQL_YYABORT; - } - else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) - { - my_error(ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE"); - MYSQL_YYABORT; - } - else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE"); - MYSQL_YYABORT; - } - else - { - Lex->safe_to_cache_query=0; - Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE; - Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE; - } + my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE")); + if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE")); + if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE")); + + Lex->safe_to_cache_query=0; + Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE; + Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE; } | SQL_CACHE_SYM { @@ -7648,40 +8381,31 @@ select_option: SQL_NO_CACHE wasn't specified, and only once per query. */ if (Lex->current_select != &Lex->select_lex) - { - my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE"); - MYSQL_YYABORT; - } - else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) - { - my_error(ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE"); - MYSQL_YYABORT; - } - else if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE"); - MYSQL_YYABORT; - } - else - { - Lex->safe_to_cache_query=1; - Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; - Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE; - } + my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE")); + if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE")); + if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE")); + + Lex->safe_to_cache_query=1; + Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; + Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE; } ; -select_lock_type: +opt_select_lock_type: /* empty */ | FOR_SYM UPDATE_SYM { LEX *lex=Lex; + lex->current_select->lock_type= TL_WRITE; lex->current_select->set_lock_for_tables(TL_WRITE); lex->safe_to_cache_query=0; } | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM { LEX *lex=Lex; + lex->current_select->lock_type= TL_READ_WITH_SHARED_LOCKS; lex->current_select-> set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS); lex->safe_to_cache_query=0; @@ -7694,7 +8418,7 @@ select_item_list: | '*' { Item *item= new (thd->mem_root) - Item_field(&thd->lex->current_select->context, + Item_field(thd, &thd->lex->current_select->context, NULL, NULL, "*"); if (item == NULL) MYSQL_YYABORT; @@ -7720,10 +8444,7 @@ select_item: { if (Lex->sql_command == SQLCOM_CREATE_VIEW && check_column_name($4.str)) - { - my_error(ER_WRONG_COLUMN_NAME, MYF(0), $4.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), $4.str)); $2->is_autogenerated_name= FALSE; $2->set_name($4.str, $4.length, system_charset_info); } @@ -7734,6 +8455,12 @@ select_item: } ; +remember_tok_start: + { + $$= (char*) YYLIP->get_tok_start(); + } + ; + remember_name: { $$= (char*) YYLIP->get_cpp_tok_start(); @@ -7754,6 +8481,12 @@ select_alias: | TEXT_STRING_sys { $$=$1; } ; +opt_default_time_precision: + /* empty */ { $$= NOT_FIXED_DEC; } + | '(' ')' { $$= NOT_FIXED_DEC; } + | '(' real_ulong_num ')' { $$= $2; }; + ; + opt_time_precision: /* empty */ { $$= 0; } | '(' ')' { $$= 0; } @@ -7797,7 +8530,7 @@ expr: /* (X1 OR X2) OR Y ==> OR (X1, X2, Y) */ - item1->add($3); + item1->add($3, thd->mem_root); $$ = $1; } } @@ -7807,13 +8540,13 @@ expr: /* X OR (Y1 OR Y2) ==> OR (X, Y1, Y2) */ - item3->add_at_head($1); + item3->add_at_head($1, thd->mem_root); $$ = $3; } else { /* X OR Y */ - $$ = new (thd->mem_root) Item_cond_or($1, $3); + $$= new (thd->mem_root) Item_cond_or(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } @@ -7821,7 +8554,7 @@ expr: | expr XOR expr %prec XOR { /* XOR is a proprietary extension */ - $$ = new (thd->mem_root) Item_func_xor($1, $3); + $$= new (thd->mem_root) Item_func_xor(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } @@ -7847,7 +8580,7 @@ expr: /* (X1 AND X2) AND Y ==> AND (X1, X2, Y) */ - item1->add($3); + item1->add($3, thd->mem_root); $$ = $1; } } @@ -7857,13 +8590,13 @@ expr: /* X AND (Y1 AND Y2) ==> AND (X, Y1, Y2) */ - item3->add_at_head($1); + item3->add_at_head($1, thd->mem_root); $$ = $3; } else { /* X AND Y */ - $$ = new (thd->mem_root) Item_cond_and($1, $3); + $$= new (thd->mem_root) Item_cond_and(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } @@ -7876,37 +8609,37 @@ expr: } | bool_pri IS TRUE_SYM %prec IS { - $$= new (thd->mem_root) Item_func_istrue($1); + $$= new (thd->mem_root) Item_func_istrue(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } | bool_pri IS not TRUE_SYM %prec IS { - $$= new (thd->mem_root) Item_func_isnottrue($1); + $$= new (thd->mem_root) Item_func_isnottrue(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } | bool_pri IS FALSE_SYM %prec IS { - $$= new (thd->mem_root) Item_func_isfalse($1); + $$= new (thd->mem_root) Item_func_isfalse(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } | bool_pri IS not FALSE_SYM %prec IS { - $$= new (thd->mem_root) Item_func_isnotfalse($1); + $$= new (thd->mem_root) Item_func_isnotfalse(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } | bool_pri IS UNKNOWN_SYM %prec IS { - $$= new (thd->mem_root) Item_func_isnull($1); + $$= new (thd->mem_root) Item_func_isnull(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } | bool_pri IS not UNKNOWN_SYM %prec IS { - $$= new (thd->mem_root) Item_func_isnotnull($1); + $$= new (thd->mem_root) Item_func_isnotnull(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } @@ -7916,31 +8649,31 @@ expr: bool_pri: bool_pri IS NULL_SYM %prec IS { - $$= new (thd->mem_root) Item_func_isnull($1); + $$= new (thd->mem_root) Item_func_isnull(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } | bool_pri IS not NULL_SYM %prec IS { - $$= new (thd->mem_root) Item_func_isnotnull($1); + $$= new (thd->mem_root) Item_func_isnotnull(thd, $1); if ($$ == NULL) MYSQL_YYABORT; } | bool_pri EQUAL_SYM predicate %prec EQUAL_SYM { - $$= new (thd->mem_root) Item_func_equal($1,$3); + $$= new (thd->mem_root) Item_func_equal(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bool_pri comp_op predicate %prec '=' { - $$= (*$2)(0)->create($1,$3); + $$= (*$2)(0)->create(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bool_pri comp_op all_or_any '(' subselect ')' %prec '=' { - $$= all_any_subquery_creator($1, $2, $3, $5); + $$= all_any_subquery_creator(thd, $1, $2, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } @@ -7950,13 +8683,13 @@ bool_pri: predicate: bit_expr IN_SYM '(' subselect ')' { - $$= new (thd->mem_root) Item_in_subselect($1, $4); + $$= new (thd->mem_root) Item_in_subselect(thd, $1, $4); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr not IN_SYM '(' subselect ')' { - Item *item= new (thd->mem_root) Item_in_subselect($1, $5); + Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $5); if (item == NULL) MYSQL_YYABORT; $$= negate_expression(thd, item); @@ -7971,9 +8704,9 @@ predicate: } | bit_expr IN_SYM '(' expr ',' expr_list ')' { - $6->push_front($4); - $6->push_front($1); - $$= new (thd->mem_root) Item_func_in(*$6); + $6->push_front($4, thd->mem_root); + $6->push_front($1, thd->mem_root); + $$= new (thd->mem_root) Item_func_in(thd, *$6); if ($$ == NULL) MYSQL_YYABORT; } @@ -7985,9 +8718,9 @@ predicate: } | bit_expr not IN_SYM '(' expr ',' expr_list ')' { - $7->push_front($5); - $7->push_front($1); - Item_func_in *item = new (thd->mem_root) Item_func_in(*$7); + $7->push_front($5, thd->mem_root); + $7->push_front($1, thd->mem_root); + Item_func_in *item= new (thd->mem_root) Item_func_in(thd, *$7); if (item == NULL) MYSQL_YYABORT; item->negate(); @@ -7995,14 +8728,14 @@ predicate: } | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate { - $$= new (thd->mem_root) Item_func_between($1,$3,$5); + $$= new (thd->mem_root) Item_func_between(thd, $1, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate { Item_func_between *item; - item= new (thd->mem_root) Item_func_between($1,$4,$6); + item= new (thd->mem_root) Item_func_between(thd, $1, $4, $6); if (item == NULL) MYSQL_YYABORT; item->negate(); @@ -8010,39 +8743,40 @@ predicate: } | bit_expr SOUNDS_SYM LIKE bit_expr { - Item *item1= new (thd->mem_root) Item_func_soundex($1); - Item *item4= new (thd->mem_root) Item_func_soundex($4); + Item *item1= new (thd->mem_root) Item_func_soundex(thd, $1); + Item *item4= new (thd->mem_root) Item_func_soundex(thd, $4); if ((item1 == NULL) || (item4 == NULL)) MYSQL_YYABORT; - $$= new (thd->mem_root) Item_func_eq(item1, item4); + $$= new (thd->mem_root) Item_func_eq(thd, item1, item4); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr LIKE simple_expr opt_escape { - $$= new (thd->mem_root) Item_func_like($1,$3,$4,Lex->escape_used); + $$= new (thd->mem_root) Item_func_like(thd, $1, $3, $4, + Lex->escape_used); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr not LIKE simple_expr opt_escape { - Item *item= new (thd->mem_root) Item_func_like($1,$4,$5, + Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $5, Lex->escape_used); if (item == NULL) MYSQL_YYABORT; - $$= new (thd->mem_root) Item_func_not(item); + $$= new (thd->mem_root) Item_func_not(thd, item); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr REGEXP bit_expr { - $$= new (thd->mem_root) Item_func_regex($1,$3); + $$= new (thd->mem_root) Item_func_regex(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr not REGEXP bit_expr { - Item *item= new (thd->mem_root) Item_func_regex($1,$4); + Item *item= new (thd->mem_root) Item_func_regex(thd, $1, $4); if (item == NULL) MYSQL_YYABORT; $$= negate_expression(thd, item); @@ -8055,85 +8789,85 @@ predicate: bit_expr: bit_expr '|' bit_expr %prec '|' { - $$= new (thd->mem_root) Item_func_bit_or($1,$3); + $$= new (thd->mem_root) Item_func_bit_or(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr '&' bit_expr %prec '&' { - $$= new (thd->mem_root) Item_func_bit_and($1,$3); + $$= new (thd->mem_root) Item_func_bit_and(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr SHIFT_LEFT bit_expr %prec SHIFT_LEFT { - $$= new (thd->mem_root) Item_func_shift_left($1,$3); + $$= new (thd->mem_root) Item_func_shift_left(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr SHIFT_RIGHT bit_expr %prec SHIFT_RIGHT { - $$= new (thd->mem_root) Item_func_shift_right($1,$3); + $$= new (thd->mem_root) Item_func_shift_right(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr '+' bit_expr %prec '+' { - $$= new (thd->mem_root) Item_func_plus($1,$3); + $$= new (thd->mem_root) Item_func_plus(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr '-' bit_expr %prec '-' { - $$= new (thd->mem_root) Item_func_minus($1,$3); + $$= new (thd->mem_root) Item_func_minus(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr '+' INTERVAL_SYM expr interval %prec '+' { - $$= new (thd->mem_root) Item_date_add_interval($1,$4,$5,0); + $$= new (thd->mem_root) Item_date_add_interval(thd, $1, $4, $5, 0); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr '-' INTERVAL_SYM expr interval %prec '-' { - $$= new (thd->mem_root) Item_date_add_interval($1,$4,$5,1); + $$= new (thd->mem_root) Item_date_add_interval(thd, $1, $4, $5, 1); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr '*' bit_expr %prec '*' { - $$= new (thd->mem_root) Item_func_mul($1,$3); + $$= new (thd->mem_root) Item_func_mul(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr '/' bit_expr %prec '/' { - $$= new (thd->mem_root) Item_func_div($1,$3); + $$= new (thd->mem_root) Item_func_div(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr '%' bit_expr %prec '%' { - $$= new (thd->mem_root) Item_func_mod($1,$3); + $$= new (thd->mem_root) Item_func_mod(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr DIV_SYM bit_expr %prec DIV_SYM { - $$= new (thd->mem_root) Item_func_int_div($1,$3); + $$= new (thd->mem_root) Item_func_int_div(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr MOD_SYM bit_expr %prec MOD_SYM { - $$= new (thd->mem_root) Item_func_mod($1,$3); + $$= new (thd->mem_root) Item_func_mod(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } | bit_expr '^' bit_expr { - $$= new (thd->mem_root) Item_func_bit_xor($1,$3); + $$= new (thd->mem_root) Item_func_bit_xor(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } @@ -8226,7 +8960,9 @@ dyncol_type: $$= DYN_COL_DECIMAL; Lex->charset= NULL; } - | char opt_binary + | char + { Lex->charset= thd->variables.collation_connection; } + opt_binary { LEX *lex= Lex; $$= DYN_COL_STRING; @@ -8272,7 +9008,7 @@ dyncall_create_element: alloc_root(thd->mem_root, sizeof(DYNCALL_CREATE_DEF)); if ($$ == NULL) MYSQL_YYABORT; - $$->num= $1; + $$->key= $1; $$->value= $3; $$->type= (DYNAMIC_COLUMN_TYPE)$4; $$->cs= lex->charset; @@ -8292,11 +9028,11 @@ dyncall_create_list: $$= new (thd->mem_root) List<DYNCALL_CREATE_DEF>; if ($$ == NULL) MYSQL_YYABORT; - $$->push_back($1); + $$->push_back($1, thd->mem_root); } | dyncall_create_list ',' dyncall_create_element { - $1->push_back($3); + $1->push_back($3, thd->mem_root); $$= $1; } ; @@ -8309,22 +9045,22 @@ simple_expr: | function_call_conflict | simple_expr COLLATE_SYM ident_or_text %prec NEG { - Item *i1= new (thd->mem_root) Item_string($3.str, + Item *i1= new (thd->mem_root) Item_string(thd, $3.str, $3.length, thd->charset()); if (i1 == NULL) MYSQL_YYABORT; - $$= new (thd->mem_root) Item_func_set_collation($1, i1); + $$= new (thd->mem_root) Item_func_set_collation(thd, $1, i1); if ($$ == NULL) MYSQL_YYABORT; } | literal - | param_marker + | param_marker { $$= $1; } | variable | sum_expr | simple_expr OR_OR_SYM simple_expr { - $$= new (thd->mem_root) Item_func_concat($1, $3); + $$= new (thd->mem_root) Item_func_concat(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; } @@ -8334,13 +9070,13 @@ simple_expr: } | '-' simple_expr %prec NEG { - $$= new (thd->mem_root) Item_func_neg($2); + $$= new (thd->mem_root) Item_func_neg(thd, $2); if ($$ == NULL) MYSQL_YYABORT; } | '~' simple_expr %prec NEG { - $$= new (thd->mem_root) Item_func_bit_neg($2); + $$= new (thd->mem_root) Item_func_bit_neg(thd, $2); if ($$ == NULL) MYSQL_YYABORT; } @@ -8352,7 +9088,7 @@ simple_expr: } | '(' subselect ')' { - $$= new (thd->mem_root) Item_singlerow_subselect($2); + $$= new (thd->mem_root) Item_singlerow_subselect(thd, $2); if ($$ == NULL) MYSQL_YYABORT; } @@ -8360,33 +9096,56 @@ simple_expr: { $$= $2; } | '(' expr ',' expr_list ')' { - $4->push_front($2); - $$= new (thd->mem_root) Item_row(*$4); + $4->push_front($2, thd->mem_root); + $$= new (thd->mem_root) Item_row(thd, *$4); if ($$ == NULL) MYSQL_YYABORT; } | ROW_SYM '(' expr ',' expr_list ')' { - $5->push_front($3); - $$= new (thd->mem_root) Item_row(*$5); + $5->push_front($3, thd->mem_root); + $$= new (thd->mem_root) Item_row(thd, *$5); if ($$ == NULL) MYSQL_YYABORT; } | EXISTS '(' subselect ')' { - $$= new (thd->mem_root) Item_exists_subselect($3); + $$= new (thd->mem_root) Item_exists_subselect(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | '{' ident expr '}' - { $$= $3; } + { + $$= NULL; + /* + If "expr" is reasonably short pure ASCII string literal, + try to parse known ODBC style date, time or timestamp literals, + e.g: + SELECT {d'2001-01-01'}; + SELECT {t'10:20:30'}; + SELECT {ts'2001-01-01 10:20:30'}; + */ + if ($3->type() == Item::STRING_ITEM) + { + Item_string *item= (Item_string *) $3; + enum_field_types type= item->odbc_temporal_literal_type(&$2); + if (type != MYSQL_TYPE_STRING) + { + $$= create_temporal_literal(thd, item->val_str(NULL), + type, false); + } + } + if ($$ == NULL) + $$= $3; + } | MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')' { - $2->push_front($5); - Item_func_match *i1= new (thd->mem_root) Item_func_match(*$2, $6); + $2->push_front($5, thd->mem_root); + Item_func_match *i1= new (thd->mem_root) Item_func_match(thd, *$2, + $6); if (i1 == NULL) MYSQL_YYABORT; - Select->add_ftfunc_to_list(i1); + Select->add_ftfunc_to_list(thd, i1); $$= i1; } | BINARY simple_expr %prec NEG @@ -8406,7 +9165,7 @@ simple_expr: } | CASE_SYM opt_expr when_list opt_else END { - $$= new (thd->mem_root) Item_func_case(* $3, $2, $4 ); + $$= new (thd->mem_root) Item_func_case(thd, *$3, $2, $4); if ($$ == NULL) MYSQL_YYABORT; } @@ -8419,27 +9178,23 @@ simple_expr: } | CONVERT_SYM '(' expr USING charset_name ')' { - $$= new (thd->mem_root) Item_func_conv_charset($3,$5); + $$= new (thd->mem_root) Item_func_conv_charset(thd, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } | DEFAULT '(' simple_ident ')' { - if ($3->is_splocal()) - { - Item_splocal *il= static_cast<Item_splocal *>($3); - - my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str); - MYSQL_YYABORT; - } - $$= new (thd->mem_root) Item_default_value(Lex->current_context(), + Item_splocal *il= $3->get_item_splocal(); + if (il) + my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str)); + $$= new (thd->mem_root) Item_default_value(thd, Lex->current_context(), $3); if ($$ == NULL) MYSQL_YYABORT; } | VALUES '(' simple_ident_nospvar ')' { - $$= new (thd->mem_root) Item_insert_value(Lex->current_context(), + $$= new (thd->mem_root) Item_insert_value(thd, Lex->current_context(), $3); if ($$ == NULL) MYSQL_YYABORT; @@ -8447,7 +9202,7 @@ simple_expr: | INTERVAL_SYM expr interval '+' expr %prec INTERVAL_SYM /* we cannot put interval before - */ { - $$= new (thd->mem_root) Item_date_add_interval($5,$2,$3,0); + $$= new (thd->mem_root) Item_date_add_interval(thd, $5, $2, $3, 0); if ($$ == NULL) MYSQL_YYABORT; } @@ -8462,19 +9217,29 @@ simple_expr: function_call_keyword: CHAR_SYM '(' expr_list ')' { - $$= new (thd->mem_root) Item_func_char(*$3); + $$= new (thd->mem_root) Item_func_char(thd, *$3); if ($$ == NULL) MYSQL_YYABORT; } | CHAR_SYM '(' expr_list USING charset_name ')' { - $$= new (thd->mem_root) Item_func_char(*$3, $5); + $$= new (thd->mem_root) Item_func_char(thd, *$3, $5); if ($$ == NULL) MYSQL_YYABORT; } | CURRENT_USER optional_braces { - $$= new (thd->mem_root) Item_func_current_user(Lex->current_context()); + $$= new (thd->mem_root) Item_func_current_user(thd, + Lex->current_context()); + if ($$ == NULL) + MYSQL_YYABORT; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->safe_to_cache_query= 0; + } + | CURRENT_ROLE optional_braces + { + $$= new (thd->mem_root) Item_func_current_role(thd, + Lex->current_context()); if ($$ == NULL) MYSQL_YYABORT; Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); @@ -8482,25 +9247,25 @@ function_call_keyword: } | DATE_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_date_typecast($3); + $$= new (thd->mem_root) Item_date_typecast(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | DAY_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_dayofmonth($3); + $$= new (thd->mem_root) Item_func_dayofmonth(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | HOUR_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_hour($3); + $$= new (thd->mem_root) Item_func_hour(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | INSERT '(' expr ',' expr ',' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_insert($3,$5,$7,$9); + $$= new (thd->mem_root) Item_func_insert(thd, $3, $5, $7, $9); if ($$ == NULL) MYSQL_YYABORT; } @@ -8509,125 +9274,127 @@ function_call_keyword: List<Item> *list= new (thd->mem_root) List<Item>; if (list == NULL) MYSQL_YYABORT; - list->push_front($5); - list->push_front($3); - Item_row *item= new (thd->mem_root) Item_row(*list); + list->push_front($5, thd->mem_root); + list->push_front($3, thd->mem_root); + Item_row *item= new (thd->mem_root) Item_row(thd, *list); if (item == NULL) MYSQL_YYABORT; - $$= new (thd->mem_root) Item_func_interval(item); + $$= new (thd->mem_root) Item_func_interval(thd, item); if ($$ == NULL) MYSQL_YYABORT; } | INTERVAL_SYM '(' expr ',' expr ',' expr_list ')' %prec INTERVAL_SYM { - $7->push_front($5); - $7->push_front($3); - Item_row *item= new (thd->mem_root) Item_row(*$7); + $7->push_front($5, thd->mem_root); + $7->push_front($3, thd->mem_root); + Item_row *item= new (thd->mem_root) Item_row(thd, *$7); if (item == NULL) MYSQL_YYABORT; - $$= new (thd->mem_root) Item_func_interval(item); + $$= new (thd->mem_root) Item_func_interval(thd, item); if ($$ == NULL) MYSQL_YYABORT; } | LEFT '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_left($3,$5); + $$= new (thd->mem_root) Item_func_left(thd, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } | MINUTE_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_minute($3); + $$= new (thd->mem_root) Item_func_minute(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | MONTH_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_month($3); + $$= new (thd->mem_root) Item_func_month(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | RIGHT '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_right($3,$5); + $$= new (thd->mem_root) Item_func_right(thd, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } | SECOND_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_second($3); + $$= new (thd->mem_root) Item_func_second(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | TIME_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_time_typecast($3, AUTO_SEC_PART_DIGITS); + $$= new (thd->mem_root) Item_time_typecast(thd, $3, + AUTO_SEC_PART_DIGITS); if ($$ == NULL) MYSQL_YYABORT; } | TIMESTAMP '(' expr ')' { - $$= new (thd->mem_root) Item_datetime_typecast($3, AUTO_SEC_PART_DIGITS); + $$= new (thd->mem_root) Item_datetime_typecast(thd, $3, + AUTO_SEC_PART_DIGITS); if ($$ == NULL) MYSQL_YYABORT; } | TIMESTAMP '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_add_time($3, $5, 1, 0); + $$= new (thd->mem_root) Item_func_add_time(thd, $3, $5, 1, 0); if ($$ == NULL) MYSQL_YYABORT; } | TRIM '(' expr ')' { - $$= new (thd->mem_root) Item_func_trim($3); + $$= new (thd->mem_root) Item_func_trim(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | TRIM '(' LEADING expr FROM expr ')' { - $$= new (thd->mem_root) Item_func_ltrim($6,$4); + $$= new (thd->mem_root) Item_func_ltrim(thd, $6, $4); if ($$ == NULL) MYSQL_YYABORT; } | TRIM '(' TRAILING expr FROM expr ')' { - $$= new (thd->mem_root) Item_func_rtrim($6,$4); + $$= new (thd->mem_root) Item_func_rtrim(thd, $6, $4); if ($$ == NULL) MYSQL_YYABORT; } | TRIM '(' BOTH expr FROM expr ')' { - $$= new (thd->mem_root) Item_func_trim($6,$4); + $$= new (thd->mem_root) Item_func_trim(thd, $6, $4); if ($$ == NULL) MYSQL_YYABORT; } | TRIM '(' LEADING FROM expr ')' { - $$= new (thd->mem_root) Item_func_ltrim($5); + $$= new (thd->mem_root) Item_func_ltrim(thd, $5); if ($$ == NULL) MYSQL_YYABORT; } | TRIM '(' TRAILING FROM expr ')' { - $$= new (thd->mem_root) Item_func_rtrim($5); + $$= new (thd->mem_root) Item_func_rtrim(thd, $5); if ($$ == NULL) MYSQL_YYABORT; } | TRIM '(' BOTH FROM expr ')' { - $$= new (thd->mem_root) Item_func_trim($5); + $$= new (thd->mem_root) Item_func_trim(thd, $5); if ($$ == NULL) MYSQL_YYABORT; } | TRIM '(' expr FROM expr ')' { - $$= new (thd->mem_root) Item_func_trim($5,$3); + $$= new (thd->mem_root) Item_func_trim(thd, $5, $3); if ($$ == NULL) MYSQL_YYABORT; } - | USER '(' ')' + | USER_SYM '(' ')' { - $$= new (thd->mem_root) Item_func_user(); + $$= new (thd->mem_root) Item_func_user(thd); if ($$ == NULL) MYSQL_YYABORT; Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); @@ -8635,7 +9402,7 @@ function_call_keyword: } | YEAR_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_year($3); + $$= new (thd->mem_root) Item_func_year(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } @@ -8656,27 +9423,27 @@ function_call_keyword: function_call_nonkeyword: ADDDATE_SYM '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_date_add_interval($3, $5, + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $5, INTERVAL_DAY, 0); if ($$ == NULL) MYSQL_YYABORT; } | ADDDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')' { - $$= new (thd->mem_root) Item_date_add_interval($3, $6, $7, 0); + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 0); if ($$ == NULL) MYSQL_YYABORT; } | CURDATE optional_braces { - $$= new (thd->mem_root) Item_func_curdate_local(); + $$= new (thd->mem_root) Item_func_curdate_local(thd); if ($$ == NULL) MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | CURTIME opt_time_precision { - $$= new (thd->mem_root) Item_func_curtime_local($2); + $$= new (thd->mem_root) Item_func_curtime_local(thd, $2); if ($$ == NULL) MYSQL_YYABORT; Lex->safe_to_cache_query=0; @@ -8684,76 +9451,76 @@ function_call_nonkeyword: | DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' %prec INTERVAL_SYM { - $$= new (thd->mem_root) Item_date_add_interval($3,$6,$7,0); + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 0); if ($$ == NULL) MYSQL_YYABORT; } | DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' %prec INTERVAL_SYM { - $$= new (thd->mem_root) Item_date_add_interval($3,$6,$7,1); + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 1); if ($$ == NULL) MYSQL_YYABORT; } | EXTRACT_SYM '(' interval FROM expr ')' { - $$=new (thd->mem_root) Item_extract( $3, $5); + $$=new (thd->mem_root) Item_extract(thd, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } | GET_FORMAT '(' date_time_type ',' expr ')' { - $$= new (thd->mem_root) Item_func_get_format($3, $5); + $$= new (thd->mem_root) Item_func_get_format(thd, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } | NOW_SYM opt_time_precision { - $$= new (thd->mem_root) Item_func_now_local($2); + $$= new (thd->mem_root) Item_func_now_local(thd, $2); if ($$ == NULL) MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | POSITION_SYM '(' bit_expr IN_SYM expr ')' { - $$ = new (thd->mem_root) Item_func_locate($5,$3); + $$= new (thd->mem_root) Item_func_locate(thd, $5, $3); if ($$ == NULL) MYSQL_YYABORT; } | SUBDATE_SYM '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_date_add_interval($3, $5, + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $5, INTERVAL_DAY, 1); if ($$ == NULL) MYSQL_YYABORT; } | SUBDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')' { - $$= new (thd->mem_root) Item_date_add_interval($3, $6, $7, 1); + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 1); if ($$ == NULL) MYSQL_YYABORT; } | SUBSTRING '(' expr ',' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_substr($3,$5,$7); + $$= new (thd->mem_root) Item_func_substr(thd, $3, $5, $7); if ($$ == NULL) MYSQL_YYABORT; } | SUBSTRING '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_substr($3,$5); + $$= new (thd->mem_root) Item_func_substr(thd, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } | SUBSTRING '(' expr FROM expr FOR_SYM expr ')' { - $$= new (thd->mem_root) Item_func_substr($3,$5,$7); + $$= new (thd->mem_root) Item_func_substr(thd, $3, $5, $7); if ($$ == NULL) MYSQL_YYABORT; } | SUBSTRING '(' expr FROM expr ')' { - $$= new (thd->mem_root) Item_func_substr($3,$5); + $$= new (thd->mem_root) Item_func_substr(thd, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } @@ -8768,42 +9535,42 @@ function_call_nonkeyword: */ Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); if (global_system_variables.sysdate_is_now == 0) - $$= new (thd->mem_root) Item_func_sysdate_local($2); + $$= new (thd->mem_root) Item_func_sysdate_local(thd, $2); else - $$= new (thd->mem_root) Item_func_now_local($2); + $$= new (thd->mem_root) Item_func_now_local(thd, $2); if ($$ == NULL) MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | TIMESTAMP_ADD '(' interval_time_stamp ',' expr ',' expr ')' { - $$= new (thd->mem_root) Item_date_add_interval($7,$5,$3,0); + $$= new (thd->mem_root) Item_date_add_interval(thd, $7, $5, $3, 0); if ($$ == NULL) MYSQL_YYABORT; } | TIMESTAMP_DIFF '(' interval_time_stamp ',' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_timestamp_diff($5,$7,$3); + $$= new (thd->mem_root) Item_func_timestamp_diff(thd, $5, $7, $3); if ($$ == NULL) MYSQL_YYABORT; } | UTC_DATE_SYM optional_braces { - $$= new (thd->mem_root) Item_func_curdate_utc(); + $$= new (thd->mem_root) Item_func_curdate_utc(thd); if ($$ == NULL) MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | UTC_TIME_SYM opt_time_precision { - $$= new (thd->mem_root) Item_func_curtime_utc($2); + $$= new (thd->mem_root) Item_func_curtime_utc(thd, $2); if ($$ == NULL) MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | UTC_TIMESTAMP_SYM opt_time_precision { - $$= new (thd->mem_root) Item_func_now_utc($2); + $$= new (thd->mem_root) Item_func_now_utc(thd, $2); if ($$ == NULL) MYSQL_YYABORT; Lex->safe_to_cache_query=0; @@ -8823,16 +9590,9 @@ function_call_nonkeyword: MYSQL_YYABORT; } | - COLUMN_EXISTS_SYM '(' expr ',' expr ')' - { - $$= new (thd->mem_root) Item_func_dyncol_exists($3, $5); - if ($$ == NULL) - MYSQL_YYABORT; - } - | - COLUMN_LIST_SYM '(' expr ')' + COLUMN_CHECK_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_dyncol_list($3); + $$= new (thd->mem_root) Item_func_dyncol_check(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } @@ -8863,114 +9623,174 @@ function_call_nonkeyword: function_call_conflict: ASCII_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_ascii($3); + $$= new (thd->mem_root) Item_func_ascii(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | CHARSET '(' expr ')' { - $$= new (thd->mem_root) Item_func_charset($3); + $$= new (thd->mem_root) Item_func_charset(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | COALESCE '(' expr_list ')' { - $$= new (thd->mem_root) Item_func_coalesce(* $3); + $$= new (thd->mem_root) Item_func_coalesce(thd, *$3); if ($$ == NULL) MYSQL_YYABORT; } | COLLATION_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_collation($3); + $$= new (thd->mem_root) Item_func_collation(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | DATABASE '(' ')' { - $$= new (thd->mem_root) Item_func_database(); + $$= new (thd->mem_root) Item_func_database(thd); if ($$ == NULL) MYSQL_YYABORT; Lex->safe_to_cache_query=0; } - | IF '(' expr ',' expr ',' expr ')' + | IF_SYM '(' expr ',' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_if($3,$5,$7); + $$= new (thd->mem_root) Item_func_if(thd, $3, $5, $7); + if ($$ == NULL) + MYSQL_YYABORT; + } + | FORMAT_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_format(thd, $3, $5); + if ($$ == NULL) + MYSQL_YYABORT; + } + | FORMAT_SYM '(' expr ',' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_format(thd, $3, $5, $7); if ($$ == NULL) MYSQL_YYABORT; } | LAST_VALUE '(' expr_list ')' { - $$= new (thd->mem_root) Item_func_last_value(* $3); + $$= new (thd->mem_root) Item_func_last_value(thd, *$3); if ($$ == NULL) MYSQL_YYABORT; } | MICROSECOND_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_microsecond($3); + $$= new (thd->mem_root) Item_func_microsecond(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | MOD_SYM '(' expr ',' expr ')' { - $$ = new (thd->mem_root) Item_func_mod($3, $5); + $$= new (thd->mem_root) Item_func_mod(thd, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } - | OLD_PASSWORD '(' expr ')' + | OLD_PASSWORD_SYM '(' expr ')' { - $$= new (thd->mem_root) Item_func_old_password($3); + $$= new (thd->mem_root) + Item_func_password(thd, $3, Item_func_password::OLD); if ($$ == NULL) MYSQL_YYABORT; } - | PASSWORD '(' expr ')' + | PASSWORD_SYM '(' expr ')' { Item* i1; - if (thd->variables.old_passwords) - i1= new (thd->mem_root) Item_func_old_password($3); - else - i1= new (thd->mem_root) Item_func_password($3); + i1= new (thd->mem_root) Item_func_password(thd, $3); if (i1 == NULL) MYSQL_YYABORT; $$= i1; } | QUARTER_SYM '(' expr ')' { - $$ = new (thd->mem_root) Item_func_quarter($3); + $$= new (thd->mem_root) Item_func_quarter(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | REPEAT_SYM '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_repeat($3,$5); + $$= new (thd->mem_root) Item_func_repeat(thd, $3, $5); if ($$ == NULL) MYSQL_YYABORT; } | REPLACE '(' expr ',' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_replace($3,$5,$7); + $$= new (thd->mem_root) Item_func_replace(thd, $3, $5, $7); + if ($$ == NULL) + MYSQL_YYABORT; + } + | REVERSE_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_reverse(thd, $3); + if ($$ == NULL) + MYSQL_YYABORT; + } + | ROW_COUNT_SYM '(' ')' + { + $$= new (thd->mem_root) Item_func_row_count(thd); if ($$ == NULL) MYSQL_YYABORT; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->safe_to_cache_query= 0; } | TRUNCATE_SYM '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_round($3,$5,1); + $$= new (thd->mem_root) Item_func_round(thd, $3, $5, 1); if ($$ == NULL) MYSQL_YYABORT; } | WEEK_SYM '(' expr ')' { - Item *i1= new (thd->mem_root) Item_int((char*) "0", - thd->variables.default_week_format, - 1); - if (i1 == NULL) + Item *i1; + LEX_STRING name= {C_STRING_WITH_LEN("default_week_format")}; + if (!(i1= get_system_var(thd, OPT_SESSION, + name, null_lex_str))) MYSQL_YYABORT; - $$= new (thd->mem_root) Item_func_week($3, i1); + i1->set_name((const char *) + STRING_WITH_LEN("@@default_week_format"), + system_charset_info); + $$= new (thd->mem_root) Item_func_week(thd, $3, i1); if ($$ == NULL) MYSQL_YYABORT; } | WEEK_SYM '(' expr ',' expr ')' { - $$= new (thd->mem_root) Item_func_week($3,$5); + $$= new (thd->mem_root) Item_func_week(thd, $3, $5); + if ($$ == NULL) + MYSQL_YYABORT; + } + | WEIGHT_STRING_SYM '(' expr opt_ws_levels ')' + { + $$= new (thd->mem_root) Item_func_weight_string(thd, $3, 0, 0, $4); + if ($$ == NULL) + MYSQL_YYABORT; + } + | WEIGHT_STRING_SYM '(' expr AS CHAR_SYM ws_nweights opt_ws_levels ')' + { + $$= new (thd->mem_root) + Item_func_weight_string(thd, $3, 0, $6, + $7 | MY_STRXFRM_PAD_WITH_SPACE); + if ($$ == NULL) + MYSQL_YYABORT; + } + | WEIGHT_STRING_SYM '(' expr AS BINARY ws_nweights ')' + { + Item *item= new (thd->mem_root) Item_char_typecast(thd, $3, $6, + &my_charset_bin); + if (item == NULL) + MYSQL_YYABORT; + $$= new (thd->mem_root) + Item_func_weight_string(thd, item, 0, $6, + MY_STRXFRM_PAD_WITH_SPACE); + if ($$ == NULL) + MYSQL_YYABORT; + } + | WEIGHT_STRING_SYM '(' expr ',' ulong_num ',' ulong_num ',' ulong_num ')' + { + $$= new (thd->mem_root) Item_func_weight_string(thd, $3, $5, $7, + $9); if ($$ == NULL) MYSQL_YYABORT; } @@ -8982,9 +9802,8 @@ function_call_conflict: if ($$ == NULL) MYSQL_YYABORT; #else - my_error(ER_FEATURE_DISABLED, MYF(0), - sym_group_geom.name, sym_group_geom.needed_define); - MYSQL_YYABORT; + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, + sym_group_geom.needed_define)); #endif } ; @@ -8993,52 +9812,52 @@ geometry_function: CONTAINS_SYM '(' expr ',' expr ')' { $$= GEOM_NEW(thd, - Item_func_spatial_rel($3, $5, - Item_func::SP_CONTAINS_FUNC)); + Item_func_spatial_precise_rel(thd, $3, $5, + Item_func::SP_CONTAINS_FUNC)); } | GEOMETRYCOLLECTION '(' expr_list ')' { $$= GEOM_NEW(thd, - Item_func_spatial_collection(* $3, + Item_func_spatial_collection(thd, *$3, Geometry::wkb_geometrycollection, Geometry::wkb_point)); } | LINESTRING '(' expr_list ')' { $$= GEOM_NEW(thd, - Item_func_spatial_collection(* $3, + Item_func_spatial_collection(thd, *$3, Geometry::wkb_linestring, Geometry::wkb_point)); } | MULTILINESTRING '(' expr_list ')' { $$= GEOM_NEW(thd, - Item_func_spatial_collection(* $3, + Item_func_spatial_collection(thd, *$3, Geometry::wkb_multilinestring, Geometry::wkb_linestring)); } | MULTIPOINT '(' expr_list ')' { $$= GEOM_NEW(thd, - Item_func_spatial_collection(* $3, + Item_func_spatial_collection(thd, *$3, Geometry::wkb_multipoint, Geometry::wkb_point)); } | MULTIPOLYGON '(' expr_list ')' { $$= GEOM_NEW(thd, - Item_func_spatial_collection(* $3, + Item_func_spatial_collection(thd, *$3, Geometry::wkb_multipolygon, Geometry::wkb_polygon)); } | POINT_SYM '(' expr ',' expr ')' { - $$= GEOM_NEW(thd, Item_func_point($3,$5)); + $$= GEOM_NEW(thd, Item_func_point(thd, $3, $5)); } | POLYGON '(' expr_list ')' { $$= GEOM_NEW(thd, - Item_func_spatial_collection(* $3, + Item_func_spatial_collection(thd, *$3, Geometry::wkb_polygon, Geometry::wkb_linestring)); } @@ -9065,7 +9884,7 @@ function_call_generic: { if (lex->current_select->inc_in_sum_expr()) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } } @@ -9146,10 +9965,7 @@ function_call_generic: */ if (!$1.str || check_db_name(&$1)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $1.str)); if (check_routine_name(&$3)) { MYSQL_YYABORT; @@ -9194,11 +10010,11 @@ udf_expr_list: $$= new (thd->mem_root) List<Item>; if ($$ == NULL) MYSQL_YYABORT; - $$->push_back($1); + $$->push_back($1, thd->mem_root); } | udf_expr_list ',' udf_expr { - $1->push_back($3); + $1->push_back($3, thd->mem_root); $$= $1; } ; @@ -9233,46 +10049,46 @@ udf_expr: sum_expr: AVG_SYM '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_avg($3, FALSE); + $$= new (thd->mem_root) Item_sum_avg(thd, $3, FALSE); if ($$ == NULL) MYSQL_YYABORT; } | AVG_SYM '(' DISTINCT in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_avg($4, TRUE); + $$= new (thd->mem_root) Item_sum_avg(thd, $4, TRUE); if ($$ == NULL) MYSQL_YYABORT; } | BIT_AND '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_and($3); + $$= new (thd->mem_root) Item_sum_and(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | BIT_OR '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_or($3); + $$= new (thd->mem_root) Item_sum_or(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | BIT_XOR '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_xor($3); + $$= new (thd->mem_root) Item_sum_xor(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | COUNT_SYM '(' opt_all '*' ')' { - Item *item= new (thd->mem_root) Item_int((int32) 0L,1); + Item *item= new (thd->mem_root) Item_int(thd, (int32) 0L, 1); if (item == NULL) MYSQL_YYABORT; - $$= new (thd->mem_root) Item_sum_count(item); + $$= new (thd->mem_root) Item_sum_count(thd, item); if ($$ == NULL) MYSQL_YYABORT; } | COUNT_SYM '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_count($3); + $$= new (thd->mem_root) Item_sum_count(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } @@ -9282,13 +10098,13 @@ sum_expr: { Select->in_sum_expr--; } ')' { - $$= new (thd->mem_root) Item_sum_count(* $5); + $$= new (thd->mem_root) Item_sum_count(thd, *$5); if ($$ == NULL) MYSQL_YYABORT; } | MIN_SYM '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_min($3); + $$= new (thd->mem_root) Item_sum_min(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } @@ -9299,55 +10115,55 @@ sum_expr: */ | MIN_SYM '(' DISTINCT in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_min($4); + $$= new (thd->mem_root) Item_sum_min(thd, $4); if ($$ == NULL) MYSQL_YYABORT; } | MAX_SYM '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_max($3); + $$= new (thd->mem_root) Item_sum_max(thd, $3); if ($$ == NULL) MYSQL_YYABORT; } | MAX_SYM '(' DISTINCT in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_max($4); + $$= new (thd->mem_root) Item_sum_max(thd, $4); if ($$ == NULL) MYSQL_YYABORT; } | STD_SYM '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_std($3, 0); + $$= new (thd->mem_root) Item_sum_std(thd, $3, 0); if ($$ == NULL) MYSQL_YYABORT; } | VARIANCE_SYM '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_variance($3, 0); + $$= new (thd->mem_root) Item_sum_variance(thd, $3, 0); if ($$ == NULL) MYSQL_YYABORT; } | STDDEV_SAMP_SYM '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_std($3, 1); + $$= new (thd->mem_root) Item_sum_std(thd, $3, 1); if ($$ == NULL) MYSQL_YYABORT; } | VAR_SAMP_SYM '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_variance($3, 1); + $$= new (thd->mem_root) Item_sum_variance(thd, $3, 1); if ($$ == NULL) MYSQL_YYABORT; } | SUM_SYM '(' in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_sum($3, FALSE); + $$= new (thd->mem_root) Item_sum_sum(thd, $3, FALSE); if ($$ == NULL) MYSQL_YYABORT; } | SUM_SYM '(' DISTINCT in_sum_expr ')' { - $$= new (thd->mem_root) Item_sum_sum($4, TRUE); + $$= new (thd->mem_root) Item_sum_sum(thd, $4, TRUE); if ($$ == NULL) MYSQL_YYABORT; } @@ -9360,7 +10176,7 @@ sum_expr: SELECT_LEX *sel= Select; sel->in_sum_expr--; $$= new (thd->mem_root) - Item_func_group_concat(Lex->current_context(), $3, $5, + Item_func_group_concat(thd, Lex->current_context(), $3, $5, sel->gorder_list, $7); if ($$ == NULL) MYSQL_YYABORT; @@ -9373,10 +10189,7 @@ variable: '@' { if (! Lex->parsing_options.allows_variable) - { - my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); } variable_aux { @@ -9388,16 +10201,16 @@ variable_aux: ident_or_text SET_VAR expr { Item_func_set_user_var *item; - $$= item= new (thd->mem_root) Item_func_set_user_var($1, $3); + $$= item= new (thd->mem_root) Item_func_set_user_var(thd, $1, $3); if ($$ == NULL) MYSQL_YYABORT; LEX *lex= Lex; lex->uncacheable(UNCACHEABLE_SIDEEFFECT); - lex->set_var_list.push_back(item); + lex->set_var_list.push_back(item, thd->mem_root); } | ident_or_text { - $$= new (thd->mem_root) Item_func_get_user_var($1); + $$= new (thd->mem_root) Item_func_get_user_var(thd, $1); if ($$ == NULL) MYSQL_YYABORT; LEX *lex= Lex; @@ -9408,7 +10221,7 @@ variable_aux: /* disallow "SELECT @@global.global.variable" */ if ($3.str && $4.str && check_reserved_words(&$3)) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } if (!($$= get_system_var(thd, $2, $3, $4))) @@ -9443,9 +10256,8 @@ opt_gorder_clause: sel->olap != UNSPECIFIED_OLAP_TYPE && (sel->linkage != UNION_TYPE || sel->braces)) { - my_error(ER_WRONG_USAGE, MYF(0), - "CUBE/ROLLUP", "ORDER BY"); - MYSQL_YYABORT; + my_yyabort_error((ER_WRONG_USAGE, MYF(0), + "CUBE/ROLLUP", "ORDER BY")); } } gorder_list; @@ -9464,7 +10276,7 @@ in_sum_expr: LEX *lex= Lex; if (lex->current_select->inc_in_sum_expr()) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } } @@ -9478,7 +10290,9 @@ in_sum_expr: cast_type: BINARY opt_field_length { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; } - | CHAR_SYM opt_field_length opt_binary + | CHAR_SYM opt_field_length + { Lex->charset= thd->variables.collation_connection; } + opt_binary { $$=ITEM_CAST_CHAR; Lex->dec= 0; } | NCHAR_SYM opt_field_length { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; } @@ -9524,11 +10338,11 @@ expr_list: $$= new (thd->mem_root) List<Item>; if ($$ == NULL) MYSQL_YYABORT; - $$->push_back($1); + $$->push_back($1, thd->mem_root); } | expr_list ',' expr { - $1->push_back($3); + $1->push_back($3, thd->mem_root); $$= $1; } ; @@ -9544,11 +10358,11 @@ ident_list: $$= new (thd->mem_root) List<Item>; if ($$ == NULL) MYSQL_YYABORT; - $$->push_back($1); + $$->push_back($1, thd->mem_root); } | ident_list ',' simple_ident { - $1->push_back($3); + $1->push_back($3, thd->mem_root); $$= $1; } ; @@ -9566,16 +10380,16 @@ opt_else: when_list: WHEN_SYM expr THEN_SYM expr { - $$= new List<Item>; + $$= new (thd->mem_root) List<Item>; if ($$ == NULL) MYSQL_YYABORT; - $$->push_back($2); - $$->push_back($4); + $$->push_back($2, thd->mem_root); + $$->push_back($4, thd->mem_root); } | when_list WHEN_SYM expr THEN_SYM expr { - $1->push_back($3); - $1->push_back($5); + $1->push_back($3, thd->mem_root); + $1->push_back($5, thd->mem_root); $$= $1; } ; @@ -9587,9 +10401,9 @@ table_ref: | join_table { LEX *lex= Lex; - if (!($$= lex->current_select->nest_last_join(lex->thd))) + if (!($$= lex->current_select->nest_last_join(thd))) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } } @@ -9636,9 +10450,7 @@ join_table: left-associative joins. */ table_ref normal_join table_ref %prec TABLE_REF_PRIORITY - { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); } - | table_ref STRAIGHT_JOIN table_factor - { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=1; } + { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=$2; } | table_ref normal_join table_ref ON { @@ -9650,23 +10462,8 @@ join_table: } expr { - add_join_on($3,$6); - Lex->pop_context(); - Select->parsing_place= NO_MATTER; - } - | table_ref STRAIGHT_JOIN table_factor - ON - { - MYSQL_YYABORT_UNLESS($1 && $3); - /* Change the current name resolution context to a local context. */ - if (push_new_name_resolution_context(thd, $1, $3)) - MYSQL_YYABORT; - Select->parsing_place= IN_ON; - } - expr - { - $3->straight=1; - add_join_on($3,$6); + $3->straight=$2; + add_join_on(thd, $3, $6); Lex->pop_context(); Select->parsing_place= NO_MATTER; } @@ -9676,10 +10473,15 @@ join_table: MYSQL_YYABORT_UNLESS($1 && $3); } '(' using_list ')' - { add_join_natural($1,$3,$7,Select); $$=$3; } - | table_ref NATURAL JOIN_SYM table_factor + { + $3->straight=$2; + add_join_natural($1,$3,$7,Select); + $$=$3; + } + | table_ref NATURAL inner_join table_factor { MYSQL_YYABORT_UNLESS($1 && ($$=$4)); + $4->straight=$3; add_join_natural($1,$4,NULL,Select); } @@ -9695,7 +10497,7 @@ join_table: } expr { - add_join_on($5,$8); + add_join_on(thd, $5, $8); Lex->pop_context(); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; @@ -9734,7 +10536,7 @@ join_table: LEX *lex= Lex; if (!($$= lex->current_select->convert_right_join())) MYSQL_YYABORT; - add_join_on($$, $8); + add_join_on(thd, $$, $8); Lex->pop_context(); Select->parsing_place= NO_MATTER; } @@ -9759,12 +10561,34 @@ join_table: } ; + +inner_join: /* $$ set if using STRAIGHT_JOIN, false otherwise */ + JOIN_SYM { $$ = 0; } + | INNER_SYM JOIN_SYM { $$ = 0; } + | STRAIGHT_JOIN { $$ = 1; } + ; + normal_join: - JOIN_SYM {} - | INNER_SYM JOIN_SYM {} - | CROSS JOIN_SYM {} + inner_join { $$ = $1; } + | CROSS JOIN_SYM { $$ = 0; } ; +/* + table PARTITION (list of partitions), reusing using_list instead of creating + a new rule for partition_list. +*/ +opt_use_partition: + /* empty */ { $$= 0;} + | use_partition + ; + +use_partition: + PARTITION_SYM '(' using_list ')' have_partitioning + { + $$= $3; + } + ; + /* This is a flattening of the rules <table factor> and <table primary> in the SQL:2003 standard, since we don't have <sample clause> @@ -9778,13 +10602,14 @@ table_factor: SELECT_LEX *sel= Select; sel->table_join_options= 0; } - table_ident opt_table_alias opt_key_definition + table_ident opt_use_partition opt_table_alias opt_key_definition { - if (!($$= Select->add_table_to_list(thd, $2, $3, + if (!($$= Select->add_table_to_list(thd, $2, $4, Select->get_table_join_options(), YYPS->m_lock_type, YYPS->m_mdl_type, - Select->pop_index_hints()))) + Select->pop_index_hints(), + $3))) MYSQL_YYABORT; Select->add_joined_table($$); } @@ -9796,15 +10621,11 @@ table_factor: { if (sel->set_braces(1)) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } - /* select in braces, can't contain global parameters */ - if (sel->master_unit()->fake_select_lex) - sel->master_unit()->global_parameters= - sel->master_unit()->fake_select_lex; } - if ($2->init_nested_join(lex->thd)) + if ($2->init_nested_join(thd)) MYSQL_YYABORT; $$= 0; /* incomplete derived tables return NULL, we must be @@ -9850,11 +10671,11 @@ table_factor: SELECT_LEX *sel= lex->current_select; SELECT_LEX_UNIT *unit= sel->master_unit(); lex->current_select= sel= unit->outer_select(); - Table_ident *ti= new Table_ident(unit); + Table_ident *ti= new (thd->mem_root) Table_ident(unit); if (ti == NULL) MYSQL_YYABORT; - if (!($$= sel->add_table_to_list(lex->thd, - new Table_ident(unit), $5, 0, + if (!($$= sel->add_table_to_list(thd, + ti, $5, 0, TL_READ, MDL_SHARED_READ))) MYSQL_YYABORT; @@ -9872,7 +10693,7 @@ table_factor: Tables with or without joins within parentheses cannot have aliases, and we ruled out derived tables above. */ - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } else @@ -9917,7 +10738,7 @@ select_derived_union: { if ($1 && $2) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } } @@ -9935,12 +10756,10 @@ select_derived_union: last select in the union. */ Lex->pop_context(); - } - opt_union_order_or_limit - { + if ($1 != NULL) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } } @@ -9951,16 +10770,9 @@ select_init2_derived: select_part2_derived { LEX *lex= Lex; - SELECT_LEX * sel= lex->current_select; if (lex->current_select->set_braces(0)) { - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; - } - if (sel->linkage == UNION_TYPE && - sel->master_unit()->first_select()->braces) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } } @@ -9979,28 +10791,25 @@ select_part2_derived: { Select->parsing_place= NO_MATTER; } - opt_select_from select_lock_type ; /* handle contents of parentheses in join expression */ select_derived: get_select_lex { - LEX *lex= Lex; - if ($1->init_nested_join(lex->thd)) + if ($1->init_nested_join(thd)) MYSQL_YYABORT; } derived_table_list { - LEX *lex= Lex; /* for normal joins, $3 != NULL and end_nested_join() != NULL, for derived tables, both must equal NULL */ - if (!($$= $1->end_nested_join(lex->thd)) && $3) + if (!($$= $1->end_nested_join(thd)) && $3) MYSQL_YYABORT; if (!$3 && $$) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } } @@ -10013,7 +10822,7 @@ select_derived2: if (!lex->expr_allows_subselect || lex->sql_command == (int)SQLCOM_PURGE) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE || @@ -10027,7 +10836,7 @@ select_derived2: { Select->parsing_place= NO_MATTER; } - opt_select_from + table_expression ; get_select_lex: @@ -10040,17 +10849,14 @@ select_derived_init: LEX *lex= Lex; if (! lex->parsing_options.allows_derived) - { - my_error(ER_VIEW_SELECT_DERIVED, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_DERIVED, MYF(0))); SELECT_LEX *sel= lex->current_select; TABLE_LIST *embedding; - if (!sel->embedding || sel->end_nested_join(lex->thd)) + if (!sel->embedding || sel->end_nested_join(thd)) { /* we are not in parentheses */ - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } embedding= Select->embedding; @@ -10128,14 +10934,14 @@ key_usage_list: using_list: ident { - if (!($$= new List<String>)) + if (!($$= new (thd->mem_root) List<String>)) MYSQL_YYABORT; String *s= new (thd->mem_root) String((const char *) $1.str, $1.length, system_charset_info); if (s == NULL) MYSQL_YYABORT; - $$->push_back(s); + $$->push_back(s, thd->mem_root); } | using_list ',' ident { @@ -10144,7 +10950,7 @@ using_list: system_charset_info); if (s == NULL) MYSQL_YYABORT; - $1->push_back(s); + $1->push_back(s, thd->mem_root); $$= $1; } ; @@ -10193,7 +10999,7 @@ opt_table_alias: /* empty */ { $$=0; } | table_alias ident { - $$= (LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING)); + $$= (LEX_STRING*) thd->memdup(&$2,sizeof(LEX_STRING)); if ($$ == NULL) MYSQL_YYABORT; } @@ -10204,7 +11010,7 @@ opt_all: | ALL ; -where_clause: +opt_where_clause: /* empty */ { Select->where= 0; } | WHERE { @@ -10213,14 +11019,14 @@ where_clause: expr { SELECT_LEX *select= Select; - select->where= normalize_cond($3); + select->where= normalize_cond(thd, $3); select->parsing_place= NO_MATTER; if ($3) $3->top_level_item(); } ; -having_clause: +opt_having_clause: /* empty */ | HAVING { @@ -10229,7 +11035,7 @@ having_clause: expr { SELECT_LEX *sel= Select; - sel->having= normalize_cond($3); + sel->having= normalize_cond(thd, $3); sel->parsing_place= NO_MATTER; if ($3) $3->top_level_item(); @@ -10246,8 +11052,8 @@ opt_escape: { Lex->escape_used= FALSE; $$= ((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ? - new (thd->mem_root) Item_string("", 0, &my_charset_latin1) : - new (thd->mem_root) Item_string("\\", 1, &my_charset_latin1)); + new (thd->mem_root) Item_string_ascii(thd, "", 0) : + new (thd->mem_root) Item_string_ascii(thd, "\\", 1)); if ($$ == NULL) MYSQL_YYABORT; } @@ -10257,7 +11063,7 @@ opt_escape: group by statement in select */ -group_clause: +opt_group_clause: /* empty */ | GROUP_SYM BY group_list olap_opt ; @@ -10282,14 +11088,11 @@ olap_opt: */ LEX *lex=Lex; if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) - { - my_error(ER_WRONG_USAGE, MYF(0), "WITH CUBE", - "global union parameters"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH CUBE", + "global union parameters")); lex->current_select->olap= CUBE_TYPE; - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "CUBE"); - MYSQL_YYABORT; + + my_yyabort_error((ER_NOT_SUPPORTED_YET, MYF(0), "CUBE")); } | WITH_ROLLUP_SYM { @@ -10302,11 +11105,8 @@ olap_opt: */ LEX *lex= Lex; if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) - { - my_error(ER_WRONG_USAGE, MYF(0), "WITH ROLLUP", - "global union parameters"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH ROLLUP", + "global union parameters")); lex->current_select->olap= ROLLUP_TYPE; } ; @@ -10356,7 +11156,8 @@ order_clause: "CUBE/ROLLUP", "ORDER BY"); MYSQL_YYABORT; } - if (lex->sql_command != SQLCOM_ALTER_TABLE && !unit->fake_select_lex) + if (lex->sql_command != SQLCOM_ALTER_TABLE && + !unit->fake_select_lex) { /* A query of the of the form (SELECT ...) ORDER BY order_list is @@ -10370,12 +11171,26 @@ order_clause: if (!unit->is_union() && (first_sl->order_list.elements || first_sl->select_limit) && - unit->add_fake_select_lex(lex->thd)) + unit->add_fake_select_lex(thd)) MYSQL_YYABORT; } + if (sel->master_unit()->is_union() && !sel->braces) + { + /* + At this point we don't know yet whether this is the last + select in union or not, but we move ORDER BY to + fake_select_lex anyway. If there would be one more select + in union mysql_new_select will correctly throw error. + */ + DBUG_ASSERT(sel->master_unit()->fake_select_lex); + lex->current_select= sel->master_unit()->fake_select_lex; + } } order_list - ; + { + + } + ; order_list: order_list ',' order_ident order_dir @@ -10390,33 +11205,38 @@ order_dir: | DESC { $$ =0; } ; -opt_limit_clause_init: - /* empty */ - { - LEX *lex= Lex; - SELECT_LEX *sel= lex->current_select; - sel->offset_limit= 0; - sel->select_limit= 0; - lex->limit_rows_examined= 0; - } - | limit_clause {} - ; - opt_limit_clause: /* empty */ {} | limit_clause {} ; +limit_clause_init: + LIMIT + { + SELECT_LEX *sel= Select; + if (sel->master_unit()->is_union() && !sel->braces) + { + /* Move LIMIT that belongs to UNION to fake_select_lex */ + Lex->current_select= sel->master_unit()->fake_select_lex; + DBUG_ASSERT(Select); + } + } + ; + limit_clause: - LIMIT limit_options + limit_clause_init limit_options { - Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + SELECT_LEX *sel= Select; + if (!sel->select_limit->basic_const_item() || + sel->select_limit->val_int() > 0) + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } - | LIMIT limit_options ROWS_SYM EXAMINED_SYM limit_rows_option + | limit_clause_init limit_options + ROWS_SYM EXAMINED_SYM limit_rows_option { Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } - | LIMIT ROWS_SYM EXAMINED_SYM limit_rows_option + | limit_clause_init ROWS_SYM EXAMINED_SYM limit_rows_option { Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } @@ -10452,12 +11272,12 @@ limit_option: Item_splocal *splocal; LEX *lex= thd->lex; Lex_input_stream *lip= & thd->m_parser_state->m_lip; - sp_variable_t *spv; + sp_variable *spv; sp_pcontext *spc = lex->spcont; - if (spc && (spv = spc->find_variable(&$1))) + if (spc && (spv = spc->find_variable($1, false))) { splocal= new (thd->mem_root) - Item_splocal($1, spv->offset, spv->type, + Item_splocal(thd, $1, spv->offset, spv->type, lip->get_tok_start() - lex->sphead->m_tmp_query, lip->get_ptr() - lip->get_tok_start()); if (splocal == NULL) @@ -10468,37 +11288,31 @@ limit_option: lex->safe_to_cache_query=0; } else - { - my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); if (splocal->type() != Item::INT_ITEM) - { - my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0))); splocal->limit_clause_param= TRUE; $$= splocal; } | param_marker { - ((Item_param *) $1)->limit_clause_param= TRUE; + $1->limit_clause_param= TRUE; } | ULONGLONG_NUM { - $$= new (thd->mem_root) Item_uint($1.str, $1.length); + $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length); if ($$ == NULL) MYSQL_YYABORT; } | LONG_NUM { - $$= new (thd->mem_root) Item_uint($1.str, $1.length); + $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length); if ($$ == NULL) MYSQL_YYABORT; } | NUM { - $$= new (thd->mem_root) Item_uint($1.str, $1.length); + $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length); if ($$ == NULL) MYSQL_YYABORT; } @@ -10524,8 +11338,8 @@ delete_limit_clause: Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); sel->explicit_limit= 1; } - | LIMIT ROWS_SYM EXAMINED_SYM { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } - | LIMIT limit_option ROWS_SYM EXAMINED_SYM { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } + | LIMIT ROWS_SYM EXAMINED_SYM { my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } + | LIMIT limit_option ROWS_SYM EXAMINED_SYM { my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } ; int_num: @@ -10569,7 +11383,7 @@ real_ulonglong_num: dec_num_error: dec_num - { my_parse_error(ER(ER_ONLY_INTEGERS_ALLOWED)); } + { my_parse_error(thd, ER_ONLY_INTEGERS_ALLOWED); } ; dec_num: @@ -10582,32 +11396,26 @@ choice: | DEFAULT { $$= HA_CHOICE_UNDEF; } ; -procedure_clause: - /* empty */ +opt_procedure_clause: + /* empty */ { $$= false; } | PROCEDURE_SYM ident /* Procedure name */ { LEX *lex=Lex; if (! lex->parsing_options.allows_select_procedure) - { - my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "PROCEDURE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_CLAUSE, MYF(0), "PROCEDURE")); if (&lex->select_lex != lex->current_select) - { - my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery")); lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= &lex->proc_list.first; Item_field *item= new (thd->mem_root) - Item_field(&lex->current_select->context, + Item_field(thd, &lex->current_select->context, NULL, NULL, $2.str); if (item == NULL) MYSQL_YYABORT; - if (add_proc_to_list(lex->thd, item)) + if (add_proc_to_list(thd, item)) MYSQL_YYABORT; Lex->uncacheable(UNCACHEABLE_SIDEEFFECT); @@ -10623,6 +11431,7 @@ procedure_clause: { /* Subqueries are allowed from now.*/ Lex->expr_allows_subselect= true; + $$= true; } ; @@ -10649,7 +11458,8 @@ procedure_item: select_var_list_init: { LEX *lex=Lex; - if (!lex->describe && (!(lex->result= new select_dumpvar()))) + if (!lex->describe && + (!(lex->result= new (thd->mem_root) select_dumpvar(thd)))) MYSQL_YYABORT; } select_var_list @@ -10661,16 +11471,13 @@ select_var_list: | select_var_ident {} ; -select_var_ident: - '@' ident_or_text +select_var_ident: select_outvar { - LEX *lex=Lex; - if (lex->result) + if (Lex->result) { - my_var *var= new my_var($2,0,0,(enum_field_types)0); - if (var == NULL) + if ($1 == NULL) MYSQL_YYABORT; - ((select_dumpvar *)lex->result)->var_list.push_back(var); + ((select_dumpvar *)Lex->result)->var_list.push_back($1, thd->mem_root); } else { @@ -10678,48 +11485,39 @@ select_var_ident: The parser won't create select_result instance only if it's an EXPLAIN. */ - DBUG_ASSERT(lex->describe); + DBUG_ASSERT(Lex->describe); } } + ; + +select_outvar: + '@' ident_or_text + { + $$ = Lex->result ? new (thd->mem_root) my_var_user($2) : NULL; + } | ident_or_text { - LEX *lex=Lex; - sp_variable_t *t; + sp_variable *t; - if (!lex->spcont || !(t=lex->spcont->find_variable(&$1))) - { - my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); - MYSQL_YYABORT; - } - if (lex->result) - { - my_var *var= new my_var($1,1,t->offset,t->type); - if (var == NULL) - MYSQL_YYABORT; - ((select_dumpvar *)lex->result)->var_list.push_back(var); -#ifndef DBUG_OFF - var->sp= lex->sphead; -#endif - } - else - { - /* - The parser won't create select_result instance only - if it's an EXPLAIN. - */ - DBUG_ASSERT(lex->describe); - } + if (!Lex->spcont || !(t= Lex->spcont->find_variable($1, false))) + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); + $$ = Lex->result ? (new (thd->mem_root) + my_var_sp($1, t->offset, t->type, + Lex->sphead)) : + NULL; } ; +opt_into: + /* empty */ { $$= false; } + | into { $$= true; } + ; + into: INTO { if (! Lex->parsing_options.allows_select_into) - { - my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "INTO"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_CLAUSE, MYF(0), "INTO")); } into_destination ; @@ -10729,8 +11527,10 @@ into_destination: { LEX *lex= Lex; lex->uncacheable(UNCACHEABLE_SIDEEFFECT); - if (!(lex->exchange= new sql_exchange($2.str, 0)) || - !(lex->result= new select_export(lex->exchange))) + if (!(lex->exchange= + new (thd->mem_root) sql_exchange($2.str, 0)) || + !(lex->result= + new (thd->mem_root) select_export(thd, lex->exchange))) MYSQL_YYABORT; } opt_load_data_charset @@ -10742,9 +11542,10 @@ into_destination: if (!lex->describe) { lex->uncacheable(UNCACHEABLE_SIDEEFFECT); - if (!(lex->exchange= new sql_exchange($2.str,1))) + if (!(lex->exchange= new (thd->mem_root) sql_exchange($2.str,1))) MYSQL_YYABORT; - if (!(lex->result= new select_dump(lex->exchange))) + if (!(lex->result= + new (thd->mem_root) select_dump(thd, lex->exchange))) MYSQL_YYABORT; } } @@ -10776,119 +11577,103 @@ do: */ drop: - DROP opt_temporary table_or_tables if_exists + DROP opt_temporary table_or_tables opt_if_exists { LEX *lex=Lex; - lex->sql_command = SQLCOM_DROP_TABLE; - lex->drop_temporary= $2; - lex->drop_if_exists= $4; + lex->set_command(SQLCOM_DROP_TABLE, $2, $4); YYPS->m_lock_type= TL_UNLOCK; YYPS->m_mdl_type= MDL_EXCLUSIVE; } table_list opt_restrict {} - | DROP INDEX_SYM ident ON table_ident {} + | DROP INDEX_SYM opt_if_exists_table_element ident ON table_ident {} { LEX *lex=Lex; - Alter_drop *ad= new Alter_drop(Alter_drop::KEY, $3.str); + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::KEY, $4.str, $3)); if (ad == NULL) MYSQL_YYABORT; lex->sql_command= SQLCOM_DROP_INDEX; lex->alter_info.reset(); - lex->alter_info.flags= ALTER_DROP_INDEX; - lex->alter_info.drop_list.push_back(ad); - if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL, + lex->alter_info.flags= Alter_info::ALTER_DROP_INDEX; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + if (!lex->current_select->add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE)) + MDL_SHARED_UPGRADABLE)) MYSQL_YYABORT; } - | DROP DATABASE if_exists ident + | DROP DATABASE opt_if_exists ident { LEX *lex=Lex; - lex->sql_command= SQLCOM_DROP_DB; - lex->drop_if_exists=$3; + lex->set_command(SQLCOM_DROP_DB, $3); lex->name= $4; } - | DROP FUNCTION_SYM if_exists ident '.' ident + | DROP FUNCTION_SYM opt_if_exists ident '.' ident { LEX *lex= thd->lex; sp_name *spname; if ($4.str && check_db_name(&$4)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), $4.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $4.str)); if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } - lex->sql_command = SQLCOM_DROP_FUNCTION; - lex->drop_if_exists= $3; - spname= new sp_name($4, $6, true); + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION")); + lex->set_command(SQLCOM_DROP_FUNCTION, $3); + spname= new (thd->mem_root) sp_name($4, $6, true); if (spname == NULL) MYSQL_YYABORT; spname->init_qname(thd); lex->spname= spname; } - | DROP FUNCTION_SYM if_exists ident + | DROP FUNCTION_SYM opt_if_exists ident { LEX *lex= thd->lex; LEX_STRING db= {0, 0}; sp_name *spname; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION")); if (thd->db && lex->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; - lex->sql_command = SQLCOM_DROP_FUNCTION; - lex->drop_if_exists= $3; - spname= new sp_name(db, $4, false); + lex->set_command(SQLCOM_DROP_FUNCTION, $3); + spname= new (thd->mem_root) sp_name(db, $4, false); if (spname == NULL) MYSQL_YYABORT; spname->init_qname(thd); lex->spname= spname; } - | DROP PROCEDURE_SYM if_exists sp_name + | DROP PROCEDURE_SYM opt_if_exists sp_name { LEX *lex=Lex; if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"); - MYSQL_YYABORT; - } - lex->sql_command = SQLCOM_DROP_PROCEDURE; - lex->drop_if_exists= $3; + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE")); + lex->set_command(SQLCOM_DROP_PROCEDURE, $3); lex->spname= $4; } - | DROP USER clear_privileges user_list + | DROP USER_SYM opt_if_exists clear_privileges user_list + { + Lex->set_command(SQLCOM_DROP_USER, $3); + } + | DROP ROLE_SYM opt_if_exists clear_privileges role_list { - Lex->sql_command = SQLCOM_DROP_USER; + Lex->set_command(SQLCOM_DROP_ROLE, $3); } - | DROP VIEW_SYM if_exists + | DROP VIEW_SYM opt_if_exists { LEX *lex= Lex; - lex->sql_command= SQLCOM_DROP_VIEW; - lex->drop_if_exists= $3; + lex->set_command(SQLCOM_DROP_VIEW, $3); YYPS->m_lock_type= TL_UNLOCK; YYPS->m_mdl_type= MDL_EXCLUSIVE; } table_list opt_restrict {} - | DROP EVENT_SYM if_exists sp_name + | DROP EVENT_SYM opt_if_exists sp_name { - Lex->drop_if_exists= $3; Lex->spname= $4; - Lex->sql_command = SQLCOM_DROP_EVENT; + Lex->set_command(SQLCOM_DROP_EVENT, $3); } - | DROP TRIGGER_SYM if_exists sp_name + | DROP TRIGGER_SYM opt_if_exists sp_name { LEX *lex= Lex; - lex->sql_command= SQLCOM_DROP_TRIGGER; - lex->drop_if_exists= $3; + lex->set_command(SQLCOM_DROP_TRIGGER, $3); lex->spname= $4; } | DROP TABLESPACE tablespace_name opt_ts_engine opt_ts_wait @@ -10901,12 +11686,10 @@ drop: LEX *lex= Lex; lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP; } - | DROP SERVER_SYM if_exists ident_or_text + | DROP SERVER_SYM opt_if_exists ident_or_text { - Lex->sql_command = SQLCOM_DROP_SERVER; - Lex->drop_if_exists= $3; - Lex->server_options.server_name= $4.str; - Lex->server_options.server_name_length= $4.length; + Lex->set_command(SQLCOM_DROP_SERVER, $3); + Lex->server_options.reset($4); } ; @@ -10926,6 +11709,19 @@ table_name: } ; +table_name_with_opt_use_partition: + table_ident opt_use_partition + { + if (!Select->add_table_to_list(thd, $1, NULL, + TL_OPTION_UPDATING, + YYPS->m_lock_type, + YYPS->m_mdl_type, + NULL, + $2)) + MYSQL_YYABORT; + } + ; + table_alias_ref_list: table_alias_ref | table_alias_ref_list ',' table_alias_ref @@ -10942,14 +11738,33 @@ table_alias_ref: } ; -if_exists: - /* empty */ { $$= 0; } - | IF EXISTS { $$= 1; } +opt_if_exists_table_element: + /* empty */ + { + Lex->check_exists= FALSE; + $$= 0; + } + | IF_SYM EXISTS + { + Lex->check_exists= TRUE; + $$= 1; + } + ; + +opt_if_exists: + /* empty */ + { + $$.set(DDL_options_st::OPT_NONE); + } + | IF_SYM EXISTS + { + $$.set(DDL_options_st::OPT_IF_EXISTS); + } ; opt_temporary: /* empty */ { $$= 0; } - | TEMPORARY { $$= 1; } + | TEMPORARY { $$= HA_LEX_CREATE_TMP_TABLE; } ; /* ** Insert : add new data to table @@ -11030,7 +11845,7 @@ insert2: ; insert_table: - table_name + table_name_with_opt_use_partition { LEX *lex=Lex; lex->field_list.empty(); @@ -11045,16 +11860,17 @@ insert_field_spec: | SET { LEX *lex=Lex; - if (!(lex->insert_list = new List_item) || - lex->many_values.push_back(lex->insert_list)) + if (!(lex->insert_list= new (thd->mem_root) List_item) || + lex->many_values.push_back(lex->insert_list, thd->mem_root)) MYSQL_YYABORT; } ident_eq_list ; fields: - fields ',' insert_ident { Lex->field_list.push_back($3); } - | insert_ident { Lex->field_list.push_back($1); } + fields ',' insert_ident + { Lex->field_list.push_back($3, thd->mem_root); } + | insert_ident { Lex->field_list.push_back($1, thd->mem_root); } ; insert_values: @@ -11082,8 +11898,8 @@ ident_eq_value: simple_ident_nospvar equal expr_or_default { LEX *lex=Lex; - if (lex->field_list.push_back($1) || - lex->insert_list->push_back($3)) + if (lex->field_list.push_back($1, thd->mem_root) || + lex->insert_list->push_back($3, thd->mem_root)) MYSQL_YYABORT; } ; @@ -11101,13 +11917,13 @@ opt_equal: no_braces: '(' { - if (!(Lex->insert_list = new List_item)) + if (!(Lex->insert_list= new (thd->mem_root) List_item)) MYSQL_YYABORT; } opt_values ')' { LEX *lex=Lex; - if (lex->many_values.push_back(lex->insert_list)) + if (lex->many_values.push_back(lex->insert_list, thd->mem_root)) MYSQL_YYABORT; } ; @@ -11120,12 +11936,12 @@ opt_values: values: values ',' expr_or_default { - if (Lex->insert_list->push_back($3)) + if (Lex->insert_list->push_back($3, thd->mem_root)) MYSQL_YYABORT; } | expr_or_default { - if (Lex->insert_list->push_back($1)) + if (Lex->insert_list->push_back($1, thd->mem_root)) MYSQL_YYABORT; } ; @@ -11134,7 +11950,7 @@ expr_or_default: expr { $$= $1;} | DEFAULT { - $$= new (thd->mem_root) Item_default_value(Lex->current_context()); + $$= new (thd->mem_root) Item_default_value(thd, Lex->current_context()); if ($$ == NULL) MYSQL_YYABORT; } @@ -11176,7 +11992,7 @@ update: */ Select->set_lock_for_tables($3); } - where_clause opt_order_clause delete_limit_clause {} + opt_where_clause opt_order_clause delete_limit_clause {} ; update_list: @@ -11201,8 +12017,8 @@ insert_update_elem: simple_ident_nospvar equal expr_or_default { LEX *lex= Lex; - if (lex->update_list.push_back($1) || - lex->value_list.push_back($3)) + if (lex->update_list.push_back($1, thd->mem_root) || + lex->value_list.push_back($3, thd->mem_root)) MYSQL_YYABORT; } ; @@ -11230,24 +12046,27 @@ delete: ; single_multi: - FROM table_ident + FROM table_ident opt_use_partition { if (!Select->add_table_to_list(thd, $2, NULL, TL_OPTION_UPDATING, YYPS->m_lock_type, - YYPS->m_mdl_type)) + YYPS->m_mdl_type, + NULL, + $3)) MYSQL_YYABORT; YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; } - where_clause opt_order_clause + opt_where_clause opt_order_clause delete_limit_clause {} + opt_select_expressions {} | table_wild_list { mysql_init_multi_delete(Lex); YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; } - FROM join_table_list where_clause + FROM join_table_list opt_where_clause { if (multi_delete_set_locks_and_link_aux_tables(Lex)) MYSQL_YYABORT; @@ -11258,13 +12077,18 @@ single_multi: YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; } - USING join_table_list where_clause + USING join_table_list opt_where_clause { if (multi_delete_set_locks_and_link_aux_tables(Lex)) MYSQL_YYABORT; } ; +opt_select_expressions: + /* empty */ + | RETURNING_SYM select_item_list + ; + table_wild_list: table_wild_one | table_wild_list ',' table_wild_one @@ -11273,7 +12097,7 @@ table_wild_list: table_wild_one: ident opt_wild { - Table_ident *ti= new Table_ident($1); + Table_ident *ti= new (thd->mem_root) Table_ident($1); if (ti == NULL) MYSQL_YYABORT; if (!Select->add_table_to_list(thd, @@ -11286,7 +12110,7 @@ table_wild_one: } | ident '.' ident opt_wild { - Table_ident *ti= new Table_ident(thd, $1, $3, 0); + Table_ident *ti= new (thd->mem_root) Table_ident(thd, $1, $3, 0); if (ti == NULL) MYSQL_YYABORT; if (!Select->add_table_to_list(thd, @@ -11330,9 +12154,9 @@ truncate: table_name { LEX* lex= thd->lex; - DBUG_ASSERT(!lex->m_stmt); - lex->m_stmt= new (thd->mem_root) Truncate_statement(lex); - if (lex->m_stmt == NULL) + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_truncate_table(); + if (lex->m_sql_cmd == NULL) MYSQL_YYABORT; } ; @@ -11407,9 +12231,10 @@ show: { LEX *lex=Lex; lex->wild=0; + lex->ident=null_lex_str; mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; - bzero((char*) &lex->create_info,sizeof(lex->create_info)); + lex->create_info.init(); } show_param { @@ -11472,6 +12297,19 @@ show_param: if (prepare_schema_table(thd, lex, 0, SCH_PLUGINS)) MYSQL_YYABORT; } + | PLUGINS_SYM SONAME_SYM TEXT_STRING_sys + { + Lex->ident= $3; + Lex->sql_command= SQLCOM_SHOW_PLUGINS; + if (prepare_schema_table(thd, Lex, 0, SCH_ALL_PLUGINS)) + MYSQL_YYABORT; + } + | PLUGINS_SYM SONAME_SYM wild_and_where + { + Lex->sql_command= SQLCOM_SHOW_PLUGINS; + if (prepare_schema_table(thd, Lex, 0, SCH_ALL_PLUGINS)) + MYSQL_YYABORT; + } | ENGINE_SYM known_storage_engines show_engine_param { Lex->create_info.db_type= $2; } | ENGINE_SYM ALL show_engine_param @@ -11497,13 +12335,14 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS; - } opt_limit_clause_init - | RELAYLOG_SYM EVENTS_SYM binlog_in binlog_from + } + opt_limit_clause + | RELAYLOG_SYM optional_connection_name EVENTS_SYM binlog_in binlog_from { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS; - } opt_limit_clause_init - | keys_or_index from_or_in table_ident opt_db where_clause + } opt_limit_clause + | keys_or_index from_or_in table_ident opt_db opt_where_clause { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_KEYS; @@ -11523,19 +12362,11 @@ show_param: { LEX *lex=Lex; lex->sql_command= SQLCOM_SHOW_AUTHORS; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT, - ER(ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT), - "SHOW AUTHORS"); } | CONTRIBUTORS_SYM { LEX *lex=Lex; lex->sql_command= SQLCOM_SHOW_CONTRIBUTORS; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT, - ER(ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT), - "SHOW CONTRIBUTORS"); } | PRIVILEGES { @@ -11546,25 +12377,25 @@ show_param: { (void) create_select_for_variable("warning_count"); } | COUNT_SYM '(' '*' ')' ERRORS { (void) create_select_for_variable("error_count"); } - | WARNINGS opt_limit_clause_init + | WARNINGS opt_limit_clause { Lex->sql_command = SQLCOM_SHOW_WARNS;} - | ERRORS opt_limit_clause_init + | ERRORS opt_limit_clause { Lex->sql_command = SQLCOM_SHOW_ERRORS;} | PROFILES_SYM { Lex->sql_command = SQLCOM_SHOW_PROFILES; } - | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause_init + | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_PROFILE; if (prepare_schema_table(thd, lex, NULL, SCH_PROFILES) != 0) - YYABORT; + MYSQL_YYABORT; } | opt_var_type STATUS_SYM wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_STATUS; lex->option_type= $1; - if (prepare_schema_table(thd, lex, 0, SCH_STATUS)) + if (prepare_schema_table(thd, lex, 0, SCH_SESSION_STATUS)) MYSQL_YYABORT; } | opt_full PROCESSLIST_SYM @@ -11574,7 +12405,7 @@ show_param: LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_VARIABLES; lex->option_type= $1; - if (prepare_schema_table(thd, lex, 0, SCH_VARIABLES)) + if (prepare_schema_table(thd, lex, 0, SCH_SESSION_VARIABLES)) MYSQL_YYABORT; } | charset wild_and_where @@ -11593,25 +12424,20 @@ show_param: } | GRANTS { - LEX *lex=Lex; - lex->sql_command= SQLCOM_SHOW_GRANTS; - LEX_USER *curr_user; - if (!(curr_user= (LEX_USER*) lex->thd->alloc(sizeof(st_lex_user)))) + Lex->sql_command= SQLCOM_SHOW_GRANTS; + if (!(Lex->grant_user= (LEX_USER*)thd->alloc(sizeof(LEX_USER)))) MYSQL_YYABORT; - bzero(curr_user, sizeof(st_lex_user)); - lex->grant_user= curr_user; + Lex->grant_user->user= current_user_and_current_role; } - | GRANTS FOR_SYM user + | GRANTS FOR_SYM user_or_role clear_privileges { LEX *lex=Lex; lex->sql_command= SQLCOM_SHOW_GRANTS; lex->grant_user=$3; - lex->grant_user->password=null_lex_str; } | CREATE DATABASE opt_if_not_exists ident { - Lex->sql_command=SQLCOM_SHOW_CREATE_DB; - Lex->create_info.options=$3; + Lex->set_command(SQLCOM_SHOW_CREATE_DB, $3); Lex->name= $4; } | CREATE TABLE_SYM table_ident @@ -11634,37 +12460,22 @@ show_param: { Lex->sql_command = SQLCOM_SHOW_MASTER_STAT; } - | SLAVE STATUS_SYM + | ALL SLAVES STATUS_SYM { Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + Lex->verbose= 1; } - | CLIENT_STATS_SYM - { - LEX *lex= Lex; - lex->sql_command= SQLCOM_SHOW_CLIENT_STATS; - if (prepare_schema_table(thd, lex, 0, SCH_CLIENT_STATS)) - MYSQL_YYABORT; - } - | USER_STATS_SYM - { - LEX *lex= Lex; - lex->sql_command= SQLCOM_SHOW_USER_STATS; - if (prepare_schema_table(thd, lex, 0, SCH_USER_STATS)) - MYSQL_YYABORT; - } - | TABLE_STATS_SYM + | SLAVE STATUS_SYM { - LEX *lex= Lex; - lex->sql_command= SQLCOM_SHOW_TABLE_STATS; - if (prepare_schema_table(thd, lex, 0, SCH_TABLE_STATS)) - MYSQL_YYABORT; + LEX *lex= thd->lex; + lex->mi.connection_name= null_lex_str; + lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + lex->verbose= 0; } - | INDEX_STATS_SYM + | SLAVE connection_name STATUS_SYM { - LEX *lex= Lex; - lex->sql_command= SQLCOM_SHOW_INDEX_STATS; - if (prepare_schema_table(thd, lex, 0, SCH_INDEX_STATS)) - MYSQL_YYABORT; + Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + Lex->verbose= 0; } | CREATE PROCEDURE_SYM sp_name { @@ -11715,6 +12526,32 @@ show_param: Lex->spname= $3; Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT; } + | describe_command FOR_SYM expr + { + Lex->sql_command= SQLCOM_SHOW_EXPLAIN; + if (prepare_schema_table(thd, Lex, 0, SCH_EXPLAIN)) + MYSQL_YYABORT; + add_value_to_list(thd, $3); + } + | IDENT_sys remember_tok_start wild_and_where + { + LEX *lex= Lex; + bool in_plugin; + lex->sql_command= SQLCOM_SHOW_GENERIC; + ST_SCHEMA_TABLE *table= find_schema_table(thd, $1.str, &in_plugin); + if (!table || !table->old_format || !in_plugin) + { + my_parse_error(thd, ER_SYNTAX_ERROR, $2); + MYSQL_YYABORT; + } + if (lex->wild && table->idx_field1 < 0) + { + my_parse_error(thd, ER_SYNTAX_ERROR, $3); + MYSQL_YYABORT; + } + if (make_schema_select(thd, Lex->current_select, table)) + MYSQL_YYABORT; + } ; show_engine_param: @@ -11762,19 +12599,21 @@ binlog_from: ; wild_and_where: - /* empty */ - | LIKE TEXT_STRING_sys + /* empty */ { $$= 0; } + | LIKE remember_tok_start TEXT_STRING_sys { - Lex->wild= new (thd->mem_root) String($2.str, $2.length, + Lex->wild= new (thd->mem_root) String($3.str, $3.length, system_charset_info); if (Lex->wild == NULL) MYSQL_YYABORT; + $$= $2; } - | WHERE expr + | WHERE remember_tok_start expr { - Select->where= normalize_cond($2); - if ($2) - $2->top_level_item(); + Select->where= normalize_cond(thd, $3); + if ($3) + $3->top_level_item(); + $$= $2; } ; @@ -11797,22 +12636,50 @@ describe: } | describe_command opt_extended_describe { Lex->describe|= DESCRIBE_NORMAL; } - select + explainable_command { LEX *lex=Lex; lex->select_lex.options|= SELECT_DESCRIBE; } ; +explainable_command: + select + | insert + | replace + | update + | delete + ; + describe_command: DESC | DESCRIBE ; +analyze_stmt_command: + ANALYZE_SYM opt_format_json explainable_command + { + Lex->analyze_stmt= true; + } + ; + opt_extended_describe: - /* empty */ {} - | EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; } + EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; } | PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; } + | opt_format_json {} + ; + +opt_format_json: + /* empty */ {} + | FORMAT_SYM '=' ident_or_text + { + if (!my_strcasecmp(system_charset_info, $3.str, "JSON")) + Lex->explain_json= true; + else if (!my_strcasecmp(system_charset_info, $3.str, "TRADITIONAL")) + DBUG_ASSERT(Lex->explain_json==false); + else + my_yyabort_error((ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0), $3.str)); + } ; opt_describe_column: @@ -11854,24 +12721,37 @@ flush_options: YYPS->m_lock_type= TL_READ_NO_INSERT; YYPS->m_mdl_type= MDL_SHARED_HIGH_PRIO; } - opt_table_list {} - opt_with_read_lock {} + opt_table_list opt_flush_lock + {} | flush_options_list ; -opt_with_read_lock: +opt_flush_lock: /* empty */ {} - | WITH READ_SYM LOCK_SYM optional_flush_tables_arguments + | flush_lock + { + TABLE_LIST *tables= Lex->query_tables; + for (; tables; tables= tables->next_global) { - TABLE_LIST *tables= Lex->query_tables; - Lex->type|= REFRESH_READ_LOCK | $4; - for (; tables; tables= tables->next_global) - { - tables->mdl_request.set_type(MDL_SHARED_NO_WRITE); - tables->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */ - tables->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */ - } + tables->mdl_request.set_type(MDL_SHARED_NO_WRITE); + tables->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */ + tables->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */ } + } + ; + +flush_lock: + WITH READ_SYM LOCK_SYM optional_flush_tables_arguments + { Lex->type|= REFRESH_READ_LOCK | $4; } + | FOR_SYM + { + if (Lex->query_tables == NULL) // Table list can't be empty + { + my_parse_error(thd, ER_NO_TABLES_USED); + MYSQL_YYABORT; + } + Lex->type|= REFRESH_FOR_EXPORT; + } EXPORT_SYM {} ; flush_options_list: @@ -11889,10 +12769,16 @@ flush_option: { Lex->type|= REFRESH_GENERAL_LOG; } | SLOW LOGS_SYM { Lex->type|= REFRESH_SLOW_LOG; } - | BINARY LOGS_SYM + | BINARY LOGS_SYM opt_delete_gtid_domain { Lex->type|= REFRESH_BINARY_LOG; } - | RELAY LOGS_SYM - { Lex->type|= REFRESH_RELAY_LOG; } + | RELAY LOGS_SYM optional_connection_name + { + LEX *lex= Lex; + if (lex->type & REFRESH_RELAY_LOG) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "FLUSH", "RELAY LOGS")); + lex->type|= REFRESH_RELAY_LOG; + lex->relay_log_connection_name= lex->mi.connection_name; + } | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE_FREE; } | HOSTS_SYM @@ -11900,28 +12786,39 @@ flush_option: | PRIVILEGES { Lex->type|= REFRESH_GRANT; } | LOGS_SYM - { Lex->type|= REFRESH_LOG; } + { + Lex->type|= REFRESH_LOG; + Lex->relay_log_connection_name= empty_lex_str; + } | STATUS_SYM { Lex->type|= REFRESH_STATUS; } - | SLAVE + | SLAVE optional_connection_name { - Lex->type|= REFRESH_SLAVE; - Lex->reset_slave_info.all= false; - } - | CLIENT_STATS_SYM - { Lex->type|= REFRESH_CLIENT_STATS; } - | USER_STATS_SYM - { Lex->type|= REFRESH_USER_STATS; } - | TABLE_STATS_SYM - { Lex->type|= REFRESH_TABLE_STATS; } - | INDEX_STATS_SYM - { Lex->type|= REFRESH_INDEX_STATS; } + LEX *lex= Lex; + if (lex->type & REFRESH_SLAVE) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "FLUSH","SLAVE")); + lex->type|= REFRESH_SLAVE; + lex->reset_slave_info.all= false; + } | MASTER_SYM { Lex->type|= REFRESH_MASTER; } | DES_KEY_FILE { Lex->type|= REFRESH_DES_KEY_FILE; } | RESOURCES { Lex->type|= REFRESH_USER_RESOURCES; } + | IDENT_sys remember_tok_start + { + Lex->type|= REFRESH_GENERIC; + ST_SCHEMA_TABLE *table= find_schema_table(thd, $1.str); + if (!table || !table->reset_table) + { + my_parse_error(thd, ER_SYNTAX_ERROR, $2); + MYSQL_YYABORT; + } + Lex->view_list.push_back((LEX_STRING*) + thd->memdup(&$1, sizeof(LEX_STRING)), + thd->mem_root); + } ; opt_table_list: @@ -11929,6 +12826,33 @@ opt_table_list: | table_list {} ; +opt_delete_gtid_domain: + /* empty */ {} + | DELETE_DOMAIN_ID_SYM '=' '(' delete_domain_id_list ')' + {} + ; +delete_domain_id_list: + /* Empty */ + | delete_domain_id + | delete_domain_id_list ',' delete_domain_id + ; + +delete_domain_id: + ulonglong_num + { + uint32 value= (uint32) $1; + if ($1 > UINT_MAX32) + { + my_printf_error(ER_BINLOG_CANT_DELETE_GTID_DOMAIN, + "The value of gtid domain being deleted ('%llu') " + "exceeds its maximum size " + "of 32 bit unsigned integer", MYF(0), $1); + MYSQL_YYABORT; + } + insert_dynamic(&Lex->delete_gtid_domain, (uchar*) &value); + } + ; + optional_flush_tables_arguments: /* empty */ {$$= 0;} | AND_SYM DISABLE_SYM CHECKPOINT_SYM {$$= REFRESH_CHECKPOINT; } @@ -11950,8 +12874,14 @@ reset_options: reset_option: SLAVE { Lex->type|= REFRESH_SLAVE; } + optional_connection_name slave_reset_options { } - | MASTER_SYM { Lex->type|= REFRESH_MASTER; } + | MASTER_SYM + { + Lex->type|= REFRESH_MASTER; + Lex->next_binlog_file_number= 0; + } + master_reset_options | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE;} ; @@ -11960,6 +12890,14 @@ slave_reset_options: | ALL { Lex->reset_slave_info.all= true; } ; +master_reset_options: + /* empty */ {} + | TO_SYM ulong_num + { + Lex->next_binlog_file_number = $2; + } + ; + purge: PURGE { @@ -11984,7 +12922,7 @@ purge_option: { LEX *lex= Lex; lex->value_list.empty(); - lex->value_list.push_front($2); + lex->value_list.push_front($2, thd->mem_root); lex->sql_command= SQLCOM_PURGE_BEFORE; } ; @@ -11998,6 +12936,7 @@ kill: lex->value_list.empty(); lex->users_list.empty(); lex->sql_command= SQLCOM_KILL; + lex->kill_type= KILL_TYPE_ID; } kill_type kill_option kill_expr { @@ -12014,21 +12953,30 @@ kill_option: /* empty */ { $$= (int) KILL_CONNECTION; } | CONNECTION_SYM { $$= (int) KILL_CONNECTION; } | QUERY_SYM { $$= (int) KILL_QUERY; } + | QUERY_SYM ID_SYM + { + $$= (int) KILL_QUERY; + Lex->kill_type= KILL_TYPE_QUERY; + } ; kill_expr: expr { - Lex->value_list.push_front($$); - Lex->kill_type= KILL_TYPE_ID; + Lex->value_list.push_front($$, thd->mem_root); } - | USER user + | USER_SYM user { - Lex->users_list.push_back($2); + Lex->users_list.push_back($2, thd->mem_root); Lex->kill_type= KILL_TYPE_USER; } ; + +shutdown: + SHUTDOWN { Lex->sql_command= SQLCOM_SHUTDOWN; } + ; + /* change database */ use: @@ -12046,6 +12994,7 @@ load: LOAD data_or_xml { LEX *lex= thd->lex; + mysql_init_select(lex); if (lex->sphead) { @@ -12061,14 +13010,14 @@ load: lex->local_file= $5; lex->duplicates= DUP_ERROR; lex->ignore= 0; - if (!(lex->exchange= new sql_exchange($7.str, 0, $2))) + if (!(lex->exchange= new (thd->mem_root) sql_exchange($7.str, 0, $2))) MYSQL_YYABORT; } - opt_duplicate INTO TABLE_SYM table_ident + opt_duplicate INTO TABLE_SYM table_ident opt_use_partition { LEX *lex=Lex; if (!Select->add_table_to_list(thd, $12, NULL, TL_OPTION_UPDATING, - $4, MDL_SHARED_WRITE)) + $4, MDL_SHARED_WRITE, NULL, $13)) MYSQL_YYABORT; lex->field_list.empty(); lex->update_list.empty(); @@ -12076,7 +13025,7 @@ load: lex->many_values.empty(); } opt_load_data_charset - { Lex->exchange->cs= $14; } + { Lex->exchange->cs= $15; } opt_xml_rows_identified_by opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec opt_load_data_set_spec @@ -12185,8 +13134,7 @@ opt_ignore_lines: ; lines_or_rows: - LINES { } - + LINES { } | ROWS_SYM { } ; @@ -12198,16 +13146,16 @@ opt_field_or_var_spec: fields_or_vars: fields_or_vars ',' field_or_var - { Lex->field_list.push_back($3); } + { Lex->field_list.push_back($3, thd->mem_root); } | field_or_var - { Lex->field_list.push_back($1); } + { Lex->field_list.push_back($1, thd->mem_root); } ; field_or_var: simple_ident_nospvar {$$= $1;} | '@' ident_or_text { - $$= new (thd->mem_root) Item_user_var_as_out_param($2); + $$= new (thd->mem_root) Item_user_var_as_out_param(thd, $2); if ($$ == NULL) MYSQL_YYABORT; } @@ -12227,8 +13175,8 @@ load_data_set_elem: simple_ident_nospvar equal remember_name expr_or_default remember_end { LEX *lex= Lex; - if (lex->update_list.push_back($1) || - lex->value_list.push_back($4)) + if (lex->update_list.push_back($1, thd->mem_root) || + lex->value_list.push_back($4, thd->mem_root)) MYSQL_YYABORT; $4->set_name_no_truncate($3, (uint) ($5 - $3), thd->charset()); } @@ -12254,7 +13202,8 @@ text_literal: if (thd->convert_string(&tmp, cs_con, $1.str, $1.length, cs_cli)) MYSQL_YYABORT; } - $$= new (thd->mem_root) Item_string(tmp.str, tmp.length, cs_con, + $$= new (thd->mem_root) Item_string(thd, tmp.str, tmp.length, + cs_con, DERIVATION_COERCIBLE, repertoire); if ($$ == NULL) @@ -12265,7 +13214,7 @@ text_literal: uint repertoire= Lex->text_string_is_7bit ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30; DBUG_ASSERT(my_charset_is_ascii_based(national_charset_info)); - $$= new (thd->mem_root) Item_string($1.str, $1.length, + $$= new (thd->mem_root) Item_string(thd, $1.str, $1.length, national_charset_info, DERIVATION_COERCIBLE, repertoire); @@ -12274,14 +13223,10 @@ text_literal: } | UNDERSCORE_CHARSET TEXT_STRING { - Item_string *str= new (thd->mem_root) Item_string($2.str, + $$= new (thd->mem_root) Item_string_with_introducer(thd, $2.str, $2.length, $1); - if (str == NULL) + if ($$ == NULL) MYSQL_YYABORT; - str->set_repertoire_from_value(); - str->set_cs_specified(TRUE); - - $$= str; } | text_literal TEXT_STRING_literal { @@ -12310,9 +13255,15 @@ text_string: if ($$ == NULL) MYSQL_YYABORT; } - | HEX_NUM + | hex_or_bin_String { $$= $1; } + ; + + +hex_or_bin_String: + HEX_NUM { - Item *tmp= new (thd->mem_root) Item_hex_hybrid($1.str, $1.length); + Item *tmp= new (thd->mem_root) Item_hex_hybrid(thd, $1.str, + $1.length); if (tmp == NULL) MYSQL_YYABORT; /* @@ -12324,7 +13275,8 @@ text_string: } | HEX_STRING { - Item *tmp= new (thd->mem_root) Item_hex_string($1.str, $1.length); + Item *tmp= new (thd->mem_root) Item_hex_string(thd, $1.str, + $1.length); if (tmp == NULL) MYSQL_YYABORT; tmp->quick_fix_field(); @@ -12332,7 +13284,8 @@ text_string: } | BIN_NUM { - Item *tmp= new (thd->mem_root) Item_bin_string($1.str, $1.length); + Item *tmp= new (thd->mem_root) Item_bin_string(thd, $1.str, + $1.length); if (tmp == NULL) MYSQL_YYABORT; /* @@ -12351,16 +13304,13 @@ param_marker: Lex_input_stream *lip= YYLIP; Item_param *item; if (! lex->parsing_options.allows_variable) - { - my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); - MYSQL_YYABORT; - } - item= new (thd->mem_root) Item_param((uint) (lip->get_tok_start() - thd->query())); - if (!($$= item) || lex->param_list.push_back(item)) - { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); + const char *query_start= lex->sphead ? lex->sphead->m_tmp_query + : thd->query(); + item= new (thd->mem_root) Item_param(thd, lip->get_tok_start() - + query_start); + if (!($$= item) || lex->param_list.push_back(item, thd->mem_root)) + my_yyabort_error((ER_OUT_OF_RESOURCES, MYF(0))); } ; @@ -12370,110 +13320,73 @@ signed_literal: | '-' NUM_literal { $2->max_length++; - $$= $2->neg(); + $$= $2->neg(thd); } ; literal: text_literal { $$ = $1; } | NUM_literal { $$ = $1; } + | temporal_literal { $$= $1; } | NULL_SYM { - $$ = new (thd->mem_root) Item_null(); + /* + For the digest computation, in this context only, + NULL is considered a literal, hence reduced to '?' + REDUCE: + TOK_GENERIC_VALUE := NULL_SYM + */ + YYLIP->reduce_digest_token(TOK_GENERIC_VALUE, NULL_SYM); + $$= new (thd->mem_root) Item_null(thd); if ($$ == NULL) MYSQL_YYABORT; YYLIP->next_state= MY_LEX_OPERATOR_OR_IDENT; } | FALSE_SYM { - $$= new (thd->mem_root) Item_int((char*) "FALSE",0,1); + $$= new (thd->mem_root) Item_int(thd, (char*) "FALSE",0,1); if ($$ == NULL) MYSQL_YYABORT; } | TRUE_SYM { - $$= new (thd->mem_root) Item_int((char*) "TRUE",1,1); + $$= new (thd->mem_root) Item_int(thd, (char*) "TRUE",1,1); if ($$ == NULL) MYSQL_YYABORT; } | HEX_NUM { - $$ = new (thd->mem_root) Item_hex_hybrid($1.str, $1.length); + $$= new (thd->mem_root) Item_hex_hybrid(thd, $1.str, $1.length); if ($$ == NULL) MYSQL_YYABORT; } | HEX_STRING { - $$ = new (thd->mem_root) Item_hex_string($1.str, $1.length); + $$= new (thd->mem_root) Item_hex_string(thd, $1.str, $1.length); if ($$ == NULL) MYSQL_YYABORT; } | BIN_NUM { - $$= new (thd->mem_root) Item_bin_string($1.str, $1.length); + $$= new (thd->mem_root) Item_bin_string(thd, $1.str, $1.length); if ($$ == NULL) MYSQL_YYABORT; } - | UNDERSCORE_CHARSET hex_num_or_string - { - Item *tmp= new (thd->mem_root) Item_hex_string($2.str, $2.length); - if (tmp == NULL) - MYSQL_YYABORT; - /* - it is OK only emulate fix_fieds, because we need only - value of constant - */ - tmp->quick_fix_field(); - String *str= tmp->val_str((String*) 0); - - Item_string *item_str; - item_str= new (thd->mem_root) - Item_string(NULL, /* name will be set in select_item */ - str ? str->ptr() : "", - str ? str->length() : 0, - $1); - if (!item_str || - !item_str->check_well_formed_result(&item_str->str_value, TRUE)) - { - MYSQL_YYABORT; - } - - item_str->set_repertoire_from_value(); - item_str->set_cs_specified(TRUE); - - $$= item_str; - } - | UNDERSCORE_CHARSET BIN_NUM + | UNDERSCORE_CHARSET hex_or_bin_String { - Item *tmp= new (thd->mem_root) Item_bin_string($2.str, $2.length); - if (tmp == NULL) - MYSQL_YYABORT; + Item_string_with_introducer *item_str; /* - it is OK only emulate fix_fieds, because we need only - value of constant + Pass NULL as name. Name will be set in the "select_item" rule and + will include the introducer and the original hex/bin notation. */ - tmp->quick_fix_field(); - String *str= tmp->val_str((String*) 0); - - Item_string *item_str; item_str= new (thd->mem_root) - Item_string(NULL, /* name will be set in select_item */ - str ? str->ptr() : "", - str ? str->length() : 0, - $1); - if (!item_str || - !item_str->check_well_formed_result(&item_str->str_value, TRUE)) - { + Item_string_with_introducer(thd, NULL, $2->ptr(), $2->length(), + $1); + if (!item_str || !item_str->check_well_formed_result(true)) MYSQL_YYABORT; - } - - item_str->set_cs_specified(TRUE); $$= item_str; } - | DATE_SYM text_literal { $$ = $2; } - | TIME_SYM text_literal { $$ = $2; } - | TIMESTAMP text_literal { $$ = $2; } ; NUM_literal: @@ -12481,7 +13394,7 @@ NUM_literal: { int error; $$= new (thd->mem_root) - Item_int($1.str, + Item_int(thd, $1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); if ($$ == NULL) @@ -12491,7 +13404,7 @@ NUM_literal: { int error; $$= new (thd->mem_root) - Item_int($1.str, + Item_int(thd, $1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); if ($$ == NULL) @@ -12499,13 +13412,13 @@ NUM_literal: } | ULONGLONG_NUM { - $$= new (thd->mem_root) Item_uint($1.str, $1.length); + $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length); if ($$ == NULL) MYSQL_YYABORT; } | DECIMAL_NUM { - $$= new (thd->mem_root) Item_decimal($1.str, $1.length, + $$= new (thd->mem_root) Item_decimal(thd, $1.str, $1.length, thd->charset()); if (($$ == NULL) || (thd->is_error())) { @@ -12514,7 +13427,7 @@ NUM_literal: } | FLOAT_NUM { - $$= new (thd->mem_root) Item_float($1.str, $1.length); + $$= new (thd->mem_root) Item_float(thd, $1.str, $1.length); if (($$ == NULL) || (thd->is_error())) { MYSQL_YYABORT; @@ -12522,6 +13435,31 @@ NUM_literal: } ; + +temporal_literal: + DATE_SYM TEXT_STRING + { + if (!($$= create_temporal_literal(thd, $2.str, $2.length, YYCSCL, + MYSQL_TYPE_DATE, true))) + MYSQL_YYABORT; + } + | TIME_SYM TEXT_STRING + { + if (!($$= create_temporal_literal(thd, $2.str, $2.length, YYCSCL, + MYSQL_TYPE_TIME, true))) + MYSQL_YYABORT; + } + | TIMESTAMP TEXT_STRING + { + if (!($$= create_temporal_literal(thd, $2.str, $2.length, YYCSCL, + MYSQL_TYPE_DATETIME, true))) + MYSQL_YYABORT; + } + ; + + + + /********************************************************************** ** Creating different items. **********************************************************************/ @@ -12535,7 +13473,7 @@ table_wild: ident '.' '*' { SELECT_LEX *sel= Select; - $$= new (thd->mem_root) Item_field(Lex->current_context(), + $$= new (thd->mem_root) Item_field(thd, Lex->current_context(), NullS, $1.str, "*"); if ($$ == NULL) MYSQL_YYABORT; @@ -12546,7 +13484,7 @@ table_wild: SELECT_LEX *sel= Select; const char* schema= thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str; - $$= new (thd->mem_root) Item_field(Lex->current_context(), + $$= new (thd->mem_root) Item_field(thd, Lex->current_context(), schema, $3.str,"*"); if ($$ == NULL) @@ -12564,20 +13502,17 @@ simple_ident: { LEX *lex= thd->lex; Lex_input_stream *lip= YYLIP; - sp_variable_t *spv; + sp_variable *spv; sp_pcontext *spc = lex->spcont; - if (spc && (spv = spc->find_variable(&$1))) + if (spc && (spv = spc->find_variable($1, false))) { /* We're compiling a stored procedure and found a variable */ if (! lex->parsing_options.allows_variable) - { - my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); Item_splocal *splocal; splocal= new (thd->mem_root) - Item_splocal($1, spv->offset, spv->type, + Item_splocal(thd, $1, spv->offset, spv->type, lip->get_tok_start_prev() - lex->sphead->m_tmp_query, lip->get_tok_end() - lip->get_tok_start_prev()); if (splocal == NULL) @@ -12594,12 +13529,12 @@ simple_ident: if ((sel->parsing_place != IN_HAVING) || (sel->get_in_sum_expr() > 0)) { - $$= new (thd->mem_root) Item_field(Lex->current_context(), + $$= new (thd->mem_root) Item_field(thd, Lex->current_context(), NullS, NullS, $1.str); } else { - $$= new (thd->mem_root) Item_ref(Lex->current_context(), + $$= new (thd->mem_root) Item_ref(thd, Lex->current_context(), NullS, NullS, $1.str); } if ($$ == NULL) @@ -12616,12 +13551,12 @@ simple_ident_nospvar: if ((sel->parsing_place != IN_HAVING) || (sel->get_in_sum_expr() > 0)) { - $$= new (thd->mem_root) Item_field(Lex->current_context(), + $$= new (thd->mem_root) Item_field(thd, Lex->current_context(), NullS, NullS, $1.str); } else { - $$= new (thd->mem_root) Item_ref(Lex->current_context(), + $$= new (thd->mem_root) Item_ref(thd, Lex->current_context(), NullS, NullS, $1.str); } if ($$ == NULL) @@ -12649,31 +13584,25 @@ simple_ident_q: if (lex->trg_chistics.event == TRG_EVENT_INSERT && !new_row) - { - my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT")); if (lex->trg_chistics.event == TRG_EVENT_DELETE && new_row) - { - my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE")); DBUG_ASSERT(!new_row || (lex->trg_chistics.event == TRG_EVENT_INSERT || lex->trg_chistics.event == TRG_EVENT_UPDATE)); - const bool read_only= + const bool tmp_read_only= !(new_row && lex->trg_chistics.action_time == TRG_ACTION_BEFORE); trg_fld= new (thd->mem_root) - Item_trigger_field(Lex->current_context(), + Item_trigger_field(thd, Lex->current_context(), new_row ? Item_trigger_field::NEW_ROW: Item_trigger_field::OLD_ROW, $3.str, SELECT_ACL, - read_only); + tmp_read_only); if (trg_fld == NULL) MYSQL_YYABORT; @@ -12697,12 +13626,12 @@ simple_ident_q: if ((sel->parsing_place != IN_HAVING) || (sel->get_in_sum_expr() > 0)) { - $$= new (thd->mem_root) Item_field(Lex->current_context(), + $$= new (thd->mem_root) Item_field(thd, Lex->current_context(), NullS, $1.str, $3.str); } else { - $$= new (thd->mem_root) Item_ref(Lex->current_context(), + $$= new (thd->mem_root) Item_ref(thd, Lex->current_context(), NullS, $1.str, $3.str); } if ($$ == NULL) @@ -12721,13 +13650,13 @@ simple_ident_q: if ((sel->parsing_place != IN_HAVING) || (sel->get_in_sum_expr() > 0)) { - $$= new (thd->mem_root) Item_field(Lex->current_context(), + $$= new (thd->mem_root) Item_field(thd, Lex->current_context(), NullS, $2.str, $4.str); } else { - $$= new (thd->mem_root) Item_ref(Lex->current_context(), + $$= new (thd->mem_root) Item_ref(thd, Lex->current_context(), NullS, $2.str, $4.str); } if ($$ == NULL) @@ -12747,13 +13676,13 @@ simple_ident_q: if ((sel->parsing_place != IN_HAVING) || (sel->get_in_sum_expr() > 0)) { - $$= new (thd->mem_root) Item_field(Lex->current_context(), + $$= new (thd->mem_root) Item_field(thd, Lex->current_context(), schema, $3.str, $5.str); } else { - $$= new (thd->mem_root) Item_ref(Lex->current_context(), + $$= new (thd->mem_root) Item_ref(thd, Lex->current_context(), schema, $3.str, $5.str); } @@ -12768,26 +13697,17 @@ field_ident: { TABLE_LIST *table= Select->table_list.first; if (my_strcasecmp(table_alias_charset, $1.str, table->db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $1.str)); if (my_strcasecmp(table_alias_charset, $3.str, table->table_name)) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), $3.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $3.str)); $$=$5; } | ident '.' ident { TABLE_LIST *table= Select->table_list.first; if (my_strcasecmp(table_alias_charset, $1.str, table->alias)) - { - my_error(ER_WRONG_TABLE_NAME, MYF(0), $1.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $1.str)); $$=$3; } | '.' ident { $$=$2;} /* For Delphi */ @@ -12796,20 +13716,20 @@ field_ident: table_ident: ident { - $$= new Table_ident($1); + $$= new (thd->mem_root) Table_ident($1); if ($$ == NULL) MYSQL_YYABORT; } | ident '.' ident { - $$= new Table_ident(thd, $1,$3,0); + $$= new (thd->mem_root) Table_ident(thd, $1, $3, 0); if ($$ == NULL) MYSQL_YYABORT; } | '.' ident { /* For Delphi */ - $$= new Table_ident($2); + $$= new (thd->mem_root) Table_ident($2); if ($$ == NULL) MYSQL_YYABORT; } @@ -12818,13 +13738,13 @@ table_ident: table_ident_opt_wild: ident opt_wild { - $$= new Table_ident($1); + $$= new (thd->mem_root) Table_ident($1); if ($$ == NULL) MYSQL_YYABORT; } | ident '.' ident opt_wild { - $$= new Table_ident(thd, $1,$3,0); + $$= new (thd->mem_root) Table_ident(thd, $1, $3, 0); if ($$ == NULL) MYSQL_YYABORT; } @@ -12834,7 +13754,7 @@ table_ident_nodb: ident { LEX_STRING db={(char*) any_db,3}; - $$= new Table_ident(thd, db,$1,0); + $$= new (thd->mem_root) Table_ident(thd, db, $1, 0); if ($$ == NULL) MYSQL_YYABORT; } @@ -12862,8 +13782,8 @@ IDENT_sys: } else { - if (thd->convert_string(&$$, system_charset_info, - $1.str, $1.length, thd->charset())) + if (thd->convert_with_error(system_charset_info, &$$, + thd->charset(), $1.str, $1.length)) MYSQL_YYABORT; } } @@ -12940,19 +13860,16 @@ ident_or_text: | LEX_HOSTNAME { $$=$1;} ; -user: +user_maybe_role: ident_or_text { if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) MYSQL_YYABORT; $$->user = $1; - $$->host.str= (char *) "%"; - $$->host.length= 1; - $$->password= null_lex_str; - $$->plugin= empty_lex_str; - $$->auth= empty_lex_str; + $$->host= null_lex_str; // User or Role, see get_current_user() + $$->reset_auth(); - if (check_string_char_length(&$$->user, ER(ER_USERNAME), + if (check_string_char_length(&$$->user, ER_USERNAME, username_char_length, system_charset_info, 0)) MYSQL_YYABORT; @@ -12962,35 +13879,51 @@ user: if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) MYSQL_YYABORT; $$->user = $1; $$->host=$3; - $$->password= null_lex_str; - $$->plugin= empty_lex_str; - $$->auth= empty_lex_str; + $$->reset_auth(); - if (check_string_char_length(&$$->user, ER(ER_USERNAME), + if (check_string_char_length(&$$->user, ER_USERNAME, username_char_length, system_charset_info, 0) || check_host_name(&$$->host)) MYSQL_YYABORT; - /* - Convert hostname part of username to lowercase. - It's OK to use in-place lowercase as long as - the character set is utf8. - */ - my_casedn_str(system_charset_info, $$->host.str); + if ($$->host.str[0]) + { + /* + Convert hostname part of username to lowercase. + It's OK to use in-place lowercase as long as + the character set is utf8. + */ + my_casedn_str(system_charset_info, $$->host.str); + } + else + { + /* + fix historical undocumented convention that empty host is the + same as '%' + */ + $$->host= host_not_specified; + } } | CURRENT_USER optional_braces { - if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) + if (!($$=(LEX_USER*)thd->calloc(sizeof(LEX_USER)))) MYSQL_YYABORT; - /* - empty LEX_USER means current_user and - will be handled in the get_current_user() function - later - */ - bzero($$, sizeof(LEX_USER)); + $$->user= current_user; + $$->plugin= empty_lex_str; + $$->auth= empty_lex_str; } ; +user_or_role: user_maybe_role | current_role; + +user: user_maybe_role + { + if ($1->user.str != current_user.str && $1->host.str == 0) + $1->host= host_not_specified; + $$= $1; + } + ; + /* Keyword that we allow for identifiers (except SP labels) */ keyword: keyword_sp {} @@ -13004,11 +13937,10 @@ keyword: | CHECKPOINT_SYM {} | CLOSE_SYM {} | COLUMN_ADD_SYM {} + | COLUMN_CHECK_SYM {} | COLUMN_CREATE_SYM {} | COLUMN_DELETE_SYM {} - | COLUMN_EXISTS_SYM {} | COLUMN_GET_SYM {} - | COLUMN_LIST_SYM {} | COMMENT_SYM {} | COMMIT_SYM {} | CONTAINS_SYM {} @@ -13018,6 +13950,8 @@ keyword: | EXAMINED_SYM {} | EXECUTE_SYM {} | FLUSH_SYM {} + | FORMAT_SYM {} + | GET_SYM {} | HANDLER_SYM {} | HELP_SYM {} | HOST_SYM {} @@ -13029,7 +13963,6 @@ keyword: | OPTIONS_SYM {} | OWNER_SYM {} | PARSER_SYM {} - | PARTITION_SYM {} | PORT_SYM {} | PREPARE_SYM {} | REMOVE_SYM {} @@ -13040,9 +13973,11 @@ keyword: | SAVEPOINT_SYM {} | SECURITY_SYM {} | SERVER_SYM {} + | SHUTDOWN {} | SIGNED_SYM {} | SOCKET_SYM {} | SLAVE {} + | SLAVES {} | SONAME_SYM {} | START_SYM {} | STOP_SYM {} @@ -13063,6 +13998,7 @@ keyword: keyword_sp: ACTION {} | ADDDATE_SYM {} + | ADMIN_SYM {} | AFTER_SYM {} | AGAINST {} | AGGREGATE_SYM {} @@ -13070,9 +14006,11 @@ keyword_sp: | ALWAYS_SYM {} | ANY_SYM {} | AT_SYM {} + | ATOMIC_SYM {} | AUTHORS_SYM {} | AUTO_INC {} | AUTOEXTEND_SIZE_SYM {} + | AUTO_SYM {} | AVG_ROW_LENGTH {} | AVG_SYM {} | BINLOG_SYM {} @@ -13086,7 +14024,6 @@ keyword_sp: | CHAIN_SYM {} | CHANGED {} | CIPHER_SYM {} - | CLIENT_STATS_SYM {} | CLIENT_SYM {} | CLASS_ORIGIN_SYM {} | COALESCE {} @@ -13106,8 +14043,14 @@ keyword_sp: | CONSTRAINT_NAME_SYM {} | CONTEXT_SYM {} | CONTRIBUTORS_SYM {} + | CURRENT_POS_SYM {} | CPU_SYM {} | CUBE_SYM {} + /* + Although a reserved keyword in SQL:2003 (and :2008), + not reserved in MySQL per WL#2111 specification. + */ + | CURRENT_SYM {} | CURSOR_NAME_SYM {} | DATA_SYM {} | DATAFILE_SYM {} @@ -13117,6 +14060,7 @@ keyword_sp: | DEFINER_SYM {} | DELAY_KEY_WRITE_SYM {} | DES_KEY_FILE {} + | DIAGNOSTICS_SYM {} | DIRECTORY_SYM {} | DISABLE_SYM {} | DISCARD {} @@ -13134,7 +14078,9 @@ keyword_sp: | EVENT_SYM {} | EVENTS_SYM {} | EVERY_SYM {} + | EXCHANGE_SYM {} | EXPANSION_SYM {} + | EXPORT_SYM {} | EXTENDED_SYM {} | EXTENT_SIZE_SYM {} | FAULTS_SYM {} @@ -13156,9 +14102,9 @@ keyword_sp: | HARD_SYM {} | HOSTS_SYM {} | HOUR_SYM {} + | ID_SYM {} | IDENTIFIED_SYM {} | IGNORE_SERVER_IDS_SYM {} - | INDEX_STATS_SYM {} | INVOKER_SYM {} | IMPORT {} | INDEXES {} @@ -13183,11 +14129,13 @@ keyword_sp: | MAX_ROWS {} | MASTER_SYM {} | MASTER_HEARTBEAT_PERIOD_SYM {} + | MASTER_GTID_POS_SYM {} | MASTER_HOST_SYM {} | MASTER_PORT_SYM {} | MASTER_LOG_FILE_SYM {} | MASTER_LOG_POS_SYM {} | MASTER_USER_SYM {} + | MASTER_USE_GTID_SYM {} | MASTER_PASSWORD_SYM {} | MASTER_SERVER_ID_SYM {} | MASTER_CONNECT_RETRY_SYM {} @@ -13196,10 +14144,13 @@ keyword_sp: | MASTER_SSL_CAPATH_SYM {} | MASTER_SSL_CERT_SYM {} | MASTER_SSL_CIPHER_SYM {} + | MASTER_SSL_CRL_SYM {} + | MASTER_SSL_CRLPATH_SYM {} | MASTER_SSL_KEY_SYM {} | MAX_CONNECTIONS_PER_HOUR {} | MAX_QUERIES_PER_HOUR {} | MAX_SIZE_SYM {} + | MAX_STATEMENT_TIME_SYM {} | MAX_UPDATES_PER_HOUR {} | MAX_USER_CONNECTIONS_SYM {} | MEDIUM_SYM {} @@ -13223,24 +14174,24 @@ keyword_sp: | NAMES_SYM {} | NATIONAL_SYM {} | NCHAR_SYM {} - | NDBCLUSTER_SYM {} | NEXT_SYM {} | NEW_SYM {} | NO_WAIT_SYM {} | NODEGROUP_SYM {} | NONE_SYM {} + | NUMBER_SYM {} | NVARCHAR_SYM {} | OFFSET_SYM {} - | OLD_PASSWORD {} - | ONE_SHOT_SYM {} + | OLD_PASSWORD_SYM {} | ONE_SYM {} | ONLINE_SYM {} + | ONLY_SYM {} | PACK_KEYS_SYM {} | PAGE_SYM {} | PARTIAL {} | PARTITIONING_SYM {} | PARTITIONS_SYM {} - | PASSWORD {} + | PASSWORD_SYM {} | PERSISTENT_SYM {} | PHASE_SYM {} | PLUGIN_SYM {} @@ -13275,10 +14226,14 @@ keyword_sp: | REPLICATION {} | RESOURCES {} | RESUME_SYM {} + | RETURNED_SQLSTATE_SYM {} | RETURNS_SYM {} + | REVERSE_SYM {} + | ROLE_SYM {} | ROLLUP_SYM {} | ROUTINE_SYM {} | ROWS_SYM {} + | ROW_COUNT_SYM {} | ROW_FORMAT_SYM {} | ROW_SYM {} | RTREE_SYM {} @@ -13290,7 +14245,7 @@ keyword_sp: | SESSION_SYM {} | SIMPLE_SYM {} | SHARE_SYM {} - | SHUTDOWN {} + | SLAVE_POS_SYM {} | SLOW {} | SNAPSHOT_SYM {} | SOFT_SYM {} @@ -13301,6 +14256,7 @@ keyword_sp: | SQL_NO_CACHE_SYM {} | SQL_THREAD {} | STARTS_SYM {} + | STATEMENT_SYM {} | STATUS_SYM {} | STORAGE_SYM {} | STRING_SYM {} @@ -13314,7 +14270,6 @@ keyword_sp: | SWAPS_SYM {} | SWITCHES_SYM {} | TABLE_NAME_SYM {} - | TABLE_STATS_SYM {} | TABLES {} | TABLE_CHECKSUM_SYM {} | TABLESPACE {} @@ -13339,8 +14294,7 @@ keyword_sp: | UNDOFILE_SYM {} | UNKNOWN_SYM {} | UNTIL_SYM {} - | USER {} - | USER_STATS_SYM {} + | USER_SYM {} | USE_FRM {} | VARIABLES {} | VIEW_SYM {} @@ -13349,6 +14303,7 @@ keyword_sp: | WARNINGS {} | WAIT_SYM {} | WEEK_SYM {} + | WEIGHT_STRING_SYM {} | WORK_SYM {} | X509_SYM {} | XML_SYM {} @@ -13356,125 +14311,138 @@ keyword_sp: | VIA_SYM {} ; -/* Option functions */ +/* + SQLCOM_SET_OPTION statement. + + Note that to avoid shift/reduce conflicts, we have separate rules for the + first option listed in the statement. +*/ set: - SET opt_option + SET { LEX *lex=Lex; lex->sql_command= SQLCOM_SET_OPTION; mysql_init_select(lex); lex->option_type=OPT_SESSION; lex->var_list.empty(); - lex->one_shot_set= 0; lex->autocommit= 0; + sp_create_assignment_lex(thd, yychar == YYEMPTY); } - option_value_list + start_option_value_list {} + | SET STATEMENT_SYM + { + LEX *lex= Lex; + mysql_init_select(lex); + lex->option_type= OPT_SESSION; + lex->sql_command= SQLCOM_SET_OPTION; + lex->autocommit= 0; + } + set_stmt_option_value_following_option_type_list + { + LEX *lex= Lex; + if (lex->table_or_sp_used()) + my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT")); + lex->stmt_var_list= lex->var_list; + lex->var_list.empty(); + } + FOR_SYM verb_clause + {} ; -opt_option: - /* empty */ {} - | OPTION {} - ; - -option_value_list: - option_type_value - | option_value_list ',' option_type_value - ; +set_stmt_option_value_following_option_type_list: + /* + Only system variables can be used here. If this condition is changed + please check careful code under lex->option_type == OPT_STATEMENT + condition on wrong type casts. + */ + option_value_following_option_type + | set_stmt_option_value_following_option_type_list ',' option_value_following_option_type -option_type_value: +// Start of option value list +start_option_value_list: + option_value_no_option_type { - LEX *lex= thd->lex; - Lex_input_stream *lip= YYLIP; + if (sp_create_assignment_instr(thd, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + option_value_list_continued + | TRANSACTION_SYM + { + Lex->option_type= OPT_DEFAULT; + } + transaction_characteristics + { + if (sp_create_assignment_instr(thd, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + | option_type + { + Lex->option_type= $1; + } + start_option_value_list_following_option_type + ; - if (lex->sphead) - { - /* - If we are in SP we want have own LEX for each assignment. - This is mostly because it is hard for several sp_instr_set - and sp_instr_set_trigger instructions share one LEX. - (Well, it is theoretically possible but adds some extra - overhead on preparation for execution stage and IMO less - robust). - - QQ: May be we should simply prohibit group assignments in SP? - */ - lex->sphead->reset_lex(thd); - lex= thd->lex; - /* Set new LEX as if we at start of set rule. */ - lex->sql_command= SQLCOM_SET_OPTION; - mysql_init_select(lex); - lex->option_type=OPT_SESSION; - lex->var_list.empty(); - lex->one_shot_set= 0; - lex->autocommit= 0; - lex->sphead->m_tmp_query= lip->get_tok_start(); - } +// Start of option value list, option_type was given +start_option_value_list_following_option_type: + option_value_following_option_type + { + if (sp_create_assignment_instr(thd, yychar == YYEMPTY)) + MYSQL_YYABORT; } - ext_option_value + option_value_list_continued + | TRANSACTION_SYM transaction_characteristics { - LEX *lex= thd->lex; - Lex_input_stream *lip= YYLIP; - - if (lex->sphead) - { - sp_head *sp= lex->sphead; + if (sp_create_assignment_instr(thd, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + ; - if (!lex->var_list.is_empty()) - { - /* - We have assignment to user or system variable or - option setting, so we should construct sp_instr_stmt - for it. - */ - LEX_STRING qbuff; - sp_instr_stmt *i; +// Remainder of the option value list after first option value. +option_value_list_continued: + /* empty */ + | ',' option_value_list + ; - if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont, - lex))) - MYSQL_YYABORT; +// Repeating list of option values after first option value. +option_value_list: + { + sp_create_assignment_lex(thd, yychar == YYEMPTY); + } + option_value + { + if (sp_create_assignment_instr(thd, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + | option_value_list ',' + { + sp_create_assignment_lex(thd, yychar == YYEMPTY); + } + option_value + { + if (sp_create_assignment_instr(thd, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + ; - /* - Extract the query statement from the tokenizer. The - end is either lip->ptr, if there was no lookahead, - lip->tok_end otherwise. - */ - if (yychar == YYEMPTY) - qbuff.length= lip->get_ptr() - sp->m_tmp_query; - else - qbuff.length= lip->get_tok_end() - sp->m_tmp_query; - - if (!(qbuff.str= (char*) alloc_root(thd->mem_root, - qbuff.length + 5))) - MYSQL_YYABORT; - - strmake(strmake(qbuff.str, "SET ", 4), sp->m_tmp_query, - qbuff.length); - qbuff.length+= 4; - i->m_query= qbuff; - if (sp->add_instr(i)) - MYSQL_YYABORT; - } - if (lex->sphead->restore_lex(thd)) - MYSQL_YYABORT; - } +// Wrapper around option values following the first option value in the stmt. +option_value: + option_type + { + Lex->option_type= $1; } + option_value_following_option_type + | option_value_no_option_type ; option_type: - option_type2 {} - | GLOBAL_SYM { $$=OPT_GLOBAL; } + GLOBAL_SYM { $$=OPT_GLOBAL; } | LOCAL_SYM { $$=OPT_SESSION; } | SESSION_SYM { $$=OPT_SESSION; } ; -option_type2: - /* empty */ { $$= OPT_DEFAULT; } - | ONE_SHOT_SYM { Lex->one_shot_set= 1; $$= OPT_SESSION; } - ; - opt_var_type: /* empty */ { $$=OPT_SESSION; } | GLOBAL_SYM { $$=OPT_GLOBAL; } @@ -13489,81 +14457,68 @@ opt_var_ident_type: | SESSION_SYM '.' { $$=OPT_SESSION; } ; -ext_option_value: - sys_option_value - | option_type2 option_value +// Option values with preceding option_type. +option_value_following_option_type: + internal_variable_name equal set_expr_or_default + { + LEX *lex= Lex; + + if ($1.var && $1.var != trg_new_row_fake_var) + { + /* It is a system variable. */ + if (set_system_variable(thd, &$1, lex->option_type, $3)) + MYSQL_YYABORT; + } + else + { + /* + Not in trigger assigning value to new row, + and option_type preceding local variable is illegal. + */ + my_parse_error(thd, ER_SYNTAX_ERROR); + MYSQL_YYABORT; + } + } ; -sys_option_value: - option_type internal_variable_name equal set_expr_or_default +// Option values without preceding option_type. +option_value_no_option_type: + internal_variable_name equal set_expr_or_default { LEX *lex= Lex; - LEX_STRING *name= &$2.base_name; - if ($2.var == trg_new_row_fake_var) + if ($1.var == trg_new_row_fake_var) { /* We are in trigger and assigning value to field of new row */ - if ($1) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; - } - if (set_trigger_new_row(thd, name, $4)) + if (set_trigger_new_row(thd, &$1.base_name, $3)) MYSQL_YYABORT; } - else if ($2.var) + else if ($1.var) { - if ($1) - lex->option_type= $1; - /* It is a system variable. */ - if (set_system_variable(thd, &$2, lex->option_type, $4)) + if (set_system_variable(thd, &$1, lex->option_type, $3)) MYSQL_YYABORT; } else { sp_pcontext *spc= lex->spcont; - sp_variable_t *spv= spc->find_variable(name); - - if ($1) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; - } + sp_variable *spv= spc->find_variable($1.base_name, false); /* It is a local variable. */ - if (set_local_variable(thd, spv, $4)) + if (set_local_variable(thd, spv, $3)) MYSQL_YYABORT; } } - | option_type TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types - { - LEX *lex=Lex; - lex->option_type= $1; - Item *item= new (thd->mem_root) Item_int((int32) $5); - if (item == NULL) - MYSQL_YYABORT; - set_var *var= new set_var(lex->option_type, - find_sys_var(thd, "tx_isolation"), - &null_lex_str, - item); - if (var == NULL) - MYSQL_YYABORT; - lex->var_list.push_back(var); - } - ; - -option_value: - '@' ident_or_text equal expr + | '@' ident_or_text equal expr { Item_func_set_user_var *item; - item= new (thd->mem_root) Item_func_set_user_var($2, $4); + item= new (thd->mem_root) Item_func_set_user_var(thd, $2, $4); if (item == NULL) MYSQL_YYABORT; - set_var_user *var= new set_var_user(item); + set_var_user *var= new (thd->mem_root) set_var_user(item); if (var == NULL) MYSQL_YYABORT; - Lex->var_list.push_back(var); + Lex->var_list.push_back(var, thd->mem_root); } | '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default { @@ -13588,12 +14543,13 @@ option_value: CHARSET_INFO *cs2; cs2= $2 ? $2: global_system_variables.character_set_client; set_var_collation_client *var; - var= new set_var_collation_client(cs2, - thd->variables.collation_database, - cs2); + var= (new (thd->mem_root) + set_var_collation_client(cs2, + thd->variables.collation_database, + cs2)); if (var == NULL) MYSQL_YYABORT; - lex->var_list.push_back(var); + lex->var_list.push_back(var, thd->mem_root); } | NAMES_SYM equal expr { @@ -13603,10 +14559,10 @@ option_value: names.str= (char *)"names"; names.length= 5; - if (spc && spc->find_variable(&names)) + if (spc && spc->find_variable(names, false)) my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str); else - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } @@ -13624,57 +14580,71 @@ option_value: MYSQL_YYABORT; } set_var_collation_client *var; - var= new set_var_collation_client(cs3, cs3, cs3); + var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3); if (var == NULL) MYSQL_YYABORT; - lex->var_list.push_back(var); + lex->var_list.push_back(var, thd->mem_root); } - | PASSWORD equal text_or_password + | DEFAULT ROLE_SYM grant_role { - LEX *lex= thd->lex; + LEX *lex = Lex; LEX_USER *user; - sp_pcontext *spc= lex->spcont; - LEX_STRING pw; - - pw.str= (char *)"password"; - pw.length= 8; - if (spc && spc->find_variable(&pw)) - { - my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str); + if (!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER)))) MYSQL_YYABORT; - } - if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))) + user->user= current_user; + set_var_default_role *var= (new (thd->mem_root) + set_var_default_role(user, + $3->user)); + if (var == NULL) MYSQL_YYABORT; - user->host=null_lex_str; - user->user.str=thd->security_ctx->user; - set_var_password *var= new set_var_password(user, $3); + lex->var_list.push_back(var, thd->mem_root); + thd->lex->autocommit= TRUE; + if (lex->sphead) + lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + } + | DEFAULT ROLE_SYM grant_role FOR_SYM user + { + LEX *lex = Lex; + set_var_default_role *var= (new (thd->mem_root) + set_var_default_role($5, $3->user)); if (var == NULL) MYSQL_YYABORT; - thd->lex->var_list.push_back(var); + lex->var_list.push_back(var, thd->mem_root); thd->lex->autocommit= TRUE; if (lex->sphead) lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; } - | PASSWORD FOR_SYM user equal text_or_password + | ROLE_SYM ident_or_text + { + LEX *lex = Lex; + set_var_role *var= new (thd->mem_root) set_var_role($2); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var, thd->mem_root); + } + | PASSWORD_SYM opt_for_user text_or_password { - set_var_password *var= new set_var_password($3,$5); + LEX *lex = Lex; + set_var_password *var= (new (thd->mem_root) + set_var_password(lex->definer)); if (var == NULL) MYSQL_YYABORT; - Lex->var_list.push_back(var); - Lex->autocommit= TRUE; - if (Lex->sphead) - Lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + lex->var_list.push_back(var, thd->mem_root); + lex->autocommit= TRUE; + if (lex->sphead) + lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; } ; + internal_variable_name: ident { sp_pcontext *spc= thd->lex->spcont; - sp_variable_t *spv; + sp_variable *spv; /* Best effort lookup for system variable. */ - if (!spc || !(spv = spc->find_variable(&$1))) + if (!spc || !(spv = spc->find_variable($1, false))) { struct sys_var_with_base tmp= {NULL, $1}; @@ -13699,7 +14669,7 @@ internal_variable_name: LEX *lex= Lex; if (check_reserved_words(&$1)) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER && @@ -13707,10 +14677,7 @@ internal_variable_name: !my_strcasecmp(system_charset_info, $1.str, "OLD"))) { if ($1.str[0]=='O' || $1.str[0]=='o') - { - my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", ""); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", "")); if (lex->trg_chistics.event == TRG_EVENT_DELETE) { my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), @@ -13718,10 +14685,7 @@ internal_variable_name: MYSQL_YYABORT; } if (lex->trg_chistics.action_time == TRG_ACTION_AFTER) - { - my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after "); - MYSQL_YYABORT; - } + my_yyabort_error((ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after ")); /* This special combination will denote field of NEW row */ $$.var= trg_new_row_fake_var; $$.base_name= $3; @@ -13750,6 +14714,54 @@ internal_variable_name: } ; +transaction_characteristics: + transaction_access_mode + | isolation_level + | transaction_access_mode ',' isolation_level + | isolation_level ',' transaction_access_mode + ; + +transaction_access_mode: + transaction_access_mode_types + { + LEX *lex=Lex; + Item *item= new (thd->mem_root) Item_int(thd, (int32) $1); + if (item == NULL) + MYSQL_YYABORT; + set_var *var= (new (thd->mem_root) + set_var(thd, lex->option_type, + find_sys_var(thd, "tx_read_only"), + &null_lex_str, + item)); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var, thd->mem_root); + } + ; + +isolation_level: + ISOLATION LEVEL_SYM isolation_types + { + LEX *lex=Lex; + Item *item= new (thd->mem_root) Item_int(thd, (int32) $3); + if (item == NULL) + MYSQL_YYABORT; + set_var *var= (new (thd->mem_root) + set_var(thd, lex->option_type, + find_sys_var(thd, "tx_isolation"), + &null_lex_str, + item)); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var, thd->mem_root); + } + ; + +transaction_access_mode_types: + READ_SYM ONLY_SYM { $$= true; } + | READ_SYM WRITE_SYM { $$= false; } + ; + isolation_types: READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; } | READ_SYM COMMITTED_SYM { $$= ISO_READ_COMMITTED; } @@ -13757,46 +14769,54 @@ isolation_types: | SERIALIZABLE_SYM { $$= ISO_SERIALIZABLE; } ; -text_or_password: - TEXT_STRING { $$=$1.str;} - | PASSWORD '(' TEXT_STRING ')' +opt_for_user: + equal { - $$= $3.length ? thd->variables.old_passwords ? - Item_func_old_password::alloc(thd, $3.str, $3.length) : - Item_func_password::alloc(thd, $3.str, $3.length) : - $3.str; - if ($$ == NULL) + LEX *lex= thd->lex; + sp_pcontext *spc= lex->spcont; + LEX_STRING pw= { C_STRING_WITH_LEN("password") }; + + if (spc && spc->find_variable(pw, false)) + my_yyabort_error((ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str)); + if (!(lex->definer= (LEX_USER*) thd->calloc(sizeof(LEX_USER)))) MYSQL_YYABORT; + lex->definer->user= current_user; + lex->definer->plugin= empty_lex_str; + lex->definer->auth= empty_lex_str; } - | OLD_PASSWORD '(' TEXT_STRING ')' + | FOR_SYM user equal { Lex->definer= $2; } + ; + +text_or_password: + TEXT_STRING { Lex->definer->pwhash= $1;} + | PASSWORD_SYM '(' TEXT_STRING ')' { Lex->definer->pwtext= $3; } + | OLD_PASSWORD_SYM '(' TEXT_STRING ')' { - $$= $3.length ? Item_func_old_password::alloc(thd, $3.str, - $3.length) : - $3.str; - if ($$ == NULL) - MYSQL_YYABORT; + Lex->definer->pwtext= $3; + Lex->definer->pwhash.str= Item_func_password::alloc(thd, + $3.str, $3.length, Item_func_password::OLD); + Lex->definer->pwhash.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } ; - set_expr_or_default: expr { $$=$1; } | DEFAULT { $$=0; } | ON { - $$=new (thd->mem_root) Item_string("ON", 2, system_charset_info); + $$=new (thd->mem_root) Item_string_sys(thd, "ON", 2); if ($$ == NULL) MYSQL_YYABORT; } | ALL { - $$=new (thd->mem_root) Item_string("ALL", 3, system_charset_info); + $$=new (thd->mem_root) Item_string_sys(thd, "ALL", 3); if ($$ == NULL) MYSQL_YYABORT; } | BINARY { - $$=new (thd->mem_root) Item_string("binary", 6, system_charset_info); + $$=new (thd->mem_root) Item_string_sys(thd, "binary", 6); if ($$ == NULL) MYSQL_YYABORT; } @@ -13810,10 +14830,7 @@ lock: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "LOCK"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "LOCK")); lex->sql_command= SQLCOM_LOCK_TABLES; } table_lock_list @@ -13863,10 +14880,7 @@ unlock: LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "UNLOCK"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "UNLOCK")); lex->sql_command= SQLCOM_UNLOCK_TABLES; } table_or_tables @@ -13882,47 +14896,38 @@ handler: { LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->sql_command = SQLCOM_HA_OPEN; - if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0)) + if (!lex->current_select->add_table_to_list(thd, $2, $4, 0)) MYSQL_YYABORT; } | HANDLER_SYM table_ident_nodb CLOSE_SYM { LEX *lex= Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->sql_command = SQLCOM_HA_CLOSE; - if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) + if (!lex->current_select->add_table_to_list(thd, $2, 0, 0)) MYSQL_YYABORT; } | HANDLER_SYM table_ident_nodb READ_SYM { LEX *lex=Lex; if (lex->sphead) - { - my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); lex->expr_allows_subselect= FALSE; lex->sql_command = SQLCOM_HA_READ; lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ - Item *one= new (thd->mem_root) Item_int((int32) 1); + Item *one= new (thd->mem_root) Item_int(thd, (int32) 1); if (one == NULL) MYSQL_YYABORT; lex->current_select->select_limit= one; lex->current_select->offset_limit= 0; lex->limit_rows_examined= 0; - if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) + if (!lex->current_select->add_table_to_list(thd, $2, 0, 0)) MYSQL_YYABORT; } - handler_read_or_scan where_clause opt_limit_clause + handler_read_or_scan opt_where_clause opt_limit_clause { Lex->expr_allows_subselect= TRUE; /* Stored functions are not supported for HANDLER READ. */ @@ -13955,7 +14960,7 @@ handler_rkey_function: LEX *lex=Lex; lex->ha_read_mode = RKEY; lex->ha_rkey_mode=$1; - if (!(lex->insert_list = new List_item)) + if (!(lex->insert_list= new (thd->mem_root) List_item)) MYSQL_YYABORT; } '(' values ')' @@ -13978,35 +14983,35 @@ revoke: ; revoke_command: - grant_privileges ON opt_table grant_ident FROM user_list + grant_privileges ON opt_table grant_ident FROM user_and_role_list { LEX *lex= Lex; lex->sql_command= SQLCOM_REVOKE; lex->type= 0; } - | grant_privileges ON FUNCTION_SYM grant_ident FROM user_list + | grant_privileges ON FUNCTION_SYM grant_ident FROM user_and_role_list { LEX *lex= Lex; if (lex->columns.elements) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } lex->sql_command= SQLCOM_REVOKE; lex->type= TYPE_ENUM_FUNCTION; } - | grant_privileges ON PROCEDURE_SYM grant_ident FROM user_list + | grant_privileges ON PROCEDURE_SYM grant_ident FROM user_and_role_list { LEX *lex= Lex; if (lex->columns.elements) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } lex->sql_command= SQLCOM_REVOKE; lex->type= TYPE_ENUM_PROCEDURE; } - | ALL opt_privileges ',' GRANT OPTION FROM user_list + | ALL opt_privileges ',' GRANT OPTION FROM user_and_role_list { Lex->sql_command = SQLCOM_REVOKE_ALL; } @@ -14016,9 +15021,22 @@ revoke_command: lex->users_list.push_front ($3); lex->sql_command= SQLCOM_REVOKE; lex->type= TYPE_ENUM_PROXY; - } + } + | admin_option_for_role FROM user_and_role_list + { + Lex->sql_command= SQLCOM_REVOKE_ROLE; + if (Lex->users_list.push_front($1, thd->mem_root)) + MYSQL_YYABORT; + } ; +admin_option_for_role: + ADMIN_SYM OPTION FOR_SYM grant_role + { Lex->with_admin_option= true; $$= $4; } + | grant_role + { Lex->with_admin_option= false; $$= $1; } + ; + grant: GRANT clear_privileges grant_command {} @@ -14038,7 +15056,7 @@ grant_command: LEX *lex= Lex; if (lex->columns.elements) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } lex->sql_command= SQLCOM_GRANT; @@ -14050,7 +15068,7 @@ grant_command: LEX *lex= Lex; if (lex->columns.elements) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } lex->sql_command= SQLCOM_GRANT; @@ -14062,7 +15080,70 @@ grant_command: lex->users_list.push_front ($3); lex->sql_command= SQLCOM_GRANT; lex->type= TYPE_ENUM_PROXY; - } + } + | grant_role TO_SYM grant_list opt_with_admin_option + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_GRANT_ROLE; + /* The first role is the one that is granted */ + if (Lex->users_list.push_front($1, thd->mem_root)) + MYSQL_YYABORT; + } + + ; + +opt_with_admin: + /* nothing */ { Lex->definer = 0; } + | WITH ADMIN_SYM user_or_role { Lex->definer = $3; } + +opt_with_admin_option: + /* nothing */ { Lex->with_admin_option= false; } + | WITH ADMIN_SYM OPTION { Lex->with_admin_option= true; } + +role_list: + grant_role + { + if (Lex->users_list.push_back($1, thd->mem_root)) + MYSQL_YYABORT; + } + | role_list ',' grant_role + { + if (Lex->users_list.push_back($3, thd->mem_root)) + MYSQL_YYABORT; + } + ; + +current_role: + CURRENT_ROLE optional_braces + { + if (!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))) + MYSQL_YYABORT; + $$->user= current_role; + $$->reset_auth(); + } + ; + +grant_role: + ident_or_text + { + CHARSET_INFO *cs= system_charset_info; + /* trim end spaces (as they'll be lost in mysql.user anyway) */ + $1.length= cs->cset->lengthsp(cs, $1.str, $1.length); + $1.str[$1.length] = '\0'; + if ($1.length == 0) + my_yyabort_error((ER_INVALID_ROLE, MYF(0), "")); + if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) + MYSQL_YYABORT; + $$->user = $1; + $$->host= empty_lex_str; + $$->reset_auth(); + + if (check_string_char_length(&$$->user, ER_USERNAME, + username_char_length, + cs, 0)) + MYSQL_YYABORT; + } + | current_role ; opt_table: @@ -14124,7 +15205,7 @@ object_privilege: | SHOW VIEW_SYM { Lex->grant |= SHOW_VIEW_ACL; } | CREATE ROUTINE_SYM { Lex->grant |= CREATE_PROC_ACL; } | ALTER ROUTINE_SYM { Lex->grant |= ALTER_PROC_ACL; } - | CREATE USER { Lex->grant |= CREATE_USER_ACL; } + | CREATE USER_SYM { Lex->grant |= CREATE_USER_ACL; } | EVENT_SYM { Lex->grant |= EVENT_ACL;} | TRIGGER_SYM { Lex->grant |= TRIGGER_ACL; } | CREATE TABLESPACE { Lex->grant |= CREATE_TABLESPACE_ACL; } @@ -14145,30 +15226,21 @@ require_list_element: { LEX *lex=Lex; if (lex->x509_subject) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "SUBJECT"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SUBJECT")); lex->x509_subject=$2.str; } | ISSUER_SYM TEXT_STRING { LEX *lex=Lex; if (lex->x509_issuer) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "ISSUER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "ISSUER")); lex->x509_issuer=$2.str; } | CIPHER_SYM TEXT_STRING { LEX *lex=Lex; if (lex->ssl_cipher) - { - my_error(ER_DUP_ARGUMENT, MYF(0), "CIPHER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CIPHER")); lex->ssl_cipher=$2.str; } ; @@ -14183,11 +15255,7 @@ grant_ident: if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) - { - my_message(ER_ILLEGAL_GRANT_FOR_TABLE, - ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0))); } | ident '.' '*' { @@ -14196,11 +15264,7 @@ grant_ident: if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) - { - my_message(ER_ILLEGAL_GRANT_FOR_TABLE, - ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0))); } | '*' '.' '*' { @@ -14209,16 +15273,12 @@ grant_ident: if (lex->grant == GLOBAL_ACLS) lex->grant= GLOBAL_ACLS & ~GRANT_ACL; else if (lex->columns.elements) - { - my_message(ER_ILLEGAL_GRANT_FOR_TABLE, - ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0)); - MYSQL_YYABORT; - } + my_yyabort_error((ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0))); } | table_ident { LEX *lex=Lex; - if (!lex->current_select->add_table_to_list(lex->thd, $1,NULL, + if (!lex->current_select->add_table_to_list(thd, $1,NULL, TL_OPTION_UPDATING)) MYSQL_YYABORT; if (lex->grant == GLOBAL_ACLS) @@ -14229,12 +15289,12 @@ grant_ident: user_list: user { - if (Lex->users_list.push_back($1)) + if (Lex->users_list.push_back($1, thd->mem_root)) MYSQL_YYABORT; } | user_list ',' user { - if (Lex->users_list.push_back($3)) + if (Lex->users_list.push_back($3, thd->mem_root)) MYSQL_YYABORT; } ; @@ -14242,12 +15302,25 @@ user_list: grant_list: grant_user { - if (Lex->users_list.push_back($1)) + if (Lex->users_list.push_back($1, thd->mem_root)) MYSQL_YYABORT; } | grant_list ',' grant_user { - if (Lex->users_list.push_back($3)) + if (Lex->users_list.push_back($3, thd->mem_root)) + MYSQL_YYABORT; + } + ; + +user_and_role_list: + user_or_role + { + if (Lex->users_list.push_back($1, thd->mem_root)) + MYSQL_YYABORT; + } + | user_and_role_list ',' user_or_role + { + if (Lex->users_list.push_back($3, thd->mem_root)) MYSQL_YYABORT; } ; @@ -14258,35 +15331,15 @@ using_or_as: USING | AS ; grant_user: user IDENTIFIED_SYM BY TEXT_STRING { - $$=$1; $1->password=$4; - if ($4.length) - { - if (thd->variables.old_passwords) - { - char *buff= - (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); - if (buff == NULL) - MYSQL_YYABORT; - my_make_scrambled_password_323(buff, $4.str, $4.length); - $1->password.str= buff; - $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; - } - else - { - char *buff= - (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); - if (buff == NULL) - MYSQL_YYABORT; - my_make_scrambled_password(buff, $4.str, $4.length); - $1->password.str= buff; - $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH; - } - } + $$= $1; + $1->pwtext= $4; + if (Lex->sql_command == SQLCOM_REVOKE) + MYSQL_YYABORT; } - | user IDENTIFIED_SYM BY PASSWORD TEXT_STRING + | user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING { $$= $1; - $1->password= $5; + $1->pwhash= $5; } | user IDENTIFIED_SYM via_or_with ident_or_text { @@ -14300,8 +15353,8 @@ grant_user: $1->plugin= $4; $1->auth= $6; } - | user - { $$= $1; $1->password= null_lex_str; } + | user_or_role + { $$= $1; } ; opt_column_list: @@ -14321,7 +15374,7 @@ column_list: column_list_id: ident { - String *new_str = new (thd->mem_root) String((const char*) $1.str,$1.length,system_charset_info); + String *new_str= new (thd->mem_root) String((const char*) $1.str,$1.length,system_charset_info); if (new_str == NULL) MYSQL_YYABORT; List_iterator <LEX_COLUMN> iter(Lex->columns); @@ -14338,10 +15391,11 @@ column_list_id: point->rights |= lex->which_columns; else { - LEX_COLUMN *col= new LEX_COLUMN (*new_str,lex->which_columns); + LEX_COLUMN *col= (new (thd->mem_root) + LEX_COLUMN(*new_str,lex->which_columns)); if (col == NULL) MYSQL_YYABORT; - lex->columns.push_back(col); + lex->columns.push_back(col, thd->mem_root); } } ; @@ -14407,6 +15461,12 @@ grant_option: lex->mqh.user_conn= $2; lex->mqh.specified_limits|= USER_RESOURCES::USER_CONNECTIONS; } + | MAX_STATEMENT_TIME_SYM NUM_literal + { + LEX *lex=Lex; + lex->mqh.max_statement_time= $2->val_real(); + lex->mqh.specified_limits|= USER_RESOURCES::MAX_STATEMENT_TIME; + } ; begin: @@ -14417,6 +15477,20 @@ begin: lex->start_transaction_opt= 0; } opt_work {} + ; + +compound_statement: + sp_proc_stmt_compound_ok + { + Lex->sql_command= SQLCOM_COMPOUND; + Lex->sphead->set_stmt_end(thd); + Lex->sphead->restore_thd_mem_root(thd); + } + ; + +opt_not: + /* nothing */ { $$= 0; } + | not { $$= 1; } ; opt_work: @@ -14519,14 +15593,13 @@ union_list: ; union_opt: - /* Empty */ { $$= 0; } + opt_union_order_or_limit | union_list { $$= 1; } - | union_order_or_limit { $$= 1; } ; opt_union_order_or_limit: - /* Empty */{ $$= false; } - | union_order_or_limit { $$= true; } + /* Empty */ { $$= 0; } + | union_order_or_limit { $$= 1; } ; union_order_or_limit: @@ -14538,7 +15611,6 @@ union_order_or_limit: SELECT_LEX *fake= unit->fake_select_lex; if (fake) { - unit->global_parameters= fake; fake->no_table_names_allowed= 1; lex->current_select= fake; } @@ -14552,7 +15624,7 @@ union_order_or_limit: ; order_or_limit: - order_clause opt_limit_clause_init + order_clause opt_limit_clause | limit_clause ; @@ -14564,17 +15636,19 @@ union_option: query_specification: SELECT_SYM select_init2_derived - { + table_expression + { $$= Lex->current_select->master_unit()->first_select(); } | '(' select_paren_derived ')' + opt_union_order_or_limit { $$= Lex->current_select->master_unit()->first_select(); } ; query_expression_body: - query_specification opt_union_order_or_limit + query_specification | query_expression_body UNION_SYM union_option { @@ -14582,7 +15656,6 @@ query_expression_body: MYSQL_YYABORT; } query_specification - opt_union_order_or_limit { Lex->pop_context(); $$= $1; @@ -14603,7 +15676,7 @@ subselect_start: if (!lex->expr_allows_subselect || lex->sql_command == (int)SQLCOM_PURGE) { - my_parse_error(ER(ER_SYNTAX_ERROR)); + my_parse_error(thd, ER_SYNTAX_ERROR); MYSQL_YYABORT; } /* @@ -14694,7 +15767,7 @@ view_or_trigger_or_sp_or_event: {} | no_definer no_definer_tail {} - | view_replace_or_algorithm definer_opt view_tail + | view_algorithm definer_opt view_tail {} ; @@ -14741,9 +15814,12 @@ no_definer: ; definer: - DEFINER_SYM '=' user + DEFINER_SYM '=' user_or_role { - thd->lex->definer= get_current_user(thd, $3); + Lex->definer= $3; + Lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; + Lex->ssl_cipher= Lex->x509_subject= Lex->x509_issuer= 0; + bzero(&(Lex->mqh), sizeof(Lex->mqh)); } ; @@ -14753,20 +15829,6 @@ definer: **************************************************************************/ -view_replace_or_algorithm: - view_replace - {} - | view_replace view_algorithm - {} - | view_algorithm - {} - ; - -view_replace: - OR_SYM REPLACE - { Lex->create_view_mode= VIEW_CREATE_OR_REPLACE; } - ; - view_algorithm: ALGORITHM_SYM '=' UNDEFINED_SYM { Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED; } @@ -14786,12 +15848,14 @@ view_suid: ; view_tail: - view_suid VIEW_SYM table_ident + view_suid VIEW_SYM opt_if_not_exists table_ident { LEX *lex= thd->lex; + if (lex->add_create_options_with_check($3)) + MYSQL_YYABORT; lex->sql_command= SQLCOM_CREATE_VIEW; /* first table in list is target VIEW name */ - if (!lex->select_lex.add_table_to_list(thd, $3, NULL, + if (!lex->select_lex.add_table_to_list(thd, $4, NULL, TL_OPTION_UPDATING, TL_IGNORE, MDL_EXCLUSIVE)) @@ -14809,15 +15873,17 @@ view_list_opt: view_list: ident - { - Lex->view_list.push_back((LEX_STRING*) - sql_memdup(&$1, sizeof(LEX_STRING))); - } + { + Lex->view_list.push_back((LEX_STRING*) + thd->memdup(&$1, sizeof(LEX_STRING)), + thd->mem_root); + } | view_list ',' ident - { - Lex->view_list.push_back((LEX_STRING*) - sql_memdup(&$3, sizeof(LEX_STRING))); - } + { + Lex->view_list.push_back((LEX_STRING*) + thd->memdup(&$3, sizeof(LEX_STRING)), + thd->mem_root); + } ; view_select: @@ -14869,52 +15935,46 @@ view_check_option: trigger_tail: TRIGGER_SYM remember_name + opt_if_not_exists + { + if (Lex->add_create_options_with_check($3)) + MYSQL_YYABORT; + } sp_name trg_action_time trg_event ON - remember_name /* $7 */ - { /* $8 */ + remember_name /* $9 */ + { /* $10 */ Lex->raw_trg_on_table_name_begin= YYLIP->get_tok_start(); } - table_ident /* $9 */ + table_ident /* $11 */ FOR_SYM - remember_name /* $11 */ - { /* $12 */ + remember_name /* $13 */ + { /* $14 */ Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start(); } EACH_SYM ROW_SYM - { /* $15 */ + { /* $17 */ LEX *lex= thd->lex; Lex_input_stream *lip= YYLIP; - sp_head *sp; if (lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER"); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER")); - if (!(sp= new sp_head())) - MYSQL_YYABORT; - sp->reset_thd_mem_root(thd); - sp->init(lex); - sp->m_type= TYPE_ENUM_TRIGGER; - sp->init_sp_name(thd, $3); lex->stmt_definition_begin= $2; - lex->ident.str= $7; - lex->ident.length= $11 - $7; + lex->ident.str= $9; + lex->ident.length= $13 - $9; + lex->spname= $5; - lex->sphead= sp; - lex->spname= $3; + if (!make_sp_head(thd, $5, TYPE_ENUM_TRIGGER)) + MYSQL_YYABORT; - bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); - lex->sphead->m_chistics= &lex->sp_chistics; lex->sphead->set_body_start(thd, lip->get_cpp_ptr()); } - sp_proc_stmt /* $16 */ - { /* $17 */ + sp_proc_stmt /* $18 */ + { /* $19 */ LEX *lex= Lex; sp_head *sp= lex->sphead; @@ -14930,7 +15990,7 @@ trigger_tail: sp_proc_stmt alternatives are not saving/restoring LEX, so lex->query_tables can be wiped out. */ - if (!lex->select_lex.add_table_to_list(thd, $9, + if (!lex->select_lex.add_table_to_list(thd, $11, (LEX_STRING*) 0, TL_OPTION_UPDATING, TL_READ_NO_INSERT, @@ -14946,71 +16006,45 @@ trigger_tail: **************************************************************************/ udf_tail: - AGGREGATE_SYM remember_name FUNCTION_SYM ident + AGGREGATE_SYM udf_tail2 { thd->lex->udf.type= UDFTYPE_AGGREGATE; } + | udf_tail2 { thd->lex->udf.type= UDFTYPE_FUNCTION; } + ; + +udf_tail2: + FUNCTION_SYM opt_if_not_exists ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys { LEX *lex= thd->lex; - if (is_native_function(thd, & $4)) - { - my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0), - $4.str); + if (lex->add_create_options_with_check($2)) MYSQL_YYABORT; - } - lex->sql_command = SQLCOM_CREATE_FUNCTION; - lex->udf.type= UDFTYPE_AGGREGATE; - lex->stmt_definition_begin= $2; - lex->udf.name = $4; - lex->udf.returns=(Item_result) $6; - lex->udf.dl=$8.str; - } - | remember_name FUNCTION_SYM ident - RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys - { - LEX *lex= thd->lex; if (is_native_function(thd, & $3)) - { - my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0), - $3.str); - MYSQL_YYABORT; - } - lex->sql_command = SQLCOM_CREATE_FUNCTION; - lex->udf.type= UDFTYPE_FUNCTION; - lex->stmt_definition_begin= $1; - lex->udf.name = $3; - lex->udf.returns=(Item_result) $5; - lex->udf.dl=$7.str; + my_yyabort_error((ER_NATIVE_FCT_NAME_COLLISION, MYF(0), $3.str)); + lex->sql_command= SQLCOM_CREATE_FUNCTION; + lex->udf.name= $3; + lex->udf.returns= (Item_result) $5; + lex->udf.dl= $7.str; } ; sf_tail: - remember_name /* $1 */ - FUNCTION_SYM /* $2 */ + FUNCTION_SYM /* $1 */ + opt_if_not_exists /* $2 */ sp_name /* $3 */ '(' /* $4 */ { /* $5 */ - LEX *lex= thd->lex; + LEX *lex= Lex; Lex_input_stream *lip= YYLIP; - sp_head *sp; const char* tmp_param_begin; - lex->stmt_definition_begin= $1; + if (lex->add_create_options_with_check($2)) + MYSQL_YYABORT; lex->spname= $3; if (lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } - /* Order is important here: new - reset - init */ - sp= new sp_head(); - if (sp == NULL) - MYSQL_YYABORT; - sp->reset_thd_mem_root(thd); - sp->init(lex); - sp->init_sp_name(thd, lex->spname); + my_yyabort_error((ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION")); - sp->m_type= TYPE_ENUM_FUNCTION; - lex->sphead= sp; + if (!make_sp_head(thd, $3, TYPE_ENUM_FUNCTION)) + MYSQL_YYABORT; tmp_param_begin= lip->get_cpp_tok_start(); tmp_param_begin++; @@ -15024,41 +16058,20 @@ sf_tail: RETURNS_SYM /* $9 */ { /* $10 */ LEX *lex= Lex; - lex->charset= NULL; - lex->length= lex->dec= NULL; - lex->interval_list.empty(); - lex->type= 0; - lex->vcol_info= 0; + lex->init_last_field(&lex->sphead->m_return_field_def, NULL, + thd->variables.collation_database); } type_with_opt_collate /* $11 */ { /* $12 */ - LEX *lex= Lex; - sp_head *sp= lex->sphead; - /* - This was disabled in 5.1.12. See bug #20701 - When collation support in SP is implemented, then this test - should be removed. - */ - if (($11 == MYSQL_TYPE_STRING || $11 == MYSQL_TYPE_VARCHAR) - && (lex->type & BINCMP_FLAG)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation"); + if (Lex->sphead->fill_field_definition(thd, Lex, $11, + Lex->last_field)) MYSQL_YYABORT; - } - - if (sp->fill_field_definition(thd, lex, - (enum enum_field_types) $11, - &sp->m_return_field_def)) - MYSQL_YYABORT; - - bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); } sp_c_chistics /* $13 */ { /* $14 */ LEX *lex= thd->lex; Lex_input_stream *lip= YYLIP; - lex->sphead->m_chistics= &lex->sp_chistics; lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); } sp_proc_stmt /* $15 */ @@ -15072,10 +16085,7 @@ sf_tail: lex->sql_command= SQLCOM_CREATE_SPFUNCTION; sp->set_stmt_end(thd); if (!(sp->m_flags & sp_head::HAS_RETURN)) - { - my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str); - MYSQL_YYABORT; - } + my_yyabort_error((ER_SP_NORETURN, MYF(0), sp->m_qname.str)); if (is_native_function(thd, & sp->m_name)) { /* @@ -15094,9 +16104,9 @@ sf_tail: - The user deploys 5.{N+1}. At this point, 'select foo()' means something different, and the user code is most likely broken (it's only safe if the code is 'select db.foo()'). - With a warning printed when the SF is loaded (which has to occur - before the call), the warning will provide a hint explaining - the root cause of a later failure of 'select foo()'. + With a warning printed when the SF is loaded (which has to + occur before the call), the warning will provide a hint + explaining the root cause of a later failure of 'select foo()'. With no warning printed, the user code will fail with no apparent reason. Printing a warning each time db_load_routine is executed for @@ -15106,9 +16116,9 @@ sf_tail: If a collision exists, it should not be silenced but fixed. */ push_warning_printf(thd, - MYSQL_ERROR::WARN_LEVEL_NOTE, + Sql_condition::WARN_LEVEL_NOTE, ER_NATIVE_FCT_NAME_COLLISION, - ER(ER_NATIVE_FCT_NAME_COLLISION), + ER_THD(thd, ER_NATIVE_FCT_NAME_COLLISION), sp->m_name.str); } sp->restore_thd_mem_root(thd); @@ -15116,29 +16126,17 @@ sf_tail: ; sp_tail: - PROCEDURE_SYM remember_name sp_name + PROCEDURE_SYM opt_if_not_exists sp_name { - LEX *lex= Lex; - sp_head *sp; - - if (lex->sphead) - { - my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE"); + if (Lex->add_create_options_with_check($2)) MYSQL_YYABORT; - } - lex->stmt_definition_begin= $2; + if (Lex->sphead) + my_yyabort_error((ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE")); - /* Order is important here: new - reset - init */ - sp= new sp_head(); - if (sp == NULL) + if (!make_sp_head(thd, $3, TYPE_ENUM_PROCEDURE)) MYSQL_YYABORT; - sp->reset_thd_mem_root(thd); - sp->init(lex); - sp->m_type= TYPE_ENUM_PROCEDURE; - sp->init_sp_name(thd, $3); - - lex->sphead= sp; + Lex->spname= $3; } '(' { @@ -15151,17 +16149,11 @@ sp_tail: sp_pdparam_list ')' { - LEX *lex= thd->lex; - - lex->sphead->m_param_end= YYLIP->get_cpp_tok_start(); - bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); + Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start(); } sp_c_chistics { - LEX *lex= thd->lex; - - lex->sphead->m_chistics= &lex->sp_chistics; - lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); + Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); } sp_proc_stmt { |