mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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.
This commit is contained in:
@ -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;
|
|||||||
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)
|
|||||||
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 @@ public:
|
|||||||
|
|
||||||
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:
|
||||||
|
Reference in New Issue
Block a user