Fixed BUG#3294: Stored procedure crash if table dropped before use.
Dropping the table was not the real problem, the problem was with errors occuring within error handlers. mysql-test/r/sp-error.result: New test case for BUG#3294. mysql-test/t/sp-error.test: New test case for BUG#3294. sql/sp_head.cc: Use hreturn instruction both for continue and exit handlers (a special case of a jump). sql/sp_head.h: Use hreturn instruction both for continue and exit handlers (a special case of a jump). sql/sp_rcontext.cc: Keep track on if we're in a handler already, for error handling. sql/sp_rcontext.h: Keep track on if we're in a handler already, for error handling. sql/sql_yacc.yy: Use hreturn instruction both for continue and exit handlers (a special case of a jump).
This commit is contained in:
parent
862e78568e
commit
1912148cec
@ -485,4 +485,13 @@ create procedure bug4344() drop procedure bug4344|
|
|||||||
ERROR HY000: Can't drop a PROCEDURE from within another stored routine
|
ERROR HY000: Can't drop a PROCEDURE from within another stored routine
|
||||||
create procedure bug4344() drop function bug4344|
|
create procedure bug4344() drop function bug4344|
|
||||||
ERROR HY000: Can't drop a FUNCTION from within another stored routine
|
ERROR HY000: Can't drop a FUNCTION from within another stored routine
|
||||||
|
drop procedure if exists bug3294|
|
||||||
|
create procedure bug3294()
|
||||||
|
begin
|
||||||
|
declare continue handler for sqlexception drop table t5;
|
||||||
|
drop table t5;
|
||||||
|
end|
|
||||||
|
call bug3294()|
|
||||||
|
ERROR 42S02: Unknown table 't5'
|
||||||
|
drop procedure bug3294|
|
||||||
drop table t1|
|
drop table t1|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
# Make sure we don't have any procedures left.
|
# Make sure we don't have any procedures left.
|
||||||
delete from mysql.proc;
|
delete from mysql.proc;
|
||||||
|
|
||||||
# A test "global" procedures, i.e. not belonging to any database.
|
# A test of "global" procedures, i.e. not belonging to any database.
|
||||||
create function .f1() returns int return 1;
|
create function .f1() returns int return 1;
|
||||||
create procedure .p1() select 1, database();
|
create procedure .p1() select 1, database();
|
||||||
create procedure p1() select 2, database();
|
create procedure p1() select 2, database();
|
||||||
@ -650,6 +650,22 @@ create procedure bug4344() drop procedure bug4344|
|
|||||||
--error 1357
|
--error 1357
|
||||||
create procedure bug4344() drop function bug4344|
|
create procedure bug4344() drop function bug4344|
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUG#3294: Stored procedure crash if table dropped before use
|
||||||
|
# (Actually, when an error occurs within an error handler.)
|
||||||
|
--disable_warnings
|
||||||
|
drop procedure if exists bug3294|
|
||||||
|
--enable_warnings
|
||||||
|
create procedure bug3294()
|
||||||
|
begin
|
||||||
|
declare continue handler for sqlexception drop table t5;
|
||||||
|
drop table t5;
|
||||||
|
end|
|
||||||
|
|
||||||
|
--error 1051
|
||||||
|
call bug3294()|
|
||||||
|
drop procedure bug3294|
|
||||||
|
|
||||||
|
|
||||||
drop table t1|
|
drop table t1|
|
||||||
|
|
||||||
|
@ -499,6 +499,7 @@ sp_head::execute(THD *thd)
|
|||||||
ip= hip;
|
ip= hip;
|
||||||
ret= 0;
|
ret= 0;
|
||||||
ctx->clear_handler();
|
ctx->clear_handler();
|
||||||
|
ctx->in_handler= TRUE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1586,19 +1587,40 @@ int
|
|||||||
sp_instr_hreturn::execute(THD *thd, uint *nextp)
|
sp_instr_hreturn::execute(THD *thd, uint *nextp)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("sp_instr_hreturn::execute");
|
DBUG_ENTER("sp_instr_hreturn::execute");
|
||||||
thd->spcont->restore_variables(m_frame);
|
if (m_dest)
|
||||||
*nextp= thd->spcont->pop_hstack();
|
*nextp= m_dest;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thd->spcont->restore_variables(m_frame);
|
||||||
|
*nextp= thd->spcont->pop_hstack();
|
||||||
|
}
|
||||||
|
thd->spcont->in_handler= FALSE;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sp_instr_hreturn::print(String *str)
|
sp_instr_hreturn::print(String *str)
|
||||||
{
|
{
|
||||||
str->reserve(12);
|
str->reserve(16);
|
||||||
str->append("hreturn ");
|
str->append("hreturn ");
|
||||||
str->qs_append(m_frame);
|
str->qs_append(m_frame);
|
||||||
|
if (m_dest)
|
||||||
|
str->qs_append(m_dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
sp_instr_hreturn::opt_mark(sp_head *sp)
|
||||||
|
{
|
||||||
|
if (m_dest)
|
||||||
|
return sp_instr_jump::opt_mark(sp);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
marked= 1;
|
||||||
|
return UINT_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// sp_instr_cpush
|
// sp_instr_cpush
|
||||||
//
|
//
|
||||||
|
@ -677,7 +677,7 @@ private:
|
|||||||
}; // class sp_instr_hpop : public sp_instr
|
}; // class sp_instr_hpop : public sp_instr
|
||||||
|
|
||||||
|
|
||||||
class sp_instr_hreturn : public sp_instr
|
class sp_instr_hreturn : public sp_instr_jump
|
||||||
{
|
{
|
||||||
sp_instr_hreturn(const sp_instr_hreturn &); /* Prevent use of these */
|
sp_instr_hreturn(const sp_instr_hreturn &); /* Prevent use of these */
|
||||||
void operator=(sp_instr_hreturn &);
|
void operator=(sp_instr_hreturn &);
|
||||||
@ -685,7 +685,7 @@ class sp_instr_hreturn : public sp_instr
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
sp_instr_hreturn(uint ip, sp_pcontext *ctx, uint fp)
|
sp_instr_hreturn(uint ip, sp_pcontext *ctx, uint fp)
|
||||||
: sp_instr(ip, ctx), m_frame(fp)
|
: sp_instr_jump(ip, ctx), m_frame(fp)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~sp_instr_hreturn()
|
virtual ~sp_instr_hreturn()
|
||||||
@ -695,11 +695,7 @@ public:
|
|||||||
|
|
||||||
virtual void print(String *str);
|
virtual void print(String *str);
|
||||||
|
|
||||||
virtual uint opt_mark(sp_head *sp)
|
virtual uint opt_mark(sp_head *sp);
|
||||||
{
|
|
||||||
marked= 1;
|
|
||||||
return UINT_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
|
|||||||
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
|
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
|
||||||
m_hfound(-1), m_ccount(0)
|
m_hfound(-1), m_ccount(0)
|
||||||
{
|
{
|
||||||
|
in_handler= FALSE;
|
||||||
m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
|
m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
|
||||||
m_outs= (int *)sql_alloc(fsize * sizeof(int));
|
m_outs= (int *)sql_alloc(fsize * sizeof(int));
|
||||||
m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
|
m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
|
||||||
@ -58,6 +59,8 @@ sp_rcontext::set_item_eval(uint idx, Item *i, enum_field_types type)
|
|||||||
int
|
int
|
||||||
sp_rcontext::find_handler(uint sql_errno)
|
sp_rcontext::find_handler(uint sql_errno)
|
||||||
{
|
{
|
||||||
|
if (in_handler)
|
||||||
|
return 0; // Already executing a handler
|
||||||
if (m_hfound >= 0)
|
if (m_hfound >= 0)
|
||||||
return 1; // Already got one
|
return 1; // Already got one
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ class sp_rcontext : public Sql_alloc
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
bool in_handler;
|
||||||
|
|
||||||
sp_rcontext(uint fsize, uint hmax, uint cmax);
|
sp_rcontext(uint fsize, uint hmax, uint cmax);
|
||||||
|
|
||||||
~sp_rcontext()
|
~sp_rcontext()
|
||||||
|
@ -1599,13 +1599,17 @@ sp_decl:
|
|||||||
sp_head *sp= lex->sphead;
|
sp_head *sp= lex->sphead;
|
||||||
sp_pcontext *ctx= lex->spcont;
|
sp_pcontext *ctx= lex->spcont;
|
||||||
sp_label_t *hlab= lex->spcont->pop_label(); /* After this hdlr */
|
sp_label_t *hlab= lex->spcont->pop_label(); /* After this hdlr */
|
||||||
|
sp_instr_hreturn *i;
|
||||||
|
|
||||||
if ($2 == SP_HANDLER_CONTINUE)
|
if ($2 == SP_HANDLER_CONTINUE)
|
||||||
sp->add_instr(new sp_instr_hreturn(sp->instructions(), ctx,
|
{
|
||||||
ctx->current_pvars()));
|
i= new sp_instr_hreturn(sp->instructions(), ctx,
|
||||||
|
ctx->current_pvars());
|
||||||
|
sp->add_instr(i);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{ /* EXIT or UNDO handler, just jump to the end of the block */
|
{ /* EXIT or UNDO handler, just jump to the end of the block */
|
||||||
sp_instr_jump *i= new sp_instr_jump(sp->instructions(), ctx);
|
i= new sp_instr_hreturn(sp->instructions(), ctx, 0);
|
||||||
|
|
||||||
sp->add_instr(i);
|
sp->add_instr(i);
|
||||||
sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
|
sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user