Commit ae10d3d9 authored by thek@adventure.(none)'s avatar thek@adventure.(none)

Bug#26977 exception handlers never hreturn

  - In some cases, flow control optimization implemented in sp::optimize
    removes hreturn instructions, causing SQL exception handlers to:
      * never return
      * execute wrong logic
  - This patch overrides default short cut optimization on hreturn instructions
    to avoid this problem.
parent 10dd9970
...@@ -620,4 +620,117 @@ SHOW PROCEDURE CODE p1; ...@@ -620,4 +620,117 @@ SHOW PROCEDURE CODE p1;
Pos Instruction Pos Instruction
0 stmt 2 "CREATE INDEX idx ON t1 (c1)" 0 stmt 2 "CREATE INDEX idx ON t1 (c1)"
DROP PROCEDURE p1; DROP PROCEDURE p1;
drop table if exists t1;
drop procedure if exists proc_26977_broken;
drop procedure if exists proc_26977_works;
create table t1(a int unique);
create procedure proc_26977_broken(v int)
begin
declare i int default 5;
declare continue handler for sqlexception
begin
select 'caught something';
retry:
while i > 0 do
begin
set i = i - 1;
select 'looping', i;
end;
end while retry;
end;
select 'do something';
insert into t1 values (v);
select 'do something again';
insert into t1 values (v);
end//
create procedure proc_26977_works(v int)
begin
declare i int default 5;
declare continue handler for sqlexception
begin
select 'caught something';
retry:
while i > 0 do
begin
set i = i - 1;
select 'looping', i;
end;
end while retry;
select 'optimizer: keep hreturn';
end;
select 'do something';
insert into t1 values (v);
select 'do something again';
insert into t1 values (v);
end//
show procedure code proc_26977_broken;
Pos Instruction
0 set i@1 5
1 hpush_jump 8 2 CONTINUE
2 stmt 0 "select 'caught something'"
3 jump_if_not 7(7) (i@1 > 0)
4 set i@1 (i@1 - 1)
5 stmt 0 "select 'looping', i"
6 jump 3
7 hreturn 2
8 stmt 0 "select 'do something'"
9 stmt 5 "insert into t1 values (v)"
10 stmt 0 "select 'do something again'"
11 stmt 5 "insert into t1 values (v)"
12 hpop 1
show procedure code proc_26977_works;
Pos Instruction
0 set i@1 5
1 hpush_jump 9 2 CONTINUE
2 stmt 0 "select 'caught something'"
3 jump_if_not 7(7) (i@1 > 0)
4 set i@1 (i@1 - 1)
5 stmt 0 "select 'looping', i"
6 jump 3
7 stmt 0 "select 'optimizer: keep hreturn'"
8 hreturn 2
9 stmt 0 "select 'do something'"
10 stmt 5 "insert into t1 values (v)"
11 stmt 0 "select 'do something again'"
12 stmt 5 "insert into t1 values (v)"
13 hpop 1
call proc_26977_broken(1);
do something
do something
do something again
do something again
caught something
caught something
looping i
looping 4
looping i
looping 3
looping i
looping 2
looping i
looping 1
looping i
looping 0
call proc_26977_works(2);
do something
do something
do something again
do something again
caught something
caught something
looping i
looping 4
looping i
looping 3
looping i
looping 2
looping i
looping 1
looping i
looping 0
optimizer: keep hreturn
optimizer: keep hreturn
drop table t1;
drop procedure proc_26977_broken;
drop procedure proc_26977_works;
End of 5.0 tests. End of 5.0 tests.
...@@ -446,4 +446,79 @@ SHOW PROCEDURE CODE p1; ...@@ -446,4 +446,79 @@ SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1; DROP PROCEDURE p1;
#
# Bug#26977 exception handlers never hreturn
#
--disable_warnings
drop table if exists t1;
drop procedure if exists proc_26977_broken;
drop procedure if exists proc_26977_works;
--enable_warnings
create table t1(a int unique);
delimiter //;
create procedure proc_26977_broken(v int)
begin
declare i int default 5;
declare continue handler for sqlexception
begin
select 'caught something';
retry:
while i > 0 do
begin
set i = i - 1;
select 'looping', i;
end;
end while retry;
end;
select 'do something';
insert into t1 values (v);
select 'do something again';
insert into t1 values (v);
end//
create procedure proc_26977_works(v int)
begin
declare i int default 5;
declare continue handler for sqlexception
begin
select 'caught something';
retry:
while i > 0 do
begin
set i = i - 1;
select 'looping', i;
end;
end while retry;
select 'optimizer: keep hreturn';
end;
select 'do something';
insert into t1 values (v);
select 'do something again';
insert into t1 values (v);
end//
delimiter ;//
show procedure code proc_26977_broken;
show procedure code proc_26977_works;
## This caust an error because of jump short cut
## optimization.
call proc_26977_broken(1);
## This works
call proc_26977_works(2);
drop table t1;
drop procedure proc_26977_broken;
drop procedure proc_26977_works;
--echo End of 5.0 tests. --echo End of 5.0 tests.
...@@ -2982,10 +2982,20 @@ sp_instr_hreturn::print(String *str) ...@@ -2982,10 +2982,20 @@ sp_instr_hreturn::print(String *str)
uint uint
sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads) sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
{ {
if (m_dest)
return sp_instr_jump::opt_mark(sp, leads);
marked= 1; marked= 1;
if (m_dest)
{
/*
This is an EXIT handler; next instruction step is in m_dest.
*/
return m_dest;
}
/*
This is a CONTINUE handler; next instruction step will come from
the handler stack and not from opt_mark.
*/
return UINT_MAX; return UINT_MAX;
} }
......
...@@ -973,6 +973,12 @@ class sp_instr_hreturn : public sp_instr_jump ...@@ -973,6 +973,12 @@ class sp_instr_hreturn : public sp_instr_jump
virtual void print(String *str); virtual void print(String *str);
/* This instruction will not be short cut optimized. */
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
{
return m_ip;
}
virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads); virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
private: private:
......
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