Commit 10a92d85 authored by unknown's avatar unknown

Fixed BUG#6127: Stored procedure handlers within handlers don't work

    Replaced the dumb in-handler/not-in-handler check with a proper recursion
    check of handlers being executed.
    (Re-commit in a different tree, to make push possible.)


mysql-test/r/sp.result:
  New test case for BUG#6127.
mysql-test/t/sp.test:
  New test case for BUG#6127.
sql/sp_head.cc:
  Replaced the setting of ctx->in_handler with a enter/exit handler methods.
sql/sp_rcontext.cc:
  Replaced the boolean in_handler flag with a stack of handlers being exectuted, for proper recursion check.
sql/sp_rcontext.h:
  Replaced the boolean in_handler flag with a stack of handlers being exectuted, for proper recursion check.
  (And added some comments in the sp_rcontext class.)
parent 82b582f5
...@@ -3360,4 +3360,34 @@ call bug12979_2()| ...@@ -3360,4 +3360,34 @@ call bug12979_2()|
internal_var internal_var
NULL NULL
drop procedure bug12979_2| drop procedure bug12979_2|
drop table if exists t3|
drop procedure if exists bug6127|
create table t3 (s1 int unique)|
set @sm=@@sql_mode|
set sql_mode='traditional'|
create procedure bug6127()
begin
declare continue handler for sqlstate '23000'
begin
declare continue handler for sqlstate '22003'
insert into t3 values (0);
insert into t3 values (1000000000000000);
end;
insert into t3 values (1);
insert into t3 values (1);
end|
call bug6127()|
select * from t3|
s1
0
1
call bug6127()|
ERROR 23000: Duplicate entry '0' for key 1
select * from t3|
s1
0
1
set sql_mode=@sm|
drop table t3|
drop procedure bug6127|
drop table t1,t2; drop table t1,t2;
...@@ -4228,6 +4228,42 @@ call bug12979_2()| ...@@ -4228,6 +4228,42 @@ call bug12979_2()|
drop procedure bug12979_2| drop procedure bug12979_2|
#
# BUG#6127: Stored procedure handlers within handlers don't work
#
--disable_warnings
drop table if exists t3|
drop procedure if exists bug6127|
--enable_warnings
create table t3 (s1 int unique)|
set @sm=@@sql_mode|
set sql_mode='traditional'|
create procedure bug6127()
begin
declare continue handler for sqlstate '23000'
begin
declare continue handler for sqlstate '22003'
insert into t3 values (0);
insert into t3 values (1000000000000000);
end;
insert into t3 values (1);
insert into t3 values (1);
end|
call bug6127()|
select * from t3|
--error ER_DUP_ENTRY
call bug6127()|
select * from t3|
set sql_mode=@sm|
drop table t3|
drop procedure bug6127|
# #
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
# #
......
...@@ -1015,7 +1015,7 @@ int sp_head::execute(THD *thd) ...@@ -1015,7 +1015,7 @@ int sp_head::execute(THD *thd)
ip= hip; ip= hip;
ret= 0; ret= 0;
ctx->clear_handler(); ctx->clear_handler();
ctx->in_handler= TRUE; ctx->enter_handler(hip);
thd->clear_error(); thd->clear_error();
thd->killed= THD::NOT_KILLED; thd->killed= THD::NOT_KILLED;
continue; continue;
...@@ -2378,7 +2378,7 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) ...@@ -2378,7 +2378,7 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp)
thd->spcont->restore_variables(m_frame); thd->spcont->restore_variables(m_frame);
*nextp= thd->spcont->pop_hstack(); *nextp= thd->spcont->pop_hstack();
} }
thd->spcont->in_handler= FALSE; thd->spcont->exit_handler();
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -31,12 +31,12 @@ ...@@ -31,12 +31,12 @@
sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax) 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_ihsp(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_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t)); m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
m_hstack= (uint *)sql_alloc(hmax * sizeof(uint)); m_hstack= (uint *)sql_alloc(hmax * sizeof(uint));
m_in_handler= (uint *)sql_alloc(hmax * sizeof(uint));
m_cstack= (sp_cursor **)sql_alloc(cmax * sizeof(sp_cursor *)); m_cstack= (sp_cursor **)sql_alloc(cmax * sizeof(sp_cursor *));
m_saved.empty(); m_saved.empty();
} }
...@@ -68,8 +68,6 @@ bool ...@@ -68,8 +68,6 @@ bool
sp_rcontext::find_handler(uint sql_errno, sp_rcontext::find_handler(uint sql_errno,
MYSQL_ERROR::enum_warning_level level) MYSQL_ERROR::enum_warning_level level)
{ {
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
...@@ -79,6 +77,13 @@ sp_rcontext::find_handler(uint sql_errno, ...@@ -79,6 +77,13 @@ sp_rcontext::find_handler(uint sql_errno,
while (i--) while (i--)
{ {
sp_cond_type_t *cond= m_handler[i].cond; sp_cond_type_t *cond= m_handler[i].cond;
int j= m_ihsp;
while (j--)
if (m_in_handler[j] == m_handler[i].handler)
break;
if (j >= 0)
continue; // Already executing this handler
switch (cond->type) switch (cond->type)
{ {
......
...@@ -58,7 +58,6 @@ class sp_rcontext : public Sql_alloc ...@@ -58,7 +58,6 @@ class sp_rcontext : public Sql_alloc
public: public:
bool in_handler;
/* /*
Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT
SP parameters when they don't fit into prealloced items. This SP parameters when they don't fit into prealloced items. This
...@@ -169,6 +168,18 @@ class sp_rcontext : public Sql_alloc ...@@ -169,6 +168,18 @@ class sp_rcontext : public Sql_alloc
return m_hstack[--m_hsp]; return m_hstack[--m_hsp];
} }
inline void
enter_handler(int hid)
{
m_in_handler[m_ihsp++]= hid;
}
inline void
exit_handler()
{
m_ihsp-= 1;
}
// Save variables starting at fp and up // Save variables starting at fp and up
void void
save_variables(uint fp); save_variables(uint fp);
...@@ -203,12 +214,14 @@ class sp_rcontext : public Sql_alloc ...@@ -203,12 +214,14 @@ class sp_rcontext : public Sql_alloc
Item *m_result; // For FUNCTIONs Item *m_result; // For FUNCTIONs
sp_handler_t *m_handler; sp_handler_t *m_handler; // Visible handlers
uint m_hcount; uint m_hcount; // Stack pointer for m_handler
uint *m_hstack; uint *m_hstack; // Return stack for continue handlers
uint m_hsp; uint m_hsp; // Stack pointer for m_hstack
uint *m_in_handler; // Active handler, for recursion check
uint m_ihsp; // Stack pointer for m_in_handler
int m_hfound; // Set by find_handler; -1 if not found int m_hfound; // Set by find_handler; -1 if not found
List<Item> m_saved; // Saved variables List<Item> m_saved; // Saved variables during handler exec.
sp_cursor **m_cstack; sp_cursor **m_cstack;
uint m_ccount; uint m_ccount;
......
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