MDEV-19639 + MDEV-19640 fix + preparatory changes for WL#4179

This patch includes:
- MDEV-19639 sql_mode=ORACLE: Wrong SHOW PROCEDURE output for sysvar:=expr
- MDEV-19640 Wrong SHOW PROCEDURE output for SET GLOBAL sysvar1=expr, sysvar2=expr
- Preparatory refactoring for MySQL WL#4179

Detailed change list:

1. Changing sp_create_assignment_lex() to accept the position
   in the exact query buffer instead of a "bool no_lookahead".
   This actually fixes MDEV-19639.
   In the previous reduction sp_create_assignment_lex() was
   called too late, when the parser went far the from beginning
   of the statement, so only a part of the statement got into
   sp_instr_stmt.

2. Generating "SET" or "SET GLOBAL" inside sp_create_assignment_instr()
   depending on the option type.
   This fixes MDEV-19640.
   In the previous reduction the code passed (through no_lookahead)
   the position of the
   word GLOBAL inside sp_create_assignment_lex(), which
   worked only for the left-most assignment.

3. Fixing the affected rules to use:
   - ident_cli instead of ident
   - ident_cli_set_usual_case instead of ident_set_usual_case

4. Changing the input parameter in:
   - LEX::set_system_variable()
   - LEX::call_statement_start()
   - LEX::set_variable()
   from just LEX_CSTRING to Lex_ident_sys_st for stricter data type constrol:
   to make sure that noone passes an ident_cli
   (a fragment of the original query in the client character set)
   instead of server-side identifier
   (utf8 identifier allocated on THD when needed).

5. Adding Lex_ident_sys() in places where the affected functions are called.

6. Moving all calls of sp_create_assignment_lex() to the places
   just before parsing set_expr_or_default.
   This makes the grammar clearer, because
   sp_create_assignment_lex() and sp_create_assignment_instr()
   now stay near each other, so the balance of LEX's push/pop
   can be read easier.
   This will also help to WL#4179.

7. Adding class sp_lex_set_var
   Moving the initialization code from
   sp_create_assignment_lex() to the constructor of sp_lex_set_var.
   This will also help to WL#4179.

8. Moving a part of the "set" grammar rule into a separate
   rule "set_param".
   This makes the grammar easier to read and removes
   one shift/reduce conflict.
This commit is contained in:
Alexander Barkov 2019-05-31 16:44:17 +04:00
parent f859789e7d
commit bf5a144e16
9 changed files with 639 additions and 331 deletions

View File

@ -847,8 +847,8 @@ drop procedure if exists p_20906_b;
create procedure p_20906_a() SET @a=@a+1, @b=@b+1; create procedure p_20906_a() SET @a=@a+1, @b=@b+1;
show procedure code p_20906_a; show procedure code p_20906_a;
Pos Instruction Pos Instruction
0 stmt 31 "SET @a=@a+1" 0 stmt 31 "SET @a=@a+1"
1 stmt 31 "SET @b=@b+1" 1 stmt 31 "SET @b=@b+1"
set @a=1; set @a=1;
set @b=1; set @b=1;
call p_20906_a(); call p_20906_a();
@ -858,9 +858,9 @@ select @a, @b;
create procedure p_20906_b() SET @a=@a+1, @b=@b+1, @c=@c+1; create procedure p_20906_b() SET @a=@a+1, @b=@b+1, @c=@c+1;
show procedure code p_20906_b; show procedure code p_20906_b;
Pos Instruction Pos Instruction
0 stmt 31 "SET @a=@a+1" 0 stmt 31 "SET @a=@a+1"
1 stmt 31 "SET @b=@b+1" 1 stmt 31 "SET @b=@b+1"
2 stmt 31 "SET @c=@c+1" 2 stmt 31 "SET @c=@c+1"
set @a=1; set @a=1;
set @b=1; set @b=1;
set @c=1; set @c=1;
@ -1328,3 +1328,18 @@ Pos Instruction
4 jump 2 4 jump 2
5 hpop 1 5 hpop 1
drop function f1; drop function f1;
#
# MDEV-19640 Wrong SHOW PROCEDURE output for SET GLOBAL sysvar1=expr, sysvar2=expr
#
CREATE OR REPLACE PROCEDURE p1()
BEGIN
SET GLOBAL max_allowed_packet=16000000, max_error_count=60;
SELECT @@GLOBAL.max_allowed_packet, @@GLOBAL.max_error_count;
END;
$$
SHOW PROCEDURE CODE p1;
Pos Instruction
0 stmt 31 "SET GLOBAL max_allowed_packet=16000000"
1 stmt 31 "SET GLOBAL max_error_count=60"
2 stmt 0 "SELECT @@GLOBAL.max_allowed_packet, @..."
DROP PROCEDURE p1;

View File

@ -946,3 +946,19 @@ end|
delimiter ;| delimiter ;|
show function code f1; show function code f1;
drop function f1; drop function f1;
--echo #
--echo # MDEV-19640 Wrong SHOW PROCEDURE output for SET GLOBAL sysvar1=expr, sysvar2=expr
--echo #
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1()
BEGIN
SET GLOBAL max_allowed_packet=16000000, max_error_count=60;
SELECT @@GLOBAL.max_allowed_packet, @@GLOBAL.max_error_count;
END;
$$
DELIMITER ;$$
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;

View File

@ -1487,3 +1487,30 @@ CALL p1();
x0 x1.a x1.b x0 x1.a x1.b
100 101 102 100 101 102
DROP PROCEDURE p1; DROP PROCEDURE p1;
#
# MDEV-19640 Wrong SHOW PROCEDURE output for SET GLOBAL sysvar1=expr, sysvar2=expr
#
CREATE OR REPLACE PROCEDURE p1() AS
BEGIN
SET GLOBAL max_allowed_packet=16000000, max_error_count=60;
SELECT @@GLOBAL.max_allowed_packet, @@GLOBAL.max_error_count;
END;
$$
SHOW PROCEDURE CODE p1;
Pos Instruction
0 stmt 31 "SET GLOBAL max_allowed_packet=16000000"
1 stmt 31 "SET GLOBAL max_error_count=60"
2 stmt 0 "SELECT @@GLOBAL.max_allowed_packet, @..."
DROP PROCEDURE p1;
#
# MDEV-19639 sql_mode=ORACLE: Wrong SHOW PROCEDURE output for sysvar:=expr
#
CREATE OR REPLACE PROCEDURE p1() AS
BEGIN
max_error_count:=10;
END;
$$
SHOW PROCEDURE CODE p1;
Pos Instruction
0 stmt 31 "max_error_count:=10"
DROP PROCEDURE p1;

