mirror of
https://github.com/MariaDB/server.git
synced 2025-08-09 22:24:09 +03:00
handling of savepoints in stored routines. Fixed ha_rollback_to_savepoint()/ha_savepoint()/ha_release_savepoint() functions to properly handle savepoints inside of stored functions and triggers. Also now when we invoke stored function or trigger we create new savepoint level. We destroy it at the end of function/trigger execution and return back to old savepoint level. mysql-test/r/sp_trans.result: Added test for bug #13825 "Triggers: crash if release savepoint" and for general handling of savepoints in stored routines. mysql-test/t/sp_trans.test: Added test for bug #13825 "Triggers: crash if release savepoint" and for general handling of savepoints in stored routines. sql/ha_innodb.cc: innobase_savepoint(): Replaced check which always failed due to similar check in caller with assertion. sql/handler.cc: ha_rollback_to_savepoint()/ha_savepoint()/ha_release_savepoint(): Changed functions to properly support handling of savepoints inside of stored functions and triggers. sql/sql_class.cc: THD::reset_sub_statement_state()/restore_sub_statement_state(): When we invoke stored function or trigger we should create new savepoint level. We should destroy it at the end of function/trigger execution and return back to old savepoint level. To support this behavior we should save and reset list of current savepoints on entering function and restore old list when we leave it. sql/sql_class.h: Sub_statement_state: When we invoke stored function or trigger we should create new savepoint level. We should destroy it at the end of function/trigger execution and return back to old savepoint level. To support this behavior added "savepoint" member which is used to save/restore list of current savepoints on entering/leaving function. sql/sql_parse.cc: mysql_execute_command(): Changed processing of SQLCOM_SAVEPOINT so now it is not ignored when we are in autocommit mode and savepoint is set inside of stored function or trigger.
367 lines
9.2 KiB
Plaintext
367 lines
9.2 KiB
Plaintext
#
|
|
# tests that require InnoDB...
|
|
#
|
|
|
|
-- source include/have_innodb.inc
|
|
|
|
--disable_warnings
|
|
drop table if exists t1, t2;
|
|
--enable_warnings
|
|
|
|
delimiter |;
|
|
|
|
#
|
|
# BUG#8850: Truncate table in a stored procedure locks the tables
|
|
#
|
|
--disable_warnings
|
|
drop procedure if exists bug8850|
|
|
--enable_warnings
|
|
create table t1 (a int) engine=innodb|
|
|
create procedure bug8850()
|
|
begin
|
|
truncate table t1; insert t1 values (1); rollback;
|
|
end|
|
|
|
|
set autocommit=0|
|
|
insert t1 values (2)|
|
|
call bug8850()|
|
|
commit|
|
|
select * from t1|
|
|
|
|
call bug8850()|
|
|
set autocommit=1|
|
|
select * from t1|
|
|
drop table t1|
|
|
drop procedure bug8850|
|
|
|
|
|
|
#
|
|
# BUG#10015: Crash in InnoDB if stored routines are used
|
|
# (crash happens in auto-commit mode)
|
|
#
|
|
--disable_warnings
|
|
drop function if exists bug10015_1|
|
|
drop function if exists bug10015_2|
|
|
drop function if exists bug10015_3|
|
|
drop function if exists bug10015_4|
|
|
drop function if exists bug10015_5|
|
|
drop function if exists bug10015_6|
|
|
drop function if exists bug10015_7|
|
|
drop procedure if exists bug10015_8|
|
|
--enable_warnings
|
|
create table t1 (id int) engine=innodb|
|
|
create table t2 (id int primary key, j int) engine=innodb|
|
|
insert into t1 values (1),(2),(3)|
|
|
create function bug10015_1() returns int return (select count(*) from t1)|
|
|
select *, bug10015_1() from t1|
|
|
drop function bug10015_1|
|
|
# Test couple of a bit more complex cases
|
|
create function bug10015_2() returns int
|
|
begin
|
|
declare i, s int;
|
|
set i:= (select min(id) from t1);
|
|
set s:= (select max(id) from t1);
|
|
return (s - i);
|
|
end|
|
|
select *, bug10015_2() from t1|
|
|
drop function bug10015_2|
|
|
create function bug10015_3() returns int
|
|
return (select max(a.id - b.id) from t1 as a, t1 as b where a.id >= b.id)|
|
|
select *, bug10015_3() from t1|
|
|
drop function bug10015_3|
|
|
create function bug10015_4(i int) returns int
|
|
begin
|
|
declare m int;
|
|
set m:= (select max(id) from t2);
|
|
insert into t2 values (i, m);
|
|
return m;
|
|
end|
|
|
select *, bug10015_4(id) from t1|
|
|
select * from t2|
|
|
drop function bug10015_4|
|
|
# Now let us test how statement rollback works
|
|
# This function will cause the whole stmt to be rolled back,
|
|
# there should not be any traces left.
|
|
create function bug10015_5(i int) returns int
|
|
begin
|
|
if (i = 5) then
|
|
insert into t2 values (1, 0);
|
|
end if;
|
|
return i;
|
|
end|
|
|
--error 1062
|
|
insert into t1 values (bug10015_5(4)), (bug10015_5(5))|
|
|
select * from t1|
|
|
drop function bug10015_5|
|
|
# Thanks to error-handler this function should not cause rollback
|
|
# of statement calling it. But insert statement in it should be
|
|
# rolled back completely and don't leave any traces in t2.
|
|
# Unfortunately we can't implement such behavior in 5.0, so it
|
|
# is something to be fixed in later 5.* releases (TODO).
|
|
create function bug10015_6(i int) returns int
|
|
begin
|
|
declare continue handler for sqlexception set @error_in_func:= 1;
|
|
if (i = 5) then
|
|
insert into t2 values (4, 0), (1, 0);
|
|
end if;
|
|
return i;
|
|
end|
|
|
set @error_in_func:= 0|
|
|
insert into t1 values (bug10015_6(5)), (bug10015_6(6))|
|
|
select @error_in_func|
|
|
select * from t1|
|
|
select * from t2|
|
|
drop function bug10015_6|
|
|
# Let us test that we don't allow any statements causing transaction
|
|
# commit in stored functions (we test only most interesting cases here).
|
|
# Cases which can be caught at creation time:
|
|
--error 1422
|
|
create function bug10015_7() returns int
|
|
begin
|
|
alter table t1 add k int;
|
|
return 1;
|
|
end|
|
|
--error 1422
|
|
create function bug10015_7() returns int
|
|
begin
|
|
start transaction;
|
|
return 1;
|
|
end|
|
|
--error 1422
|
|
create function bug10015_7() returns int
|
|
begin
|
|
drop table t1;
|
|
return 1;
|
|
end|
|
|
# It should be OK to drop temporary table.
|
|
create function bug10015_7() returns int
|
|
begin
|
|
drop temporary table t1;
|
|
return 1;
|
|
end|
|
|
drop function bug10015_7|
|
|
--error 1422
|
|
create function bug10015_7() returns int
|
|
begin
|
|
commit;
|
|
return 1;
|
|
end|
|
|
# Now let us test cases which we can catch only at run-time:
|
|
create function bug10015_7() returns int
|
|
begin
|
|
call bug10015_8();
|
|
return 1;
|
|
end|
|
|
create procedure bug10015_8() alter table t1 add k int|
|
|
--error 1422
|
|
select *, bug10015_7() from t1|
|
|
drop procedure bug10015_8|
|
|
create procedure bug10015_8() start transaction|
|
|
--error 1422
|
|
select *, bug10015_7() from t1|
|
|
drop procedure bug10015_8|
|
|
# Again it is OK to drop temporary table
|
|
# We are surpressing warnings since they are not essential
|
|
create procedure bug10015_8() drop temporary table if exists t1_temp|
|
|
--disable_warnings
|
|
select *, bug10015_7() from t1|
|
|
--enable_warnings
|
|
drop procedure bug10015_8|
|
|
create procedure bug10015_8() commit|
|
|
--error 1422
|
|
select *, bug10015_7() from t1|
|
|
drop procedure bug10015_8|
|
|
drop function bug10015_7|
|
|
drop table t1, t2|
|
|
|
|
|
|
#
|
|
# BUG#13825 "Triggers: crash if release savepoint".
|
|
# Also general test for handling of savepoints in stored routines.
|
|
#
|
|
# According to SQL standard we should establish new savepoint
|
|
# level before executing stored function/trigger and destroy
|
|
# this savepoint level after execution. Stored procedures by
|
|
# default should be executed using the same savepoint level
|
|
# as their caller (to execute stored procedure using new
|
|
# savepoint level one should explicitly specify NEW SAVEPOINT
|
|
# LEVEL clause in procedure creation statement which MySQL
|
|
# does not support yet).
|
|
--disable_warnings
|
|
drop function if exists bug13825_0|
|
|
drop function if exists bug13825_1|
|
|
drop function if exists bug13825_2|
|
|
drop function if exists bug13825_3|
|
|
drop function if exists bug13825_4|
|
|
drop function if exists bug13825_5|
|
|
drop procedure if exists bug13825_0|
|
|
drop procedure if exists bug13825_1|
|
|
drop procedure if exists bug13825_2|
|
|
drop table if exists t1|
|
|
--enable_warnings
|
|
create table t1 (i int) engine=innodb|
|
|
create table t2 (i int) engine=innodb|
|
|
create function bug13825_0() returns int
|
|
begin
|
|
rollback to savepoint x;
|
|
return 1;
|
|
end|
|
|
create function bug13825_1() returns int
|
|
begin
|
|
release savepoint x;
|
|
return 1;
|
|
end|
|
|
create function bug13825_2() returns int
|
|
begin
|
|
insert into t1 values (2);
|
|
savepoint x;
|
|
insert into t1 values (3);
|
|
rollback to savepoint x;
|
|
insert into t1 values (4);
|
|
return 1;
|
|
end|
|
|
create procedure bug13825_0()
|
|
begin
|
|
rollback to savepoint x;
|
|
end|
|
|
create procedure bug13825_1()
|
|
begin
|
|
release savepoint x;
|
|
end|
|
|
create procedure bug13825_2()
|
|
begin
|
|
savepoint x;
|
|
end|
|
|
insert into t2 values (1)|
|
|
create trigger t2_bi before insert on t2 for each row
|
|
rollback to savepoint x|
|
|
create trigger t2_bu before update on t2 for each row
|
|
release savepoint x|
|
|
create trigger t2_bd before delete on t2 for each row
|
|
begin
|
|
insert into t1 values (2);
|
|
savepoint x;
|
|
insert into t1 values (3);
|
|
rollback to savepoint x;
|
|
insert into t1 values (4);
|
|
end|
|
|
create function bug13825_3(rb int) returns int
|
|
begin
|
|
insert into t1 values(1);
|
|
savepoint x;
|
|
insert into t1 values(2);
|
|
if rb then
|
|
rollback to savepoint x;
|
|
end if;
|
|
insert into t1 values(3);
|
|
return rb;
|
|
end|
|
|
create function bug13825_4() returns int
|
|
begin
|
|
savepoint x;
|
|
insert into t1 values(2);
|
|
rollback to savepoint x;
|
|
return 0;
|
|
end|
|
|
create function bug13825_5(p int) returns int
|
|
begin
|
|
savepoint x;
|
|
insert into t2 values(p);
|
|
rollback to savepoint x;
|
|
insert into t2 values(p+1);
|
|
return p;
|
|
end|
|
|
set autocommit= 0|
|
|
# Test of savepoint level handling for stored functions and triggers
|
|
begin |
|
|
insert into t1 values (1)|
|
|
savepoint x|
|
|
--error ER_SP_DOES_NOT_EXIST
|
|
set @a:= bug13825_0()|
|
|
--error ER_SP_DOES_NOT_EXIST
|
|
insert into t2 values (2)|
|
|
--error ER_SP_DOES_NOT_EXIST
|
|
set @a:= bug13825_1()|
|
|
--error ER_SP_DOES_NOT_EXIST
|
|
update t2 set i = 2|
|
|
set @a:= bug13825_2()|
|
|
select * from t1|
|
|
rollback to savepoint x|
|
|
select * from t1|
|
|
delete from t2|
|
|
select * from t1|
|
|
rollback to savepoint x|
|
|
select * from t1|
|
|
# Of course savepoints set in function should not be visible from its caller
|
|
release savepoint x|
|
|
set @a:= bug13825_2()|
|
|
select * from t1|
|
|
--error ER_SP_DOES_NOT_EXIST
|
|
rollback to savepoint x|
|
|
delete from t1|
|
|
commit|
|
|
# Test of savepoint level handling for stored procedures
|
|
begin|
|
|
insert into t1 values (5)|
|
|
savepoint x|
|
|
insert into t1 values (6)|
|
|
call bug13825_0()|
|
|
select * from t1|
|
|
call bug13825_1()|
|
|
--error ER_SP_DOES_NOT_EXIST
|
|
rollback to savepoint x|
|
|
savepoint x|
|
|
insert into t1 values (7)|
|
|
call bug13825_2()|
|
|
rollback to savepoint x|
|
|
select * from t1|
|
|
delete from t1|
|
|
commit|
|
|
set autocommit= 1|
|
|
# Let us test that savepoints work inside of functions
|
|
# even in auto-commit mode
|
|
select bug13825_3(0)|
|
|
select * from t1|
|
|
delete from t1|
|
|
select bug13825_3(1)|
|
|
select * from t1|
|
|
delete from t1|
|
|
# Curious case: rolling back to savepoint which is set by first
|
|
# statement in function should not rollback whole transaction.
|
|
set autocommit= 0|
|
|
begin|
|
|
insert into t1 values (1)|
|
|
set @a:= bug13825_4()|
|
|
select * from t1|
|
|
delete from t1|
|
|
commit|
|
|
set autocommit= 1|
|
|
# Other curious case: savepoint in the middle of statement
|
|
drop table t2|
|
|
create table t2 (i int) engine=innodb|
|
|
insert into t1 values (1), (bug13825_5(2)), (3)|
|
|
select * from t1|
|
|
select * from t2|
|
|
# Cleanup
|
|
drop function bug13825_0|
|
|
drop function bug13825_1|
|
|
drop function bug13825_2|
|
|
drop function bug13825_3|
|
|
drop function bug13825_4|
|
|
drop function bug13825_5|
|
|
drop procedure bug13825_0|
|
|
drop procedure bug13825_1|
|
|
drop procedure bug13825_2|
|
|
drop table t1, t2|
|
|
|
|
|
|
#
|
|
# BUG#NNNN: New bug synopsis
|
|
#
|
|
#--disable_warnings
|
|
#drop procedure if exists bugNNNN|
|
|
#--enable_warnings
|
|
#create procedure bugNNNN...
|
|
|
|
delimiter ;|
|