mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
Save and clear run context before executing a stored function or trigger and restore it afterwards.
This allows us to use statement replication with functions and triggers The following things are fixed with this patch: - NOW() and automatic timestamps takes the value from the main event for functions and triggers (which allows these to replicate with statement level logging) - No side effects for triggers or functions with auto-increment values(), last_insert_id(), rand() or found_rows() - Triggers can't return result sets Fixes bugs: #12480: NOW() is not constant in a trigger #12481: Using NOW() in a stored function breaks statement based replication #12482: Triggers has side effects with auto_increment values #11587: trigger causes lost connection error mysql-test/r/trigger.result: Added test fpr big mysql-test/t/sp-error.test: Changed error message numbers mysql-test/t/trigger.test: Added test for trigger returning result (#11587) sql/item_func.cc: Store the first used seed value for RAND() value. (This makes rand() replicatable in functions and triggers) Save and clear run context before executing a stored function and restore it afterwards. This removes side effects of stored functions for RAND(), auto-increment values and NOW() and makes most stored function replicatable sql/share/errmsg.txt: Reuse error message also for triggers sql/sp_head.cc: If in function or trigger, don't change value of NOW() (This allows us to use statement replication with functions that directly or indirectly uses timestamps) sql/sql_class.cc: Added framework for storing and retrieving run context while exceuting triggers or stored functions. sql/sql_class.h: Added framework for storing and retrieving run context while exceuting triggers or stored functions. sql/sql_parse.cc: If in function or trigger, don't change value of NOW() (This allows us to use statement replication with functions that directly or indirectly uses timestamps) sql/sql_trigger.cc: Moved process_triggers function from sql_trigger.h Use reset/restore sub_statement_state while executing triggers to avoid side effects and make them replicatable sql/sql_trigger.h: Moved process_triggers function from sql_trigger.h Use reset/restore sub_statement_state while executing triggers to avoid side effects and make them replicatable sql/sql_yacc.yy: Give error message if trigger can return a result set (Bug #11587) tests/fork_big2.pl: Removed return from end of lines mysql-test/r/rpl_trigger.result: New BitKeeper file ``mysql-test/r/rpl_trigger.result'' mysql-test/t/rpl_trigger.test: New BitKeeper file ``mysql-test/t/rpl_trigger.test''
This commit is contained in:
108
mysql-test/r/rpl_trigger.result
Normal file
108
mysql-test/r/rpl_trigger.result
Normal file
@ -0,0 +1,108 @@
|
||||
stop slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
reset master;
|
||||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
create table t1 (a int auto_increment, primary key (a), b int, rand_value double not null);
|
||||
create table t2 (a int auto_increment, primary key (a), b int);
|
||||
create table t3 (a int auto_increment, primary key (a), name varchar(64) not null, old_a int, old_b int, rand_value double not null);
|
||||
create trigger t1 before insert on t1 for each row
|
||||
begin
|
||||
insert into t3 values (NULL, "t1", new.a, new.b, rand());
|
||||
end|
|
||||
create trigger t2 after insert on t2 for each row
|
||||
begin
|
||||
insert into t3 values (NULL, "t2", new.a, new.b, rand());
|
||||
end|
|
||||
insert into t3 values(100,"log",0,0,0);
|
||||
SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186;
|
||||
insert into t1 values(1,1,rand()),(NULL,2,rand());
|
||||
insert into t2 (b) values(last_insert_id());
|
||||
insert into t2 values(3,0),(NULL,0);
|
||||
insert into t2 values(NULL,0),(500,0);
|
||||
select a,b, truncate(rand_value,4) from t1;
|
||||
a b truncate(rand_value,4)
|
||||
1 1 0.4320
|
||||
2 2 0.3055
|
||||
select * from t2;
|
||||
a b
|
||||
1 2
|
||||
3 0
|
||||
4 0
|
||||
5 0
|
||||
500 0
|
||||
select a,name, old_a, old_b, truncate(rand_value,4) from t3;
|
||||
a name old_a old_b truncate(rand_value,4)
|
||||
100 log 0 0 0.0000
|
||||
101 t1 1 1 0.3203
|
||||
102 t1 0 2 0.5666
|
||||
103 t2 1 2 0.9164
|
||||
104 t2 3 0 0.8826
|
||||
105 t2 4 0 0.6635
|
||||
106 t2 5 0 0.6699
|
||||
107 t2 500 0 0.3593
|
||||
|
||||
--- On slave --
|
||||
select a,b, truncate(rand_value,4) from t1;
|
||||
a b truncate(rand_value,4)
|
||||
1 1 0.4320
|
||||
2 2 0.3055
|
||||
select * from t2;
|
||||
a b
|
||||
1 2
|
||||
3 0
|
||||
4 0
|
||||
5 0
|
||||
500 0
|
||||
select a,name, old_a, old_b, truncate(rand_value,4) from t3;
|
||||
a name old_a old_b truncate(rand_value,4)
|
||||
100 log 0 0 0.0000
|
||||
101 t1 1 1 0.3203
|
||||
102 t1 0 2 0.5666
|
||||
103 t2 1 2 0.9164
|
||||
104 t2 3 0 0.8826
|
||||
105 t2 4 0 0.6635
|
||||
106 t2 5 0 0.6699
|
||||
107 t2 500 0 0.3593
|
||||
drop table t1,t2,t3;
|
||||
select get_lock("bug12480",2);
|
||||
get_lock("bug12480",2)
|
||||
1
|
||||
create table t1 (a datetime,b datetime, c datetime);
|
||||
drop function if exists bug12480;
|
||||
Warnings:
|
||||
Note 1305 FUNCTION bug12480 does not exist
|
||||
create function bug12480() returns datetime
|
||||
begin
|
||||
set @a=get_lock("bug12480",2);
|
||||
return now();
|
||||
end|
|
||||
create trigger t1_first before insert on t1
|
||||
for each row begin
|
||||
set @a=get_lock("bug12480",2);
|
||||
set new.b= now();
|
||||
set new.c= bug12480();
|
||||
end
|
||||
|
|
||||
insert into t1 set a = now();
|
||||
select a=b && a=c from t1;
|
||||
a=b && a=c
|
||||
1
|
||||
|
||||
--- On slave --
|
||||
select a=b && a=c from t1;
|
||||
a=b && a=c
|
||||
1
|
||||
test
|
||||
1
|
||||
truncate table t1;
|
||||
drop trigger t1_first;
|
||||
insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now());
|
||||
select a=b && a=c from t1;
|
||||
a=b && a=c
|
||||
1
|
||||
1
|
||||
1
|
||||
drop function bug12480;
|
||||
drop table t1;
|
@ -664,3 +664,36 @@ end|
|
||||
update t1 set data = 1;
|
||||
update t1 set data = 2;
|
||||
drop table t1;
|
||||
create table t1 (c1 int, c2 datetime);
|
||||
create trigger tr1 before insert on t1 for each row
|
||||
begin
|
||||
set new.c2= '2004-04-01';
|
||||
select 'hello';
|
||||
end|
|
||||
ERROR 0A000: Not allowed to return a result set from a trigger
|
||||
insert into t1 (c1) values (1),(2),(3);
|
||||
select * from t1;
|
||||
c1 c2
|
||||
1 NULL
|
||||
2 NULL
|
||||
3 NULL
|
||||
drop procedure if exists bug11587;
|
||||
create procedure bug11587(x char(16))
|
||||
begin
|
||||
select "hello";
|
||||
select "hello again";
|
||||
end|
|
||||
create trigger tr1 before insert on t1 for each row
|
||||
begin
|
||||
call bug11587();
|
||||
set new.c2= '2004-04-02';
|
||||
end|
|
||||
insert into t1 (c1) values (4),(5),(6);
|
||||
ERROR 0A000: PROCEDURE test.bug11587 can't return a result set in the given context
|
||||
select * from t1;
|
||||
c1 c2
|
||||
1 NULL
|
||||
2 NULL
|
||||
3 NULL
|
||||
drop procedure bug11587;
|
||||
drop table t1;
|
||||
|
117
mysql-test/t/rpl_trigger.test
Normal file
117
mysql-test/t/rpl_trigger.test
Normal file
@ -0,0 +1,117 @@
|
||||
#
|
||||
# Test of triggers with replication
|
||||
#
|
||||
|
||||
source include/master-slave.inc;
|
||||
|
||||
#
|
||||
# #12482: Triggers has side effects with auto_increment values
|
||||
#
|
||||
|
||||
create table t1 (a int auto_increment, primary key (a), b int, rand_value double not null);
|
||||
create table t2 (a int auto_increment, primary key (a), b int);
|
||||
create table t3 (a int auto_increment, primary key (a), name varchar(64) not null, old_a int, old_b int, rand_value double not null);
|
||||
|
||||
delimiter |;
|
||||
create trigger t1 before insert on t1 for each row
|
||||
begin
|
||||
insert into t3 values (NULL, "t1", new.a, new.b, rand());
|
||||
end|
|
||||
|
||||
create trigger t2 after insert on t2 for each row
|
||||
begin
|
||||
insert into t3 values (NULL, "t2", new.a, new.b, rand());
|
||||
end|
|
||||
delimiter ;|
|
||||
|
||||
insert into t3 values(100,"log",0,0,0);
|
||||
|
||||
# Ensure we always have same random numbers
|
||||
SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186;
|
||||
|
||||
# Emulate that we have rows 2-9 deleted on the slave
|
||||
insert into t1 values(1,1,rand()),(NULL,2,rand());
|
||||
insert into t2 (b) values(last_insert_id());
|
||||
insert into t2 values(3,0),(NULL,0);
|
||||
insert into t2 values(NULL,0),(500,0);
|
||||
|
||||
select a,b, truncate(rand_value,4) from t1;
|
||||
select * from t2;
|
||||
select a,name, old_a, old_b, truncate(rand_value,4) from t3;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
--disable_query_log
|
||||
select "--- On slave --" as "";
|
||||
--enable_query_log
|
||||
select a,b, truncate(rand_value,4) from t1;
|
||||
select * from t2;
|
||||
select a,name, old_a, old_b, truncate(rand_value,4) from t3;
|
||||
connection master;
|
||||
drop table t1,t2,t3;
|
||||
|
||||
#
|
||||
# #12480: NOW() is not constant in a trigger
|
||||
# #12481: Using NOW() in a stored function breaks statement based replication
|
||||
#
|
||||
|
||||
# Start by getting a lock on 'bug12480' to be able to use get_lock() as sleep()
|
||||
connect (con2,localhost,root,,);
|
||||
connection con2;
|
||||
select get_lock("bug12480",2);
|
||||
connection default;
|
||||
|
||||
create table t1 (a datetime,b datetime, c datetime);
|
||||
--ignore_warnings
|
||||
drop function if exists bug12480;
|
||||
--enable_warnings
|
||||
|
||||
delimiter |;
|
||||
|
||||
create function bug12480() returns datetime
|
||||
begin
|
||||
set @a=get_lock("bug12480",2);
|
||||
return now();
|
||||
end|
|
||||
|
||||
create trigger t1_first before insert on t1
|
||||
for each row begin
|
||||
set @a=get_lock("bug12480",2);
|
||||
set new.b= now();
|
||||
set new.c= bug12480();
|
||||
end
|
||||
|
|
||||
|
||||
delimiter ;|
|
||||
insert into t1 set a = now();
|
||||
select a=b && a=c from t1;
|
||||
let $time=`select a from t1`;
|
||||
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
--disable_query_log
|
||||
select "--- On slave --" as "";
|
||||
--enable_query_log
|
||||
select a=b && a=c from t1;
|
||||
--disable_query_log
|
||||
eval select a='$time' as 'test' from t1;
|
||||
--enable_query_log
|
||||
|
||||
connection master;
|
||||
disconnect con2;
|
||||
|
||||
truncate table t1;
|
||||
drop trigger t1_first;
|
||||
|
||||
insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now());
|
||||
select a=b && a=c from t1;
|
||||
|
||||
drop function bug12480;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# End of test
|
||||
#
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
@ -811,19 +811,19 @@ end|
|
||||
#
|
||||
|
||||
# Some things are caught when parsing
|
||||
--error ER_SP_NO_RETSET_IN_FUNC
|
||||
--error ER_SP_NO_RETSET
|
||||
create function bug8408() returns int
|
||||
begin
|
||||
select * from t1;
|
||||
return 0;
|
||||
end|
|
||||
--error ER_SP_NO_RETSET_IN_FUNC
|
||||
--error ER_SP_NO_RETSET
|
||||
create function bug8408() returns int
|
||||
begin
|
||||
show warnings;
|
||||
return 0;
|
||||
end|
|
||||
--error ER_SP_NO_RETSET_IN_FUNC
|
||||
--error ER_SP_NO_RETSET
|
||||
create function bug8408(a int) returns int
|
||||
begin
|
||||
declare b int;
|
||||
|
@ -665,6 +665,7 @@ drop table t1;
|
||||
|
||||
# Test for bug #11973 "SELECT .. INTO var_name; in trigger cause
|
||||
# crash on update"
|
||||
|
||||
create table t1 (id int, data int, username varchar(16));
|
||||
insert into t1 (id, data) values (1, 0);
|
||||
delimiter |;
|
||||
@ -684,4 +685,47 @@ connection addconroot;
|
||||
update t1 set data = 2;
|
||||
|
||||
connection default;
|
||||
disconnect addconroot;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# #11587 Trigger causes lost connection error
|
||||
#
|
||||
|
||||
create table t1 (c1 int, c2 datetime);
|
||||
delimiter |;
|
||||
--error ER_SP_NO_RETSET
|
||||
create trigger tr1 before insert on t1 for each row
|
||||
begin
|
||||
set new.c2= '2004-04-01';
|
||||
select 'hello';
|
||||
end|
|
||||
delimiter ;|
|
||||
|
||||
insert into t1 (c1) values (1),(2),(3);
|
||||
select * from t1;
|
||||
|
||||
--disable_warnings
|
||||
drop procedure if exists bug11587;
|
||||
--enable_warnings
|
||||
|
||||
delimiter |;
|
||||
create procedure bug11587(x char(16))
|
||||
begin
|
||||
select "hello";
|
||||
select "hello again";
|
||||
end|
|
||||
|
||||
create trigger tr1 before insert on t1 for each row
|
||||
begin
|
||||
call bug11587();
|
||||
set new.c2= '2004-04-02';
|
||||
end|
|
||||
delimiter ;|
|
||||
|
||||
--error 726
|
||||
insert into t1 (c1) values (4),(5),(6);
|
||||
select * from t1;
|
||||
|
||||
drop procedure bug11587;
|
||||
drop table t1;
|
||||
|
Reference in New Issue
Block a user