View File

@ -1055,3 +1055,34 @@ DELIMITER ;$$
SHOW PROCEDURE CODE p1; SHOW PROCEDURE CODE p1;
CALL p1(); CALL p1();
DROP PROCEDURE p1; DROP PROCEDURE p1;
--echo #
--echo # MDEV-19640 Wrong SHOW PROCEDURE output for SET GLOBAL sysvar1=expr, sysvar2=expr
--echo #
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1() AS
BEGIN
SET GLOBAL max_allowed_packet=16000000, max_error_count=60;
SELECT @@GLOBAL.max_allowed_packet, @@GLOBAL.max_error_count;
END;
$$
DELIMITER ;$$
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
--echo #
--echo # MDEV-19639 sql_mode=ORACLE: Wrong SHOW PROCEDURE output for sysvar:=expr
--echo #
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1() AS
BEGIN
max_error_count:=10;
END;
$$
DELIMITER ;$$
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;

View File

@ -2023,7 +2023,7 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd)
next_state= MY_LEX_HOSTNAME; next_state= MY_LEX_HOSTNAME;
break; break;
} }
yylval->lex_str.str= (char*) get_ptr(); yylval->lex_str.str= (char*) get_ptr() - 1;
yylval->lex_str.length= 1; yylval->lex_str.length= 1;
return((int) '@'); return((int) '@');
case MY_LEX_HOSTNAME: // end '@' of user@hostname case MY_LEX_HOSTNAME: // end '@' of user@hostname
@ -5579,6 +5579,7 @@ void LEX::set_stmt_init()
mysql_init_select(this); mysql_init_select(this);
option_type= OPT_SESSION; option_type= OPT_SESSION;
autocommit= 0; autocommit= 0;
var_list.empty();
}; };
@ -7574,7 +7575,7 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
bool LEX::set_variable(const LEX_CSTRING *name, Item *item) bool LEX::set_variable(const Lex_ident_sys_st *name, Item *item)
{ {
sp_pcontext *ctx; sp_pcontext *ctx;
const Sp_rcontext_handler *rh; const Sp_rcontext_handler *rh;
@ -7588,8 +7589,8 @@ bool LEX::set_variable(const LEX_CSTRING *name, Item *item)
Generate instructions for: Generate instructions for:
SET x.y= expr; SET x.y= expr;
*/ */
bool LEX::set_variable(const LEX_CSTRING *name1, bool LEX::set_variable(const Lex_ident_sys_st *name1,
const LEX_CSTRING *name2, const Lex_ident_sys_st *name2,
Item *item) Item *item)
{ {
const Sp_rcontext_handler *rh; const Sp_rcontext_handler *rh;
@ -7619,10 +7620,10 @@ bool LEX::set_variable(const LEX_CSTRING *name1,
bool LEX::set_default_system_variable(enum_var_type var_type, bool LEX::set_default_system_variable(enum_var_type var_type,
const LEX_CSTRING *name, const Lex_ident_sys_st *name,
Item *val) Item *val)
{ {
static LEX_CSTRING default_base_name= {STRING_WITH_LEN("default")}; static Lex_ident_sys default_base_name= {STRING_WITH_LEN("default")};
sys_var *var= find_sys_var(thd, name->str, name->length); sys_var *var= find_sys_var(thd, name->str, name->length);
if (!var) if (!var)
return true; return true;
@ -7636,18 +7637,19 @@ bool LEX::set_default_system_variable(enum_var_type var_type,
bool LEX::set_system_variable(enum_var_type var_type, bool LEX::set_system_variable(enum_var_type var_type,
const LEX_CSTRING *name, const Lex_ident_sys_st *name,
Item *val) Item *val)
{ {
sys_var *var= find_sys_var(thd, name->str, name->length); sys_var *var= find_sys_var(thd, name->str, name->length);
DBUG_ASSERT(thd->is_error() || var != NULL); DBUG_ASSERT(thd->is_error() || var != NULL);
return likely(var) ? set_system_variable(var_type, var, &null_clex_str, val) : true; static Lex_ident_sys null_str;
return likely(var) ? set_system_variable(var_type, var, &null_str, val) : true;
} }
bool LEX::set_system_variable(THD *thd, enum_var_type var_type, bool LEX::set_system_variable(THD *thd, enum_var_type var_type,
const LEX_CSTRING *name1, const Lex_ident_sys_st *name1,
const LEX_CSTRING *name2, const Lex_ident_sys_st *name2,
Item *val) Item *val)
{ {
sys_var *tmp; sys_var *tmp;
@ -8328,15 +8330,15 @@ bool LEX::call_statement_start(THD *thd, sp_name *name)
} }
bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name) bool LEX::call_statement_start(THD *thd, const Lex_ident_sys_st *name)
{ {
sp_name *spname= make_sp_name(thd, name); sp_name *spname= make_sp_name(thd, name);
return unlikely(!spname) || call_statement_start(thd, spname); return unlikely(!spname) || call_statement_start(thd, spname);
} }
bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name1, bool LEX::call_statement_start(THD *thd, const Lex_ident_sys_st *name1,
const LEX_CSTRING *name2) const Lex_ident_sys_st *name2)
{ {
sp_name *spname= make_sp_name(thd, name1, name2); sp_name *spname= make_sp_name(thd, name1, name2);
return unlikely(!spname) || call_statement_start(thd, spname); return unlikely(!spname) || call_statement_start(thd, spname);

View File

@ -3741,15 +3741,15 @@ public:
bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2, bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
Item *val); Item *val);
bool set_system_variable(enum_var_type var_type, sys_var *var, bool set_system_variable(enum_var_type var_type, sys_var *var,
const LEX_CSTRING *base_name, Item *val); const Lex_ident_sys_st *base_name, Item *val);
bool set_system_variable(enum_var_type var_type, const LEX_CSTRING *name, bool set_system_variable(enum_var_type var_type,
Item *val); const Lex_ident_sys_st *name, Item *val);
bool set_system_variable(THD *thd, enum_var_type var_type, bool set_system_variable(THD *thd, enum_var_type var_type,
const LEX_CSTRING *name1, const Lex_ident_sys_st *name1,
const LEX_CSTRING *name2, const Lex_ident_sys_st *name2,
Item *val); Item *val);
bool set_default_system_variable(enum_var_type var_type, bool set_default_system_variable(enum_var_type var_type,
const LEX_CSTRING *name, const Lex_ident_sys_st *name,
Item *val); Item *val);
bool set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val); bool set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val);
void set_stmt_init(); void set_stmt_init();
@ -3779,9 +3779,9 @@ public:
const char *body_start, const char *body_start,
const char *body_end); const char *body_end);
bool call_statement_start(THD *thd, sp_name *name); bool call_statement_start(THD *thd, sp_name *name);
bool call_statement_start(THD *thd, const LEX_CSTRING *name); bool call_statement_start(THD *thd, const Lex_ident_sys_st *name);
bool call_statement_start(THD *thd, const LEX_CSTRING *name1, bool call_statement_start(THD *thd, const Lex_ident_sys_st *name1,
const LEX_CSTRING *name2); const Lex_ident_sys_st *name2);
sp_variable *find_variable(const LEX_CSTRING *name, sp_variable *find_variable(const LEX_CSTRING *name,
sp_pcontext **ctx, sp_pcontext **ctx,
const Sp_rcontext_handler **rh) const; const Sp_rcontext_handler **rh) const;
@ -3791,9 +3791,9 @@ public:
sp_pcontext *not_used_ctx; sp_pcontext *not_used_ctx;
return find_variable(name, &not_used_ctx, rh); return find_variable(name, &not_used_ctx, rh);
} }
bool set_variable(const LEX_CSTRING *name, Item *item); bool set_variable(const Lex_ident_sys_st *name, Item *item);
bool set_variable(const LEX_CSTRING *name1, const LEX_CSTRING *name2, bool set_variable(const Lex_ident_sys_st *name1,
Item *item); const Lex_ident_sys_st *name2, Item *item);
void sp_variable_declarations_init(THD *thd, int nvars); void sp_variable_declarations_init(THD *thd, int nvars);
bool sp_variable_declarations_finalize(THD *thd, int nvars, bool sp_variable_declarations_finalize(THD *thd, int nvars,
const Column_definition *cdef, const Column_definition *cdef,
@ -4439,6 +4439,12 @@ public:
SELECT_LEX_UNIT *create_unit(SELECT_LEX*); SELECT_LEX_UNIT *create_unit(SELECT_LEX*);
SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit); SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit);
SELECT_LEX *wrap_select_chain_into_derived(SELECT_LEX *sel); SELECT_LEX *wrap_select_chain_into_derived(SELECT_LEX *sel);
void init_select()
{
current_select->init_select();
wild= 0;
exchange= 0;
}
bool main_select_push(); bool main_select_push();
bool insert_select_hack(SELECT_LEX *sel); bool insert_select_hack(SELECT_LEX *sel);
SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest); SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest);
@ -4747,6 +4753,22 @@ public:
}; };
class sp_lex_set_var: public sp_lex_local
{
public:
sp_lex_set_var(THD *thd, const LEX *oldlex)
:sp_lex_local(thd, oldlex)
{
// Set new LEX as if we at start of set rule
init_select();
sql_command= SQLCOM_SET_OPTION;
var_list.empty();
autocommit= 0;
option_type= oldlex->option_type; // Inherit from the outer lex
}
};
/** /**
An assignment specific LEX, which additionally has an Item (an expression) An assignment specific LEX, which additionally has an Item (an expression)
and an associated with the Item free_list, which is usually freed and an associated with the Item free_list, which is usually freed
@ -4826,8 +4848,9 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr);
Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
Item *expr); Item *expr);
void sp_create_assignment_lex(THD *thd, bool no_lookahead); bool sp_create_assignment_lex(THD *thd, const char *pos);
bool sp_create_assignment_instr(THD *thd, bool no_lookahead); bool sp_create_assignment_instr(THD *thd, bool no_lookahead,
bool need_set_keyword= true);
void mark_or_conds_to_avoid_pushdown(Item *cond); void mark_or_conds_to_avoid_pushdown(Item *cond);

View File

@ -7760,10 +7760,7 @@ void THD::reset_for_next_command(bool do_clear_error)
void void
mysql_init_select(LEX *lex) mysql_init_select(LEX *lex)
{ {
SELECT_LEX *select_lex= lex->current_select; lex->init_select();
select_lex->init_select();
lex->wild= 0;
lex->exchange= 0;
} }

View File

@ -289,7 +289,7 @@ int LEX::case_stmt_action_then()
bool bool
LEX::set_system_variable(enum enum_var_type var_type, LEX::set_system_variable(enum enum_var_type var_type,
sys_var *sysvar, const LEX_CSTRING *base_name, sys_var *sysvar, const Lex_ident_sys_st *base_name,
Item *val) Item *val)
{ {
set_var *setvar; set_var *setvar;
@ -506,34 +506,22 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
@see sp_create_assignment_instr @see sp_create_assignment_instr
@param thd Thread context @param thd Thread context
@param no_lookahead True if the parser has no lookahead @param pos The position in the raw SQL buffer
*/ */
void sp_create_assignment_lex(THD *thd, bool no_lookahead)
bool sp_create_assignment_lex(THD *thd, const char *pos)
{ {
LEX *lex= thd->lex; if (thd->lex->sphead)
if (lex->sphead)
{ {
Lex_input_stream *lip= &thd->m_parser_state->m_lip; sp_lex_local *new_lex;
LEX *old_lex= lex; if (!(new_lex= new (thd->mem_root) sp_lex_set_var(thd, thd->lex)) ||
lex->sphead->reset_lex(thd); new_lex->main_select_push())
lex= thd->lex; return true;
new_lex->sphead->m_tmp_query= pos;
/* Set new LEX as if we at start of set rule. */ return thd->lex->sphead->reset_lex(thd, new_lex);
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;
lex->main_select_push();
} }
return false;
} }
@ -542,13 +530,15 @@ void sp_create_assignment_lex(THD *thd, bool no_lookahead)
@see sp_create_assignment_lex @see sp_create_assignment_lex
@param thd Thread context @param thd - Thread context
@param no_lookahead True if the parser has no lookahead @param no_lookahead - True if the parser has no lookahead
@param need_set_keyword - if a SET statement "SET a=10",
or a direct assignment overwise "a:=10"
@return false if success, true otherwise. @return false if success, true otherwise.
*/ */
bool sp_create_assignment_instr(THD *thd, bool no_lookahead) bool sp_create_assignment_instr(THD *thd, bool no_lookahead,
bool need_set_keyword)
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
@ -556,6 +546,24 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
{ {
if (!lex->var_list.is_empty()) if (!lex->var_list.is_empty())
{ {
/*
- Every variable assignment from the same SET command, e.g.:
SET @var1=expr1, @var2=expr2;
produce each own sp_create_assignment_instr() call
lex->var_list.elements is 1 in this case.
- This query:
SET TRANSACTION READ ONLY, ISOLATION LEVEL SERIALIZABLE;
in translated to:
SET tx_read_only=1, tx_isolation=ISO_SERIALIZABLE;
but produces a single sp_create_assignment_instr() call
which includes the query fragment covering both options.
*/
DBUG_ASSERT(lex->var_list.elements >= 1 && lex->var_list.elements <= 2);
/*
sql_mode=ORACLE's direct assignment of a global variable
is not possible by the grammar.
*/
DBUG_ASSERT(Lex->option_type != OPT_GLOBAL || need_set_keyword);
/* /*
We have assignment to user or system variable or We have assignment to user or system variable or
option setting, so we should construct sp_instr_stmt option setting, so we should construct sp_instr_stmt
@ -568,10 +576,15 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
end is either lip->ptr, if there was no lookahead, end is either lip->ptr, if there was no lookahead,
lip->tok_end otherwise. lip->tok_end otherwise.
*/ */
static const LEX_CSTRING setsp= { STRING_WITH_LEN("SET ") }; static const LEX_CSTRING setlc= { STRING_WITH_LEN("SET ") };
static const LEX_CSTRING setgl= { STRING_WITH_LEN("SET GLOBAL ") };
const char *qend= no_lookahead ? lip->get_ptr() : lip->get_tok_end(); const char *qend= no_lookahead ? lip->get_ptr() : lip->get_tok_end();
Lex_cstring qbuf(lex->sphead->m_tmp_query, qend); Lex_cstring qbuf(lex->sphead->m_tmp_query, qend);
if (lex->new_sp_instr_stmt(thd, setsp, qbuf)) if (lex->new_sp_instr_stmt(thd,
Lex->option_type == OPT_GLOBAL ? setgl :
need_set_keyword ? setlc :
null_clex_str,
qbuf))
return true; return true;
} }
lex->pop_select(); lex->pop_select();
@ -820,7 +833,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
Currently there are 48 shift/reduce conflicts. Currently there are 48 shift/reduce conflicts.
We should not introduce new conflicts any more. We should not introduce new conflicts any more.
*/ */
%expect 48 %expect 47
/* /*
Comments for TOKENS. Comments for TOKENS.
@ -842,6 +855,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
*/ */
%token <lex_str> '@'
/* /*
Reserved keywords and operators Reserved keywords and operators
*/ */
@ -874,7 +889,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token CASE_SYM /* SQL-2003-R */ %token CASE_SYM /* SQL-2003-R */
%token CAST_SYM /* SQL-2003-R */ %token CAST_SYM /* SQL-2003-R */
%token CHANGE %token CHANGE
%token CHAR_SYM /* SQL-2003-R */ %token <kwd> CHAR_SYM /* SQL-2003-R */
%token CHECK_SYM /* SQL-2003-R */ %token CHECK_SYM /* SQL-2003-R */
%token COLLATE_SYM /* SQL-2003-R */ %token COLLATE_SYM /* SQL-2003-R */
%token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */ %token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */
@ -903,7 +918,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token DECIMAL_SYM /* SQL-2003-R */ %token DECIMAL_SYM /* SQL-2003-R */
%token DECLARE_MARIADB_SYM /* SQL-2003-R */ %token DECLARE_MARIADB_SYM /* SQL-2003-R */
%token DECLARE_ORACLE_SYM /* Oracle-R */ %token DECLARE_ORACLE_SYM /* Oracle-R */
%token DEFAULT /* SQL-2003-R */ %token <kwd> DEFAULT /* SQL-2003-R */
%token DELETE_DOMAIN_ID_SYM %token DELETE_DOMAIN_ID_SYM
%token DELETE_SYM /* SQL-2003-R */ %token DELETE_SYM /* SQL-2003-R */
%token DENSE_RANK_SYM %token DENSE_RANK_SYM
@ -1748,7 +1763,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
ident ident
label_ident label_ident
sp_decl_ident sp_decl_ident
ident_set_usual_case
ident_or_empty ident_or_empty
ident_table_alias ident_table_alias
ident_sysvar_name ident_sysvar_name
@ -1766,6 +1780,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
IDENT_QUOTED IDENT_QUOTED
IDENT_cli IDENT_cli
ident_cli ident_cli
ident_cli_set_usual_case
%type <kwd> %type <kwd>
keyword_data_type keyword_data_type
@ -1782,6 +1797,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
keyword_sysvar_type keyword_sysvar_type
keyword_table_alias keyword_table_alias
keyword_verb_clause keyword_verb_clause
charset
%type <table> %type <table>
table_ident table_ident_nodb references xid table_ident table_ident_nodb references xid
@ -2070,7 +2086,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
table_to_table_list table_to_table opt_table_list opt_as table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild single_multi table_wild_list table_wild_one opt_wild
opt_and charset opt_and
select_var_list select_var_list_init help select_var_list select_var_list_init help
opt_extended_describe shutdown opt_extended_describe shutdown
opt_format_json opt_format_json
@ -7284,8 +7300,8 @@ type_with_opt_collate:
; ;
charset: charset:
CHAR_SYM SET {} CHAR_SYM SET { $$= $1; }
| CHARSET {} | CHARSET { $$= $1; }
; ;
charset_name: charset_name:
@ -15540,13 +15556,9 @@ ident_table_alias:
} }
; ;
ident_set_usual_case: ident_cli_set_usual_case:
IDENT_sys IDENT_cli { $$= $1; }
| keyword_set_usual_case | keyword_set_usual_case { $$= $1; }
{
if (unlikely($$.copy_keyword(thd, &$1)))
MYSQL_YYABORT;
}
; ;
ident_sysvar_name: ident_sysvar_name:
@ -16256,57 +16268,23 @@ set:
if (lex->main_select_push()) if (lex->main_select_push())
MYSQL_YYABORT; MYSQL_YYABORT;
lex->set_stmt_init(); lex->set_stmt_init();
lex->var_list.empty();
sp_create_assignment_lex(thd, yychar == YYEMPTY);
} }
start_option_value_list set_param
{ {
Lex->pop_select(); //main select Lex->pop_select(); //main select
if (Lex->check_main_unit_semantics()) if (Lex->check_main_unit_semantics())
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| SET STATEMENT_SYM
{
if (Lex->main_select_push())
MYSQL_YYABORT;
Lex->set_stmt_init();
}
set_stmt_option_value_following_option_type_list
{
LEX *lex= Lex;
if (unlikely(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();
Lex->pop_select(); //main select
if (Lex->check_main_unit_semantics())
MYSQL_YYABORT;
}
FOR_SYM verb_clause
{}
; ;
set_stmt_option_value_following_option_type_list: set_param:
/*
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
;
/* Start of option value list */
start_option_value_list:
option_value_no_option_type option_value_no_option_type
{ | option_value_no_option_type ',' option_value_list
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
option_value_list_continued
| TRANSACTION_SYM | TRANSACTION_SYM
{ {
Lex->option_type= OPT_DEFAULT; Lex->option_type= OPT_DEFAULT;
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
} }
transaction_characteristics transaction_characteristics
{ {
@ -16318,49 +16296,50 @@ start_option_value_list:
Lex->option_type= $1; Lex->option_type= $1;
} }
start_option_value_list_following_option_type start_option_value_list_following_option_type
| STATEMENT_SYM
set_stmt_option_list
{
LEX *lex= Lex;
if (unlikely(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();
if (Lex->check_main_unit_semantics())
MYSQL_YYABORT;
}
FOR_SYM verb_clause
; ;
set_stmt_option_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.
*/
set_stmt_option
| set_stmt_option_list ',' set_stmt_option
;
/* Start of option value list, option_type was given */ /* Start of option value list, option_type was given */
start_option_value_list_following_option_type: start_option_value_list_following_option_type:
option_value_following_option_type option_value_following_option_type
| option_value_following_option_type ',' option_value_list
| TRANSACTION_SYM
{
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
transaction_characteristics
{ {
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
option_value_list_continued
| TRANSACTION_SYM transaction_characteristics
{
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
;
/* Remainder of the option value list after first option value. */
option_value_list_continued:
/* empty */
| ',' option_value_list
; ;
/* Repeating list of option values after first option value. */ /* Repeating list of option values after first option value. */
option_value_list: option_value_list:
{
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
option_value option_value
{ | option_value_list ',' option_value
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| option_value_list ','
{
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
option_value
{
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
; ;
/* Wrapper around option values following the first option value in the stmt. */ /* Wrapper around option values following the first option value in the stmt. */
@ -16393,16 +16372,21 @@ opt_var_ident_type:
| SESSION_SYM '.' { $$=OPT_SESSION; } | SESSION_SYM '.' { $$=OPT_SESSION; }
; ;
/* Option values with preceding option_type. */ /*
option_value_following_option_type: SET STATEMENT options do not need their own LEX or Query_arena.
ident equal set_expr_or_default Let's put them to the main ones.
*/
set_stmt_option:
ident_cli equal set_expr_or_default
{ {
if (unlikely(Lex->set_system_variable(Lex->option_type, &$1, $3))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $3)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| ident '.' ident equal set_expr_or_default | ident_cli '.' ident equal set_expr_or_default
{ {
if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &$1, &$3, $5))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $5)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| DEFAULT '.' ident equal set_expr_or_default | DEFAULT '.' ident equal set_expr_or_default
@ -16412,45 +16396,132 @@ option_value_following_option_type:
} }
; ;
/* Option values with preceding option_type. */
option_value_following_option_type:
ident_cli equal
{
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| ident_cli '.' ident equal
{
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $6)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| DEFAULT '.' ident equal
{
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
;
/* Option values without preceding option_type. */ /* Option values without preceding option_type. */
option_value_no_option_type: option_value_no_option_type:
ident_set_usual_case equal set_expr_or_default ident_cli_set_usual_case equal
{ {
if (unlikely(Lex->set_variable(&$1, $3))) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| ident '.' ident equal set_expr_or_default set_expr_or_default
{ {
if (unlikely(Lex->set_variable(&$1, &$3, $5))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_variable(&tmp, $4)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| DEFAULT '.' ident equal set_expr_or_default | ident_cli_set_usual_case '.' ident equal
{ {
if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $5))) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| '@' ident_or_text equal expr set_expr_or_default
{ {
if (unlikely(Lex->set_user_variable(thd, &$2, $4))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_variable(&tmp, &$3, $6)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| '@' '@' opt_var_ident_type ident_sysvar_name equal set_expr_or_default | DEFAULT '.' ident equal
{ {
if (unlikely(Lex->set_system_variable($3, &$4, $6))) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal set_expr_or_default set_expr_or_default
{ {
if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $8))) if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)))
MYSQL_YYABORT;
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| '@' '@' opt_var_ident_type DEFAULT '.' ident equal set_expr_or_default | '@' ident_or_text equal
{ {
if (unlikely(Lex->set_default_system_variable($3, &$6, $8))) if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
expr
{
if (unlikely(Lex->set_user_variable(thd, &$2, $5)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| '@' '@' opt_var_ident_type ident_sysvar_name equal
{
if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
set_expr_or_default
{
if (unlikely(Lex->set_system_variable($3, &$4, $7)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal
{
if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
set_expr_or_default
{
if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $9)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| '@' '@' opt_var_ident_type DEFAULT '.' ident equal
{
if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
set_expr_or_default
{
if (unlikely(Lex->set_default_system_variable($3, &$6, $9)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| charset old_or_new_charset_name_or_default | charset old_or_new_charset_name_or_default
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex= thd->lex; LEX *lex= thd->lex;
CHARSET_INFO *cs2; CHARSET_INFO *cs2;
cs2= $2 ? $2: global_system_variables.character_set_client; cs2= $2 ? $2: global_system_variables.character_set_client;
@ -16462,6 +16533,8 @@ option_value_no_option_type:
if (unlikely(var == NULL)) if (unlikely(var == NULL))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->var_list.push_back(var, thd->mem_root); lex->var_list.push_back(var, thd->mem_root);
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
} }
| NAMES_SYM equal expr | NAMES_SYM equal expr
{ {
@ -16476,6 +16549,8 @@ option_value_no_option_type:
} }
| NAMES_SYM charset_name_or_default opt_collate | NAMES_SYM charset_name_or_default opt_collate
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex= Lex; LEX *lex= Lex;
CHARSET_INFO *cs2; CHARSET_INFO *cs2;
CHARSET_INFO *cs3; CHARSET_INFO *cs3;
@ -16490,11 +16565,14 @@ option_value_no_option_type:
set_var_collation_client *var; set_var_collation_client *var;
var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3); var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3);
if (unlikely(var == NULL) || if (unlikely(var == NULL) ||
unlikely(lex->var_list.push_back(var, thd->mem_root))) unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| DEFAULT ROLE_SYM grant_role | DEFAULT ROLE_SYM grant_role
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex = Lex; LEX *lex = Lex;
LEX_USER *user; LEX_USER *user;
if (unlikely(!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER))))) if (unlikely(!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER)))))
@ -16510,9 +16588,13 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE; thd->lex->autocommit= TRUE;
if (lex->sphead) if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
} }
| DEFAULT ROLE_SYM grant_role FOR_SYM user | DEFAULT ROLE_SYM grant_role FOR_SYM user
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex = Lex; LEX *lex = Lex;
set_var_default_role *var= (new (thd->mem_root) set_var_default_role *var= (new (thd->mem_root)
set_var_default_role($5, $3->user)); set_var_default_role($5, $3->user));
@ -16522,22 +16604,36 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE; thd->lex->autocommit= TRUE;
if (lex->sphead) if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
} }
| ROLE_SYM ident_or_text | ROLE_SYM ident_or_text
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex = Lex; LEX *lex = Lex;
set_var_role *var= new (thd->mem_root) set_var_role($2); set_var_role *var= new (thd->mem_root) set_var_role($2);
if (unlikely(var == NULL) || if (unlikely(var == NULL) ||
unlikely(lex->var_list.push_back(var, thd->mem_root))) unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| ROLE_SYM equal set_expr_or_default | ROLE_SYM equal
{ {
if (unlikely(Lex->set_variable(&$1, $3))) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_variable(&tmp, $4)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| PASSWORD_SYM opt_for_user text_or_password | PASSWORD_SYM opt_for_user text_or_password
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex = Lex; LEX *lex = Lex;
set_var_password *var= (new (thd->mem_root) set_var_password *var= (new (thd->mem_root)
set_var_password(lex->definer)); set_var_password(lex->definer));
@ -16547,6 +16643,8 @@ option_value_no_option_type:
lex->autocommit= TRUE; lex->autocommit= TRUE;
if (lex->sphead) if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
} }
; ;

View File

@ -295,10 +295,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd } %parse-param { THD *thd }
%lex-param { THD *thd } %lex-param { THD *thd }
/* /*
Currently there are 49 shift/reduce conflicts. Currently there are 48 shift/reduce conflicts.
We should not introduce new conflicts any more. We should not introduce new conflicts any more.
*/ */
%expect 49 %expect 48
/* /*
Comments for TOKENS. Comments for TOKENS.
@ -320,6 +320,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
*/ */
%token <lex_str> '@'
/* /*
Reserved keywords and operators Reserved keywords and operators
*/ */
@ -352,7 +354,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token CASE_SYM /* SQL-2003-R */ %token CASE_SYM /* SQL-2003-R */
%token CAST_SYM /* SQL-2003-R */ %token CAST_SYM /* SQL-2003-R */
%token CHANGE %token CHANGE
%token CHAR_SYM /* SQL-2003-R */ %token <kwd> CHAR_SYM /* SQL-2003-R */
%token CHECK_SYM /* SQL-2003-R */ %token CHECK_SYM /* SQL-2003-R */
%token COLLATE_SYM /* SQL-2003-R */ %token COLLATE_SYM /* SQL-2003-R */
%token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */ %token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */
@ -381,7 +383,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token DECIMAL_SYM /* SQL-2003-R */ %token DECIMAL_SYM /* SQL-2003-R */
%token DECLARE_MARIADB_SYM /* SQL-2003-R */ %token DECLARE_MARIADB_SYM /* SQL-2003-R */
%token DECLARE_ORACLE_SYM /* Oracle-R */ %token DECLARE_ORACLE_SYM /* Oracle-R */
%token DEFAULT /* SQL-2003-R */ %token <kwd> DEFAULT /* SQL-2003-R */
%token DELETE_DOMAIN_ID_SYM %token DELETE_DOMAIN_ID_SYM
%token DELETE_SYM /* SQL-2003-R */ %token DELETE_SYM /* SQL-2003-R */
%token DENSE_RANK_SYM %token DENSE_RANK_SYM
@ -1228,7 +1230,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
ident ident
label_ident label_ident
sp_decl_ident sp_decl_ident
ident_set_usual_case
ident_or_empty ident_or_empty
ident_table_alias ident_table_alias
ident_sysvar_name ident_sysvar_name
@ -1247,6 +1248,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
IDENT_QUOTED IDENT_QUOTED
IDENT_cli IDENT_cli
ident_cli ident_cli
ident_cli_set_usual_case
ident_cli_directly_assignable
%type <kwd> %type <kwd>
keyword_data_type keyword_data_type
@ -1264,6 +1267,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
keyword_table_alias keyword_table_alias
keyword_verb_clause keyword_verb_clause
keyword_directly_assignable keyword_directly_assignable
charset
%type <table> %type <table>
table_ident table_ident_nodb references xid table_ident table_ident_nodb references xid
@ -1557,7 +1561,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
table_to_table_list table_to_table opt_table_list opt_as table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild single_multi table_wild_list table_wild_one opt_wild
opt_and charset opt_and
select_var_list select_var_list_init help select_var_list select_var_list_init help
opt_extended_describe shutdown opt_extended_describe shutdown
opt_format_json opt_format_json
@ -4046,16 +4050,18 @@ sp_proc_stmt_if:
sp_statement: sp_statement:
statement statement
| ident_directly_assignable | ident_cli_directly_assignable
{ {
// Direct procedure call (without the CALL keyword) // Direct procedure call (without the CALL keyword)
if (unlikely(Lex->call_statement_start(thd, &$1))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->call_statement_start(thd, &tmp)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
opt_sp_cparam_list opt_sp_cparam_list
| ident_directly_assignable '.' ident | ident_cli_directly_assignable '.' ident
{ {
if (unlikely(Lex->call_statement_start(thd, &$1, &$3))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->call_statement_start(thd, &tmp, &$3)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
opt_sp_cparam_list opt_sp_cparam_list
@ -7385,8 +7391,8 @@ sp_param_type_with_opt_collate:
; ;
charset: charset:
CHAR_SYM SET {} CHAR_SYM SET { $$= $1; }
| CHARSET {} | CHARSET { $$= $1; }
; ;
charset_name: charset_name:
@ -15672,13 +15678,9 @@ ident_table_alias:
} }
; ;
ident_set_usual_case: ident_cli_set_usual_case:
IDENT_sys IDENT_cli { $$= $1; }
| keyword_set_usual_case | keyword_set_usual_case { $$= $1; }
{
if (unlikely($$.copy_keyword(thd, &$1)))
MYSQL_YYABORT;
}
; ;
ident_sysvar_name: ident_sysvar_name:
@ -15715,6 +15717,12 @@ ident_directly_assignable:
; ;
ident_cli_directly_assignable:
IDENT_cli
| keyword_directly_assignable { $$= $1; }
;
label_ident: label_ident:
IDENT_sys IDENT_sys
| keyword_label | keyword_label
@ -16424,107 +16432,23 @@ set:
if (lex->main_select_push()) if (lex->main_select_push())
MYSQL_YYABORT; MYSQL_YYABORT;
lex->set_stmt_init(); lex->set_stmt_init();
lex->var_list.empty();
sp_create_assignment_lex(thd, yychar == YYEMPTY);
} }
start_option_value_list set_param
{ {
Lex->pop_select(); //main select Lex->pop_select(); //main select
if (Lex->check_main_unit_semantics()) if (Lex->check_main_unit_semantics())
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| SET STATEMENT_SYM
{
if (Lex->main_select_push())
MYSQL_YYABORT;
Lex->set_stmt_init();
}
set_stmt_option_value_following_option_type_list
{
LEX *lex= Lex;
if (unlikely(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();
Lex->pop_select(); //main select
if (Lex->check_main_unit_semantics())
MYSQL_YYABORT;
}
FOR_SYM verb_clause
{}
; ;
set_assign: set_param:
ident_directly_assignable SET_VAR
{
LEX *lex=Lex;
lex->set_stmt_init();
lex->var_list.empty();
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
set_expr_or_default
{
if (unlikely(Lex->set_variable(&$1, $4)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| ident_directly_assignable '.' ident SET_VAR
{
LEX *lex=Lex;
lex->set_stmt_init();
lex->var_list.empty();
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
set_expr_or_default
{
LEX *lex= Lex;
DBUG_ASSERT(lex->var_list.is_empty());
if (unlikely(lex->set_variable(&$1, &$3, $6)) ||
unlikely(lex->sphead->restore_lex(thd)))
MYSQL_YYABORT;
}
| COLON_ORACLE_SYM ident '.' ident SET_VAR
{
LEX *lex= Lex;
if (unlikely(!lex->is_trigger_new_or_old_reference(&$2)))
{
thd->parse_error(ER_SYNTAX_ERROR, $1.pos());
MYSQL_YYABORT;
}
lex->set_stmt_init();
lex->var_list.empty();
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
set_expr_or_default
{
LEX_CSTRING tmp= { $2.str, $2.length };
if (unlikely(Lex->set_trigger_field(&tmp, &$4, $7)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
;
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
;
/* Start of option value list */
start_option_value_list:
option_value_no_option_type option_value_no_option_type
{ | option_value_no_option_type ',' option_value_list
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
option_value_list_continued
| TRANSACTION_SYM | TRANSACTION_SYM
{ {
Lex->option_type= OPT_DEFAULT; Lex->option_type= OPT_DEFAULT;
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
} }
transaction_characteristics transaction_characteristics
{ {
@ -16536,49 +16460,105 @@ start_option_value_list:
Lex->option_type= $1; Lex->option_type= $1;
} }
start_option_value_list_following_option_type start_option_value_list_following_option_type
| STATEMENT_SYM
set_stmt_option_list
{
LEX *lex= Lex;
if (unlikely(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();
if (Lex->check_main_unit_semantics())
MYSQL_YYABORT;
}
FOR_SYM verb_clause
; ;
set_assign:
ident_cli_directly_assignable SET_VAR
{
LEX *lex=Lex;
lex->set_stmt_init();
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_variable(&tmp, $4)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
false)))
MYSQL_YYABORT;
}
| ident_cli_directly_assignable '.' ident SET_VAR
{
LEX *lex=Lex;
lex->set_stmt_init();
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
LEX *lex= Lex;
DBUG_ASSERT(lex->var_list.is_empty());
Lex_ident_sys tmp(thd, &$1);
if (unlikely(lex->set_variable(&tmp, &$3, $6)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
false)))
MYSQL_YYABORT;
}
| COLON_ORACLE_SYM ident '.' ident SET_VAR
{
LEX *lex= Lex;
if (unlikely(!lex->is_trigger_new_or_old_reference(&$2)))
{
thd->parse_error(ER_SYNTAX_ERROR, $1.pos());
MYSQL_YYABORT;
}
lex->set_stmt_init();
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
LEX_CSTRING tmp= { $2.str, $2.length };
if (unlikely(Lex->set_trigger_field(&tmp, &$4, $7)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
false)))
MYSQL_YYABORT;
}
;
set_stmt_option_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.
*/
set_stmt_option
| set_stmt_option_list ',' set_stmt_option
;
/* Start of option value list, option_type was given */ /* Start of option value list, option_type was given */
start_option_value_list_following_option_type: start_option_value_list_following_option_type:
option_value_following_option_type option_value_following_option_type
| option_value_following_option_type ',' option_value_list
| TRANSACTION_SYM
{
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
transaction_characteristics
{ {
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
option_value_list_continued
| TRANSACTION_SYM transaction_characteristics
{
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
;
/* Remainder of the option value list after first option value. */
option_value_list_continued:
/* empty */
| ',' option_value_list
; ;
/* Repeating list of option values after first option value. */ /* Repeating list of option values after first option value. */
option_value_list: option_value_list:
{
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
option_value option_value
{ | option_value_list ',' option_value
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| option_value_list ','
{
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
option_value
{
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
; ;
/* Wrapper around option values following the first option value in the stmt. */ /* Wrapper around option values following the first option value in the stmt. */
@ -16611,16 +16591,21 @@ opt_var_ident_type:
| SESSION_SYM '.' { $$=OPT_SESSION; } | SESSION_SYM '.' { $$=OPT_SESSION; }
; ;
/* Option values with preceding option_type. */ /*
option_value_following_option_type: SET STATEMENT options do not need their own LEX or Query_arena.
ident equal set_expr_or_default Let's put them to the main ones.
*/
set_stmt_option:
ident_cli equal set_expr_or_default
{ {
if (unlikely(Lex->set_system_variable(Lex->option_type, &$1, $3))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $3)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| ident '.' ident equal set_expr_or_default | ident_cli '.' ident equal set_expr_or_default
{ {
if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &$1, &$3, $5))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $5)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| DEFAULT '.' ident equal set_expr_or_default | DEFAULT '.' ident equal set_expr_or_default
@ -16630,45 +16615,132 @@ option_value_following_option_type:
} }
; ;
/* Option values with preceding option_type. */
option_value_following_option_type:
ident_cli equal
{
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| ident_cli '.' ident equal
{
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $6)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| DEFAULT '.' ident equal
{
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
;
/* Option values without preceding option_type. */ /* Option values without preceding option_type. */
option_value_no_option_type: option_value_no_option_type:
ident_set_usual_case equal set_expr_or_default ident_cli_set_usual_case equal
{ {
if (unlikely(Lex->set_variable(&$1, $3))) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| ident '.' ident equal set_expr_or_default set_expr_or_default
{ {
if (unlikely(Lex->set_variable(&$1, &$3, $5))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_variable(&tmp, $4)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| DEFAULT '.' ident equal set_expr_or_default | ident_cli_set_usual_case '.' ident equal
{ {
if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $5))) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| '@' ident_or_text equal expr set_expr_or_default
{ {
if (unlikely(Lex->set_user_variable(thd, &$2, $4))) Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_variable(&tmp, &$3, $6)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| '@' '@' opt_var_ident_type ident_sysvar_name equal set_expr_or_default | DEFAULT '.' ident equal
{ {
if (unlikely(Lex->set_system_variable($3, &$4, $6))) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal set_expr_or_default set_expr_or_default
{ {
if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $8))) if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)))
MYSQL_YYABORT;
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| '@' '@' opt_var_ident_type DEFAULT '.' ident equal set_expr_or_default | '@' ident_or_text equal
{ {
if (unlikely(Lex->set_default_system_variable($3, &$6, $8))) if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
expr
{
if (unlikely(Lex->set_user_variable(thd, &$2, $5)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| '@' '@' opt_var_ident_type ident_sysvar_name equal
{
if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
set_expr_or_default
{
if (unlikely(Lex->set_system_variable($3, &$4, $7)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal
{
if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
set_expr_or_default
{
if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $9)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| '@' '@' opt_var_ident_type DEFAULT '.' ident equal
{
if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
set_expr_or_default
{
if (unlikely(Lex->set_default_system_variable($3, &$6, $9)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| charset old_or_new_charset_name_or_default | charset old_or_new_charset_name_or_default
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex= thd->lex; LEX *lex= thd->lex;
CHARSET_INFO *cs2; CHARSET_INFO *cs2;
cs2= $2 ? $2: global_system_variables.character_set_client; cs2= $2 ? $2: global_system_variables.character_set_client;
@ -16680,6 +16752,8 @@ option_value_no_option_type:
if (unlikely(var == NULL)) if (unlikely(var == NULL))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->var_list.push_back(var, thd->mem_root); lex->var_list.push_back(var, thd->mem_root);
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
} }
| NAMES_SYM equal expr | NAMES_SYM equal expr
{ {
@ -16694,6 +16768,8 @@ option_value_no_option_type:
} }
| NAMES_SYM charset_name_or_default opt_collate | NAMES_SYM charset_name_or_default opt_collate
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex= Lex; LEX *lex= Lex;
CHARSET_INFO *cs2; CHARSET_INFO *cs2;
CHARSET_INFO *cs3; CHARSET_INFO *cs3;
@ -16708,11 +16784,14 @@ option_value_no_option_type:
set_var_collation_client *var; set_var_collation_client *var;
var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3); var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3);
if (unlikely(var == NULL) || if (unlikely(var == NULL) ||
unlikely(lex->var_list.push_back(var, thd->mem_root))) unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| DEFAULT ROLE_SYM grant_role | DEFAULT ROLE_SYM grant_role
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex = Lex; LEX *lex = Lex;
LEX_USER *user; LEX_USER *user;
if (unlikely(!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER))))) if (unlikely(!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER)))))
@ -16728,9 +16807,13 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE; thd->lex->autocommit= TRUE;
if (lex->sphead) if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
} }
| DEFAULT ROLE_SYM grant_role FOR_SYM user | DEFAULT ROLE_SYM grant_role FOR_SYM user
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex = Lex; LEX *lex = Lex;
set_var_default_role *var= (new (thd->mem_root) set_var_default_role *var= (new (thd->mem_root)
set_var_default_role($5, $3->user)); set_var_default_role($5, $3->user));
@ -16740,22 +16823,36 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE; thd->lex->autocommit= TRUE;
if (lex->sphead) if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
} }
| ROLE_SYM ident_or_text | ROLE_SYM ident_or_text
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex = Lex; LEX *lex = Lex;
set_var_role *var= new (thd->mem_root) set_var_role($2); set_var_role *var= new (thd->mem_root) set_var_role($2);
if (unlikely(var == NULL) || if (unlikely(var == NULL) ||
unlikely(lex->var_list.push_back(var, thd->mem_root))) unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| ROLE_SYM equal set_expr_or_default | ROLE_SYM equal
{ {
if (unlikely(Lex->set_variable(&$1, $3))) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
set_expr_or_default
{
Lex_ident_sys tmp(thd, &$1);
if (unlikely(Lex->set_variable(&tmp, $4)) ||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| PASSWORD_SYM opt_for_user text_or_password | PASSWORD_SYM opt_for_user text_or_password
{ {
if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
LEX *lex = Lex; LEX *lex = Lex;
set_var_password *var= (new (thd->mem_root) set_var_password *var= (new (thd->mem_root)
set_var_password(lex->definer)); set_var_password(lex->definer));
@ -16765,6 +16862,8 @@ option_value_no_option_type:
lex->autocommit= TRUE; lex->autocommit= TRUE;
if (lex->sphead) if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
} }
; ;