Commit f37a943f authored by Alexander Barkov's avatar Alexander Barkov

MDEV-10411 Providing compatibility for basic PL/SQL constructs

Moving the code from *.yy to methods:
LEX::sp_change_context()
LEX::sp_leave_statement()
LEX::sp_iterate_statement()
to reuse the same code between LEAVE and ITERATE statements.
EXIT statement will also reuse the same code.
parent 4b614955
...@@ -2571,12 +2571,12 @@ bool sp_head::add_instr_jump(THD *thd, sp_pcontext *spcont, uint dest) ...@@ -2571,12 +2571,12 @@ bool sp_head::add_instr_jump(THD *thd, sp_pcontext *spcont, uint dest)
bool sp_head::add_instr_jump_forward_with_backpatch(THD *thd, bool sp_head::add_instr_jump_forward_with_backpatch(THD *thd,
sp_pcontext *spcont) sp_pcontext *spcont,
sp_label *lab)
{ {
sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(instructions(), spcont); sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(instructions(), spcont);
if (i == NULL || add_instr(i)) if (i == NULL || add_instr(i))
return true; return true;
sp_label *lab= spcont->last_label();
push_backpatch(thd, i, lab); push_backpatch(thd, i, lab);
return false; return false;
} }
......
...@@ -344,7 +344,15 @@ class sp_head :private Query_arena, ...@@ -344,7 +344,15 @@ class sp_head :private Query_arena,
add_instr_jump(THD *thd, sp_pcontext *spcont, uint dest); add_instr_jump(THD *thd, sp_pcontext *spcont, uint dest);
bool bool
add_instr_jump_forward_with_backpatch(THD *thd, sp_pcontext *spcont); add_instr_jump_forward_with_backpatch(THD *thd, sp_pcontext *spcont,
sp_label *lab);
bool
add_instr_jump_forward_with_backpatch(THD *thd, sp_pcontext *spcont)
{
return add_instr_jump_forward_with_backpatch(thd, spcont,
spcont->last_label());
}
/** /**
Returns true if any substatement in the routine directly Returns true if any substatement in the routine directly
......
...@@ -5449,6 +5449,63 @@ LEX::sp_block_with_exceptions_finalize_exceptions(THD *thd, ...@@ -5449,6 +5449,63 @@ LEX::sp_block_with_exceptions_finalize_exceptions(THD *thd,
return sphead->add_instr_jump(thd, spcont, executable_section_ip); return sphead->add_instr_jump(thd, spcont, executable_section_ip);
} }
bool LEX::sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive)
{
uint n;
uint ip= sphead->instructions();
if ((n= spcont->diff_handlers(ctx, exclusive)))
{
sp_instr_hpop *hpop= new (thd->mem_root) sp_instr_hpop(ip++, spcont, n);
if (hpop == NULL || sphead->add_instr(hpop))
return true;
}
if ((n= spcont->diff_cursors(ctx, exclusive)))
{
sp_instr_cpop *cpop= new (thd->mem_root) sp_instr_cpop(ip++, spcont, n);
if (cpop == NULL || sphead->add_instr(cpop))
return true;
}
return false;
}
bool LEX::sp_leave_statement(THD *thd, const LEX_STRING label_name)
{
sp_label *lab= spcont->find_label(label_name);
if (!lab)
{
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", label_name.str);
return true;
}
/*
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);
return sp_change_context(thd, lab->ctx, exclusive) ||
sphead->add_instr_jump_forward_with_backpatch(thd, spcont, lab);
}
bool LEX::sp_iterate_statement(THD *thd, const LEX_STRING label_name)
{
sp_label *lab= spcont->find_label(label_name);
if (!lab || lab->type != sp_label::ITERATION)
{
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", label_name.str);
return true;
}
return sp_change_context(thd, lab->ctx, false) ||
sphead->add_instr_jump(thd, spcont, lab->ip); /* Jump back */
}
#ifdef MYSQL_SERVER #ifdef MYSQL_SERVER
uint binlog_unsafe_map[256]; uint binlog_unsafe_map[256];
......
...@@ -3151,6 +3151,10 @@ struct LEX: public Query_tables_list ...@@ -3151,6 +3151,10 @@ struct LEX: public Query_tables_list
bool sp_block_with_exceptions_finalize_exceptions(THD *thd, bool sp_block_with_exceptions_finalize_exceptions(THD *thd,
uint executable_section_ip, uint executable_section_ip,
uint exception_count); uint exception_count);
bool sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive);
bool sp_leave_statement(THD *thd, const LEX_STRING label_name);
bool sp_iterate_statement(THD *thd, const LEX_STRING label_name);
// Check if "KEY IF NOT EXISTS name" used outside of ALTER context // Check if "KEY IF NOT EXISTS name" used outside of ALTER context
bool check_add_key(DDL_options_st ddl) bool check_add_key(DDL_options_st ddl)
{ {
......
...@@ -3600,90 +3600,15 @@ sp_proc_stmt_return: ...@@ -3600,90 +3600,15 @@ sp_proc_stmt_return:
sp_proc_stmt_leave: sp_proc_stmt_leave:
LEAVE_SYM label_ident LEAVE_SYM label_ident
{ {
LEX *lex= Lex; if (Lex->sp_leave_statement(thd, $2))
sp_head *sp = lex->sphead;
sp_pcontext *ctx= lex->spcont;
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)
{
sp_instr_hpop *hpop= new (thd->mem_root)
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 (thd->mem_root)
sp_instr_cpop(ip++, ctx, n);
if (cpop == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
sp->add_instr(cpop);
}
i= new (thd->mem_root) sp_instr_jump(ip, ctx);
if (i == NULL)
MYSQL_YYABORT;
sp->push_backpatch(thd, i, lab); /* Jumping forward */
sp->add_instr(i);
} }
; ;
sp_proc_stmt_iterate: sp_proc_stmt_iterate:
ITERATE_SYM label_ident ITERATE_SYM label_ident
{ {
LEX *lex= Lex; if (Lex->sp_iterate_statement(thd, $2))
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
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;
n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */
if (n)
{
sp_instr_hpop *hpop= new (thd->mem_root)
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 (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; MYSQL_YYABORT;
} }
; ;
......
...@@ -3007,90 +3007,15 @@ sp_proc_stmt_return: ...@@ -3007,90 +3007,15 @@ sp_proc_stmt_return:
sp_proc_stmt_leave: sp_proc_stmt_leave:
LEAVE_SYM label_ident LEAVE_SYM label_ident
{ {
LEX *lex= Lex; if (Lex->sp_leave_statement(thd, $2))
sp_head *sp = lex->sphead;
sp_pcontext *ctx= lex->spcont;
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)
{
sp_instr_hpop *hpop= new (thd->mem_root)
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 (thd->mem_root)
sp_instr_cpop(ip++, ctx, n);
if (cpop == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
sp->add_instr(cpop);
}
i= new (thd->mem_root) sp_instr_jump(ip, ctx);
if (i == NULL)
MYSQL_YYABORT;
sp->push_backpatch(thd, i, lab); /* Jumping forward */
sp->add_instr(i);
} }
; ;
sp_proc_stmt_iterate: sp_proc_stmt_iterate:
ITERATE_SYM label_ident ITERATE_SYM label_ident
{ {
LEX *lex= Lex; if (Lex->sp_iterate_statement(thd, $2))
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
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;
n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */
if (n)
{
sp_instr_hpop *hpop= new (thd->mem_root)
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 (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; MYSQL_YYABORT;
} }
; ;
......
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