Commit af7f287b authored by halfspawn's avatar halfspawn Committed by Alexander Barkov

MDEV-10697 GOTO statement

parent d836f52b
This diff is collapsed.
This diff is collapsed.
...@@ -261,6 +261,7 @@ static SYMBOL symbols[] = { ...@@ -261,6 +261,7 @@ static SYMBOL symbols[] = {
{ "GET_FORMAT", SYM(GET_FORMAT)}, { "GET_FORMAT", SYM(GET_FORMAT)},
{ "GET", SYM(GET_SYM)}, { "GET", SYM(GET_SYM)},
{ "GLOBAL", SYM(GLOBAL_SYM)}, { "GLOBAL", SYM(GLOBAL_SYM)},
{ "GOTO", SYM(GOTO_SYM)},
{ "GRANT", SYM(GRANT)}, { "GRANT", SYM(GRANT)},
{ "GRANTS", SYM(GRANTS)}, { "GRANTS", SYM(GRANTS)},
{ "GROUP", SYM(GROUP_SYM)}, { "GROUP", SYM(GROUP_SYM)},
......
...@@ -556,6 +556,7 @@ sp_head::sp_head() ...@@ -556,6 +556,7 @@ sp_head::sp_head()
DBUG_ENTER("sp_head::sp_head"); DBUG_ENTER("sp_head::sp_head");
m_backpatch.empty(); m_backpatch.empty();
m_backpatch_goto.empty();
m_cont_backpatch.empty(); m_cont_backpatch.empty();
m_lex.empty(); m_lex.empty();
my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
...@@ -2212,7 +2213,8 @@ sp_head::merge_lex(THD *thd, LEX *oldlex, LEX *sublex) ...@@ -2212,7 +2213,8 @@ sp_head::merge_lex(THD *thd, LEX *oldlex, LEX *sublex)
Put the instruction on the backpatch list, associated with the label. Put the instruction on the backpatch list, associated with the label.
*/ */
int int
sp_head::push_backpatch(THD *thd, sp_instr *i, sp_label *lab) sp_head::push_backpatch(THD *thd, sp_instr *i, sp_label *lab,
List<bp_t> *list, backpatch_instr_type itype)
{ {
bp_t *bp= (bp_t *) thd->alloc(sizeof(bp_t)); bp_t *bp= (bp_t *) thd->alloc(sizeof(bp_t));
...@@ -2220,7 +2222,45 @@ sp_head::push_backpatch(THD *thd, sp_instr *i, sp_label *lab) ...@@ -2220,7 +2222,45 @@ sp_head::push_backpatch(THD *thd, sp_instr *i, sp_label *lab)
return 1; return 1;
bp->lab= lab; bp->lab= lab;
bp->instr= i; bp->instr= i;
return m_backpatch.push_front(bp); bp->instr_type= itype;
return list->push_front(bp);
}
int
sp_head::push_backpatch(THD *thd, sp_instr *i, sp_label *lab)
{
return push_backpatch(thd, i, lab, &m_backpatch, GOTO);
}
int
sp_head::push_backpatch_goto(THD *thd, sp_pcontext *ctx, sp_label *lab)
{
uint ip= instructions();
/*
Add cpop/hpop : they will be removed or updated later if target is in
the same block or not
*/
sp_instr_hpop *hpop= new (thd->mem_root) sp_instr_hpop(ip++, ctx, 0);
if (hpop == NULL || add_instr(hpop))
return true;
if (push_backpatch(thd, hpop, lab, &m_backpatch_goto, HPOP))
return true;
sp_instr_cpop *cpop= new (thd->mem_root) sp_instr_cpop(ip++, ctx, 0);
if (cpop == NULL || add_instr(cpop))
return true;
if (push_backpatch(thd, cpop, lab, &m_backpatch_goto, CPOP))
return true;
// Add jump with ip=0. IP will be updated when label is found.
sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, ctx);
if (i == NULL || add_instr(i))
return true;
if (push_backpatch(thd, i, lab, &m_backpatch_goto, GOTO))
return true;
return false;
} }
/** /**
...@@ -2247,6 +2287,97 @@ sp_head::backpatch(sp_label *lab) ...@@ -2247,6 +2287,97 @@ sp_head::backpatch(sp_label *lab)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
void
sp_head::backpatch_goto(THD *thd, sp_label *lab,sp_label *lab_begin_block)
{
bp_t *bp;
uint dest= instructions();
List_iterator<bp_t> li(m_backpatch_goto);
DBUG_ENTER("sp_head::backpatch_goto");
while ((bp= li++))
{
if (bp->instr->m_ip < lab_begin_block->ip || bp->instr->m_ip > lab->ip)
{
/*
Update only jump target from the beginning of the block where the
label is defined.
*/
continue;
}
if (my_strcasecmp(system_charset_info,
bp->lab->name.str,
lab->name.str) == 0)
{
if (bp->instr_type == GOTO)
{
DBUG_PRINT("info",
("backpatch_goto: (m_ip %d, label 0x%lx <%s>) to dest %d",
bp->instr->m_ip, (ulong) lab, lab->name.str, dest));
bp->instr->backpatch(dest, lab->ctx);
// Jump resolved, remove from the list
li.remove();
continue;
}
if (bp->instr_type == CPOP)
{
int n= lab->ctx->diff_cursors(lab_begin_block->ctx, true);
if (n == 0)
{
// Remove cpop instr
replace_instr_to_nop(thd,bp->instr->m_ip);
}
else
{
// update count of cpop
static_cast<sp_instr_cpop*>(bp->instr)->update_count(n);
n= 1;
}
li.remove();
continue;
}
if (bp->instr_type == HPOP)
{
int n= lab->ctx->diff_handlers(lab_begin_block->ctx, true);
if (n == 0)
{
// Remove hpop instr
replace_instr_to_nop(thd,bp->instr->m_ip);
}
else
{
// update count of cpop
static_cast<sp_instr_hpop*>(bp->instr)->update_count(n);
n= 1;
}
li.remove();
continue;
}
}
}
DBUG_VOID_RETURN;
}
bool
sp_head::check_unresolved_goto()
{
DBUG_ENTER("sp_head::check_unresolved_goto");
bool has_unresolved_label=false;
if (m_backpatch_goto.elements > 0)
{
List_iterator_fast<bp_t> li(m_backpatch_goto);
bp_t *bp;
while ((bp= li++))
{
if ((bp->instr_type == GOTO))
{
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "GOTO", bp->lab->name);
has_unresolved_label=true;
}
}
}
DBUG_RETURN(has_unresolved_label);
}
int int
sp_head::new_cont_backpatch(sp_instr_opt_meta *i) sp_head::new_cont_backpatch(sp_instr_opt_meta *i)
......
...@@ -516,11 +516,19 @@ class sp_head :private Query_arena, ...@@ -516,11 +516,19 @@ class sp_head :private Query_arena,
/// Put the instruction on the backpatch list, associated with the label. /// Put the instruction on the backpatch list, associated with the label.
int int
push_backpatch(THD *thd, sp_instr *, sp_label *); push_backpatch(THD *thd, sp_instr *, sp_label *);
int
push_backpatch_goto(THD *thd, sp_pcontext *ctx, sp_label *lab);
/// Update all instruction with this label in the backpatch list to /// Update all instruction with this label in the backpatch list to
/// the current position. /// the current position.
void void
backpatch(sp_label *); backpatch(sp_label *);
void
backpatch_goto(THD *thd, sp_label *, sp_label *);
/// Check for unresolved goto label
bool
check_unresolved_goto();
/// Start a new cont. backpatch level. If 'i' is NULL, the level is just incr. /// Start a new cont. backpatch level. If 'i' is NULL, the level is just incr.
int int
...@@ -695,12 +703,17 @@ class sp_head :private Query_arena, ...@@ -695,12 +703,17 @@ class sp_head :private Query_arena,
sp_pcontext *m_pcont; ///< Parse context sp_pcontext *m_pcont; ///< Parse context
List<LEX> m_lex; ///< Temp. store for the other lex List<LEX> m_lex; ///< Temp. store for the other lex
DYNAMIC_ARRAY m_instr; ///< The "instructions" DYNAMIC_ARRAY m_instr; ///< The "instructions"
enum backpatch_instr_type { GOTO, CPOP, HPOP };
typedef struct typedef struct
{ {
sp_label *lab; sp_label *lab;
sp_instr *instr; sp_instr *instr;
backpatch_instr_type instr_type;
} bp_t; } bp_t;
List<bp_t> m_backpatch; ///< Instructions needing backpatching List<bp_t> m_backpatch; ///< Instructions needing backpatching
List<bp_t> m_backpatch_goto; // Instructions needing backpatching (for goto)
/** /**
We need a special list for backpatching of instructions with a continue We need a special list for backpatching of instructions with a continue
destination (in the case of a continue handler catching an error in destination (in the case of a continue handler catching an error in
...@@ -738,6 +751,12 @@ class sp_head :private Query_arena, ...@@ -738,6 +751,12 @@ class sp_head :private Query_arena,
by routine. by routine.
*/ */
bool merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check); bool merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check);
/// Put the instruction on the a backpatch list, associated with the label.
int
push_backpatch(THD *thd, sp_instr *, sp_label *, List<bp_t> *list,
backpatch_instr_type itype);
}; // class sp_head : public Sql_alloc }; // class sp_head : public Sql_alloc
...@@ -1359,6 +1378,11 @@ class sp_instr_hpop : public sp_instr ...@@ -1359,6 +1378,11 @@ class sp_instr_hpop : public sp_instr
virtual ~sp_instr_hpop() virtual ~sp_instr_hpop()
{} {}
void update_count(uint count)
{
m_count= count;
}
virtual int execute(THD *thd, uint *nextp); virtual int execute(THD *thd, uint *nextp);
virtual void print(String *str); virtual void print(String *str);
...@@ -1451,6 +1475,11 @@ class sp_instr_cpop : public sp_instr ...@@ -1451,6 +1475,11 @@ class sp_instr_cpop : public sp_instr
virtual ~sp_instr_cpop() virtual ~sp_instr_cpop()
{} {}
void update_count(uint count)
{
m_count= count;
}
virtual int execute(THD *thd, uint *nextp); virtual int execute(THD *thd, uint *nextp);
virtual void print(String *str); virtual void print(String *str);
......
...@@ -87,6 +87,7 @@ void sp_pcontext::init(uint var_offset, ...@@ -87,6 +87,7 @@ void sp_pcontext::init(uint var_offset,
m_num_case_exprs= num_case_expressions; m_num_case_exprs= num_case_expressions;
m_labels.empty(); m_labels.empty();
m_goto_labels.empty();
} }
...@@ -129,6 +130,12 @@ sp_pcontext *sp_pcontext::push_context(THD *thd, sp_pcontext::enum_scope scope) ...@@ -129,6 +130,12 @@ sp_pcontext *sp_pcontext::push_context(THD *thd, sp_pcontext::enum_scope scope)
} }
bool cmp_labels(sp_label *a, sp_label *b)
{
return (my_strcasecmp(system_charset_info, a->name.str, b->name.str) == 0
&& a->type == b->type);
}
sp_pcontext *sp_pcontext::pop_context() sp_pcontext *sp_pcontext::pop_context()
{ {
m_parent->m_max_var_index+= m_max_var_index; m_parent->m_max_var_index+= m_max_var_index;
...@@ -140,6 +147,18 @@ sp_pcontext *sp_pcontext::pop_context() ...@@ -140,6 +147,18 @@ sp_pcontext *sp_pcontext::pop_context()
if (m_num_case_exprs > m_parent->m_num_case_exprs) if (m_num_case_exprs > m_parent->m_num_case_exprs)
m_parent->m_num_case_exprs= m_num_case_exprs; m_parent->m_num_case_exprs= m_num_case_exprs;
/*
** Push unresolved goto label to parent context
*/
sp_label *label;
List_iterator_fast<sp_label> li(m_goto_labels);
while ((label= li++))
{
if (label->ip == 0)
{
m_parent->m_goto_labels.add_unique(label, &cmp_labels);
}
}
return m_parent; return m_parent;
} }
...@@ -227,9 +246,9 @@ sp_variable *sp_pcontext::add_variable(THD *thd, LEX_STRING name) ...@@ -227,9 +246,9 @@ sp_variable *sp_pcontext::add_variable(THD *thd, LEX_STRING name)
return m_vars.append(p) ? NULL : p; return m_vars.append(p) ? NULL : p;
} }
sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip, sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip,
sp_label::enum_type type) sp_label::enum_type type,
List<sp_label> *list)
{ {
sp_label *label= sp_label *label=
new (thd->mem_root) sp_label(name, ip, type, this); new (thd->mem_root) sp_label(name, ip, type, this);
...@@ -237,11 +256,47 @@ sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip, ...@@ -237,11 +256,47 @@ sp_label *sp_pcontext::push_label(THD *thd, LEX_STRING name, uint ip,
if (!label) if (!label)
return NULL; return NULL;
m_labels.push_front(label, thd->mem_root); list->push_front(label, thd->mem_root);
return label; return label;
} }
sp_label *sp_pcontext::find_goto_label(const LEX_STRING name, bool recusive)
{
List_iterator_fast<sp_label> li(m_goto_labels);
sp_label *lab;
while ((lab= li++))
{
if (my_strcasecmp(system_charset_info, name.str, lab->name.str) == 0)
return lab;
}
if (!recusive)
return NULL;
/*
Note about exception handlers.
See SQL:2003 SQL/PSM (ISO/IEC 9075-4:2003),
section 13.1 <compound statement>,
syntax rule 4.
In short, a DECLARE HANDLER block can not refer
to labels from the parent context, as they are out of scope.
*/
if (m_scope == HANDLER_SCOPE && m_parent)
{
if (m_parent->m_parent)
{
// Skip the parent context
return m_parent->m_parent->find_goto_label(name);
}
}
return m_parent && (m_scope == REGULAR_SCOPE) ?
m_parent->find_goto_label(name) :
NULL;
}
sp_label *sp_pcontext::find_label(const LEX_STRING name) sp_label *sp_pcontext::find_label(const LEX_STRING name)
{ {
......
...@@ -94,6 +94,7 @@ class sp_variable : public Sql_alloc ...@@ -94,6 +94,7 @@ class sp_variable : public Sql_alloc
/// IF/WHILE/REPEAT/LOOP, when such statement is rewritten into a /// IF/WHILE/REPEAT/LOOP, when such statement is rewritten into a
/// combination of low-level jump/jump_if instructions and labels. /// combination of low-level jump/jump_if instructions and labels.
class sp_label : public Sql_alloc class sp_label : public Sql_alloc
{ {
public: public:
...@@ -106,7 +107,10 @@ class sp_label : public Sql_alloc ...@@ -106,7 +107,10 @@ class sp_label : public Sql_alloc
BEGIN, BEGIN,
/// Label at iteration control /// Label at iteration control
ITERATION ITERATION,
/// Label for jump
GOTO
}; };
/// Name of the label. /// Name of the label.
...@@ -132,6 +136,7 @@ class sp_label : public Sql_alloc ...@@ -132,6 +136,7 @@ class sp_label : public Sql_alloc
{ } { }
}; };
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/// This class represents condition-value term in DECLARE CONDITION or /// This class represents condition-value term in DECLARE CONDITION or
...@@ -507,15 +512,29 @@ class sp_pcontext : public Sql_alloc ...@@ -507,15 +512,29 @@ class sp_pcontext : public Sql_alloc
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
sp_label *push_label(THD *thd, const LEX_STRING name, uint ip, sp_label *push_label(THD *thd, const LEX_STRING name, uint ip,
sp_label::enum_type type); sp_label::enum_type type, List<sp_label> * list);
sp_label *push_label(THD *thd, LEX_STRING name, uint ip,
sp_label::enum_type type)
{ return push_label(thd, name, ip, type, &m_labels); }
sp_label *push_goto_label(THD *thd, LEX_STRING name, uint ip,
sp_label::enum_type type)
{ return push_label(thd, name, ip, type, &m_goto_labels); }
sp_label *push_label(THD *thd, const LEX_STRING name, uint ip) sp_label *push_label(THD *thd, const LEX_STRING name, uint ip)
{ { return push_label(thd, name, ip, sp_label::IMPLICIT); }
return push_label(thd, name, ip, sp_label::IMPLICIT);
} sp_label *push_goto_label(THD *thd, const LEX_STRING name, uint ip)
{ return push_goto_label(thd, name, ip, sp_label::GOTO); }
sp_label *find_label(const LEX_STRING name); sp_label *find_label(const LEX_STRING name);
sp_label *find_goto_label(const LEX_STRING name, bool recusive);
sp_label *find_goto_label(const LEX_STRING name)
{ return find_goto_label(name, true); }
sp_label *find_label_current_loop_start(); sp_label *find_label_current_loop_start();
sp_label *last_label() sp_label *last_label()
...@@ -528,6 +547,11 @@ class sp_pcontext : public Sql_alloc ...@@ -528,6 +547,11 @@ class sp_pcontext : public Sql_alloc
return label; return label;
} }
sp_label *last_goto_label()
{
return m_goto_labels.head();
}
sp_label *pop_label() sp_label *pop_label()
{ return m_labels.pop(); } { return m_labels.pop(); }
...@@ -697,8 +721,27 @@ class sp_pcontext : public Sql_alloc ...@@ -697,8 +721,27 @@ class sp_pcontext : public Sql_alloc
/// Stack of SQL-handlers. /// Stack of SQL-handlers.
Dynamic_array<sp_handler *> m_handlers; Dynamic_array<sp_handler *> m_handlers;
/// List of labels. /*
In the below example the label <<lab>> has two meanings:
- GOTO lab : must go before the beginning of the loop
- CONTINUE lab : must go to the beginning of the loop
We solve this by storing block labels and goto labels into separate lists.
BEGIN
<<lab>>
FOR i IN a..10 LOOP
...
GOTO lab;
...
CONTINUE lab;
...
END LOOP;
END;
*/
/// List of block labels
List<sp_label> m_labels; List<sp_label> m_labels;
/// List of goto labels
List<sp_label> m_goto_labels;
/// Children contexts, used for destruction. /// Children contexts, used for destruction.
Dynamic_array<sp_pcontext *> m_children; Dynamic_array<sp_pcontext *> m_children;
......
...@@ -5704,6 +5704,54 @@ bool LEX::sp_leave_statement(THD *thd, const LEX_STRING label_name) ...@@ -5704,6 +5704,54 @@ bool LEX::sp_leave_statement(THD *thd, const LEX_STRING label_name)
return sp_exit_block(thd, lab, NULL); return sp_exit_block(thd, lab, NULL);
} }
bool LEX::sp_goto_statement(THD *thd, const LEX_STRING label_name)
{
sp_label *lab= spcont->find_goto_label(label_name);
if (!lab || lab->ip == 0)
{
sp_label *delayedlabel;
if (!lab)
{
// Label not found --> add forward jump to an unknown label
spcont->push_goto_label(thd, label_name, 0, sp_label::GOTO);
delayedlabel= spcont->last_goto_label();
}
else
{
delayedlabel= lab;
}
return sphead->push_backpatch_goto(thd, spcont, delayedlabel);
}
else
{
// Label found (backward goto)
return sp_change_context(thd, lab->ctx, false) ||
sphead->add_instr_jump(thd, spcont, lab->ip); /* Jump back */
}
return false;
}
bool LEX::sp_push_goto_label(THD *thd, const LEX_STRING label_name)
{
sp_label *lab= spcont->find_goto_label(label_name, false);
if (lab)
{
if (lab->ip != 0)
{
my_error(ER_SP_LABEL_REDEFINE, MYF(0), label_name.str);
return true;
}
lab->ip= sphead->instructions();
sp_label *beginblocklabel= spcont->find_label(empty_lex_str);
sphead->backpatch_goto(thd, lab, beginblocklabel);
}
else
{
spcont->push_goto_label(thd, label_name, sphead->instructions());
}
return false;
}
bool LEX::sp_exit_block(THD *thd, sp_label *lab) bool LEX::sp_exit_block(THD *thd, sp_label *lab)
{ {
......
...@@ -3317,6 +3317,7 @@ struct LEX: public Query_tables_list ...@@ -3317,6 +3317,7 @@ struct LEX: public Query_tables_list
bool sp_exit_statement(THD *thd, Item *when); bool sp_exit_statement(THD *thd, Item *when);
bool sp_exit_statement(THD *thd, const LEX_STRING label_name, Item *item); bool sp_exit_statement(THD *thd, const LEX_STRING label_name, Item *item);
bool sp_leave_statement(THD *thd, const LEX_STRING label_name); bool sp_leave_statement(THD *thd, const LEX_STRING label_name);
bool sp_goto_statement(THD *thd, const LEX_STRING label_name);
bool sp_continue_statement(THD *thd, Item *when); bool sp_continue_statement(THD *thd, Item *when);
bool sp_continue_statement(THD *thd, const LEX_STRING label_name, Item *when); bool sp_continue_statement(THD *thd, const LEX_STRING label_name, Item *when);
...@@ -3329,6 +3330,7 @@ struct LEX: public Query_tables_list ...@@ -3329,6 +3330,7 @@ struct LEX: public Query_tables_list
void sp_pop_loop_empty_label(THD *thd); void sp_pop_loop_empty_label(THD *thd);
bool sp_while_loop_expression(THD *thd, Item *expr); bool sp_while_loop_expression(THD *thd, Item *expr);
bool sp_while_loop_finalize(THD *thd); bool sp_while_loop_finalize(THD *thd);
bool sp_push_goto_label(THD *thd, LEX_STRING label_name);
Item_param *add_placeholder(THD *thd, char *name, Item_param *add_placeholder(THD *thd, char *name,
uint pos_in_query, uint len_in_query); uint pos_in_query, uint len_in_query);
......
...@@ -1098,6 +1098,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -1098,6 +1098,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token GET_FORMAT /* MYSQL-FUNC */ %token GET_FORMAT /* MYSQL-FUNC */
%token GET_SYM /* SQL-2003-R */ %token GET_SYM /* SQL-2003-R */
%token GLOBAL_SYM /* SQL-2003-R */ %token GLOBAL_SYM /* SQL-2003-R */
%token GOTO_SYM /* Oracle, reserved in PL/SQL*/
%token GRANT /* SQL-2003-R */ %token GRANT /* SQL-2003-R */
%token GRANTS %token GRANTS
%token GROUP_SYM /* SQL-2003-R */ %token GROUP_SYM /* SQL-2003-R */
...@@ -14288,6 +14289,7 @@ keyword_sp: ...@@ -14288,6 +14289,7 @@ keyword_sp:
| GET_FORMAT {} | GET_FORMAT {}
| GRANTS {} | GRANTS {}
| GLOBAL_SYM {} | GLOBAL_SYM {}
| GOTO_SYM {}
| HASH_SYM {} | HASH_SYM {}
| HARD_SYM {} | HARD_SYM {}
| HOSTS_SYM {} | HOSTS_SYM {}
......
...@@ -516,6 +516,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -516,6 +516,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token GET_FORMAT /* MYSQL-FUNC */ %token GET_FORMAT /* MYSQL-FUNC */
%token GET_SYM /* SQL-2003-R */ %token GET_SYM /* SQL-2003-R */
%token GLOBAL_SYM /* SQL-2003-R */ %token GLOBAL_SYM /* SQL-2003-R */
%token GOTO_SYM /* Oracle, reserved in PL/SQL*/
%token GRANT /* SQL-2003-R */ %token GRANT /* SQL-2003-R */
%token GRANTS %token GRANTS
%token GROUP_SYM /* SQL-2003-R */ %token GROUP_SYM /* SQL-2003-R */
...@@ -1005,7 +1006,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -1005,7 +1006,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_component key_cache_name opt_component key_cache_name
sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
opt_constraint constraint opt_ident opt_constraint constraint opt_ident
label_declaration_oracle ident_directly_assignable label_declaration_oracle labels_declaration_oracle
ident_directly_assignable
sp_decl_ident sp_decl_ident
sp_block_label sp_block_label
...@@ -1307,15 +1309,16 @@ END_OF_INPUT ...@@ -1307,15 +1309,16 @@ END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt %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_statement sp_proc_stmt_return
sp_proc_stmt_in_returns_clause
%type <NONE> sp_proc_stmt_compound_ok %type <NONE> sp_proc_stmt_compound_ok
%type <NONE> sp_proc_stmt_if %type <NONE> sp_proc_stmt_if
%type <NONE> sp_labeled_control sp_unlabeled_control %type <NONE> sp_labeled_control sp_unlabeled_control
%type <NONE> sp_labeled_block sp_unlabeled_block %type <NONE> sp_labeled_block sp_unlabeled_block
%type <NONE> sp_labelable_stmt
%type <NONE> sp_proc_stmt_continue %type <NONE> sp_proc_stmt_continue
%type <NONE> sp_proc_stmt_exit %type <NONE> sp_proc_stmt_exit
%type <NONE> sp_proc_stmt_leave %type <NONE> sp_proc_stmt_leave
%type <NONE> sp_proc_stmt_iterate %type <NONE> sp_proc_stmt_iterate
%type <NONE> sp_proc_stmt_goto
%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close %type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
%type <NONE> case_stmt_specification %type <NONE> case_stmt_specification
%type <NONE> loop_body while_body repeat_body %type <NONE> loop_body while_body repeat_body
...@@ -2425,6 +2428,17 @@ sp_proc_stmts1: ...@@ -2425,6 +2428,17 @@ sp_proc_stmts1:
| sp_proc_stmts1 sp_proc_stmt ';' | sp_proc_stmts1 sp_proc_stmt ';'
; ;
sp_proc_stmts1_implicit_block:
{
Lex->sp_block_init(thd);
}
sp_proc_stmts1
{
if (Lex->sp_block_finalize(thd))
MYSQL_YYABORT;
}
;
opt_sp_decl_body_list: opt_sp_decl_body_list:
/* Empty */ /* Empty */
{ {
...@@ -3034,32 +3048,28 @@ sp_opt_default: ...@@ -3034,32 +3048,28 @@ sp_opt_default:
| SET_VAR expr { $$ = $2; } | SET_VAR expr { $$ = $2; }
; ;
/* sp_proc_stmt:
ps_proc_stmt_in_returns_clause is a statement that is allowed sp_labeled_block
in the RETURNS clause of a stored function definition directly, | sp_unlabeled_block
without the BEGIN..END block.
It should not include any syntax structures starting with '(', to avoid
shift/reduce conflicts with the rule "field_type" and its sub-rules
that scan an optional length, like CHAR(1) or YEAR(4).
See MDEV-9166.
*/
sp_proc_stmt_in_returns_clause:
sp_proc_stmt_return
| sp_labeled_block
| sp_labeled_control | sp_labeled_control
| sp_proc_stmt_compound_ok | sp_unlabeled_control
| sp_labelable_stmt
| labels_declaration_oracle sp_labelable_stmt {}
; ;
sp_proc_stmt: sp_labelable_stmt:
sp_proc_stmt_in_returns_clause sp_proc_stmt_statement
| sp_proc_stmt_statement
| sp_proc_stmt_continue | sp_proc_stmt_continue
| sp_proc_stmt_exit | sp_proc_stmt_exit
| sp_proc_stmt_leave | sp_proc_stmt_leave
| sp_proc_stmt_iterate | sp_proc_stmt_iterate
| sp_proc_stmt_goto
| sp_proc_stmt_open | sp_proc_stmt_open
| sp_proc_stmt_fetch | sp_proc_stmt_fetch
| sp_proc_stmt_close | sp_proc_stmt_close
| sp_proc_stmt_return
| sp_proc_stmt_if
| case_stmt_specification
| NULL_SYM { } | NULL_SYM { }
; ;
...@@ -3245,6 +3255,15 @@ sp_proc_stmt_iterate: ...@@ -3245,6 +3255,15 @@ sp_proc_stmt_iterate:
} }
; ;
sp_proc_stmt_goto:
GOTO_SYM label_ident
{
if (Lex->sp_goto_statement(thd, $2))
MYSQL_YYABORT;
}
;
remember_lex: remember_lex:
{ {
$$= thd->lex; $$= thd->lex;
...@@ -3396,7 +3415,7 @@ sp_if: ...@@ -3396,7 +3415,7 @@ sp_if:
if (sp->restore_lex(thd)) if (sp->restore_lex(thd))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
sp_proc_stmts1 sp_proc_stmts1_implicit_block
{ {
sp_head *sp= Lex->sphead; sp_head *sp= Lex->sphead;
sp_pcontext *ctx= Lex->spcont; sp_pcontext *ctx= Lex->spcont;
...@@ -3419,7 +3438,7 @@ sp_if: ...@@ -3419,7 +3438,7 @@ sp_if:
sp_elseifs: sp_elseifs:
/* Empty */ /* Empty */
| ELSIF_SYM sp_if | ELSIF_SYM sp_if
| ELSE sp_proc_stmts1 | ELSE sp_proc_stmts1_implicit_block
; ;
case_stmt_specification: case_stmt_specification:
...@@ -3535,7 +3554,7 @@ simple_when_clause: ...@@ -3535,7 +3554,7 @@ simple_when_clause:
MYSQL_YYABORT; MYSQL_YYABORT;
} }
THEN_SYM THEN_SYM
sp_proc_stmts1 sp_proc_stmts1_implicit_block
{ {
if (Lex->case_stmt_action_then()) if (Lex->case_stmt_action_then())
MYSQL_YYABORT; MYSQL_YYABORT;
...@@ -3557,7 +3576,7 @@ searched_when_clause: ...@@ -3557,7 +3576,7 @@ searched_when_clause:
MYSQL_YYABORT; MYSQL_YYABORT;
} }
THEN_SYM THEN_SYM
sp_proc_stmts1 sp_proc_stmts1_implicit_block
{ {
if (Lex->case_stmt_action_then()) if (Lex->case_stmt_action_then())
MYSQL_YYABORT; MYSQL_YYABORT;
...@@ -3576,7 +3595,7 @@ else_clause_opt: ...@@ -3576,7 +3595,7 @@ else_clause_opt:
sp->add_instr(i)) sp->add_instr(i))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| ELSE sp_proc_stmts1 | ELSE sp_proc_stmts1_implicit_block
; ;
sp_opt_label: sp_opt_label:
...@@ -3585,7 +3604,7 @@ sp_opt_label: ...@@ -3585,7 +3604,7 @@ sp_opt_label:
; ;
sp_block_label: sp_block_label:
label_declaration_oracle labels_declaration_oracle
{ {
if (Lex->spcont->block_label_declare($1)) if (Lex->spcont->block_label_declare($1))
MYSQL_YYABORT; MYSQL_YYABORT;
...@@ -3819,14 +3838,14 @@ pop_sp_loop_label: ...@@ -3819,14 +3838,14 @@ pop_sp_loop_label:
; ;
sp_labeled_control: sp_labeled_control:
label_declaration_oracle LOOP_SYM labels_declaration_oracle LOOP_SYM
{ {
if (Lex->sp_push_loop_label(thd, $1)) if (Lex->sp_push_loop_label(thd, $1))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
loop_body pop_sp_loop_label loop_body pop_sp_loop_label
{ } { }
| label_declaration_oracle WHILE_SYM | labels_declaration_oracle WHILE_SYM
{ {
if (Lex->sp_push_loop_label(thd, $1)) if (Lex->sp_push_loop_label(thd, $1))
MYSQL_YYABORT; MYSQL_YYABORT;
...@@ -3834,7 +3853,7 @@ sp_labeled_control: ...@@ -3834,7 +3853,7 @@ sp_labeled_control:
} }
while_body pop_sp_loop_label while_body pop_sp_loop_label
{ } { }
| label_declaration_oracle FOR_SYM | labels_declaration_oracle FOR_SYM
{ {
// See "The FOR LOOP statement" comments in sql_lex.cc // See "The FOR LOOP statement" comments in sql_lex.cc
Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block
...@@ -3858,7 +3877,7 @@ sp_labeled_control: ...@@ -3858,7 +3877,7 @@ sp_labeled_control:
if (Lex->sp_block_finalize(thd)) // The outer DECLARE..BEGIN..END if (Lex->sp_block_finalize(thd)) // The outer DECLARE..BEGIN..END
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| label_declaration_oracle REPEAT_SYM | labels_declaration_oracle REPEAT_SYM
{ {
if (Lex->sp_push_loop_label(thd, $1)) if (Lex->sp_push_loop_label(thd, $1))
MYSQL_YYABORT; MYSQL_YYABORT;
...@@ -14188,8 +14207,18 @@ label_ident: ...@@ -14188,8 +14207,18 @@ label_ident:
} }
; ;
labels_declaration_oracle:
label_declaration_oracle { $$= $1; }
| labels_declaration_oracle label_declaration_oracle { $$= $2; }
;
label_declaration_oracle: label_declaration_oracle:
SHIFT_LEFT label_ident SHIFT_RIGHT { $$= $2; } SHIFT_LEFT label_ident SHIFT_RIGHT
{
if (Lex->sp_push_goto_label(thd, $2))
MYSQL_YYABORT;
$$= $2;
}
; ;
ident_or_text: ident_or_text:
...@@ -16434,6 +16463,8 @@ trigger_tail: ...@@ -16434,6 +16463,8 @@ trigger_tail:
{ /* $21 */ { /* $21 */
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp= lex->sphead; sp_head *sp= lex->sphead;
if (sp->check_unresolved_goto())
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CREATE_TRIGGER; lex->sql_command= SQLCOM_CREATE_TRIGGER;
sp->set_stmt_end(thd); sp->set_stmt_end(thd);
...@@ -16517,6 +16548,8 @@ sf_tail: ...@@ -16517,6 +16548,8 @@ sf_tail:
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
sp_head *sp= lex->sphead; sp_head *sp= lex->sphead;
if (sp->check_unresolved_goto())
MYSQL_YYABORT;
if (sp->is_not_allowed_in_function("function")) if (sp->is_not_allowed_in_function("function"))
MYSQL_YYABORT; MYSQL_YYABORT;
...@@ -16549,7 +16582,8 @@ sp_tail: ...@@ -16549,7 +16582,8 @@ sp_tail:
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp= lex->sphead; sp_head *sp= lex->sphead;
if (sp->check_unresolved_goto())
MYSQL_YYABORT;
sp->set_stmt_end(thd); sp->set_stmt_end(thd);
lex->sql_command= SQLCOM_CREATE_PROCEDURE; lex->sql_command= SQLCOM_CREATE_PROCEDURE;
sp->restore_thd_mem_root(thd); sp->restore_thd_mem_root(thd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment