Loading mysql-test/r/trigger-trans.result +59 −0 Original line number Diff line number Diff line Loading @@ -82,3 +82,62 @@ ALICE 33 1 0 THE CROWN 43 1 0 THE PIE 53 1 1 drop table t1; Bug#26141 mixing table types in trigger causes full table lock on innodb table Ensure we do not open and lock tables for the triggers we do not fire. drop table if exists t1, t2, t3; drop trigger if exists trg_bug26141_au; drop trigger if exists trg_bug26141_ai; create table t1 (c int primary key) engine=innodb; create table t2 (c int) engine=myisam; create table t3 (c int) engine=myisam; insert into t1 (c) values (1); create trigger trg_bug26141_ai after insert on t1 for each row begin insert into t2 (c) values (1); # We need the 'sync' lock to synchronously wait in connection 2 till # the moment when the trigger acquired all the locks. select release_lock("lock_bug26141_sync") into @a; # 1000 is time in seconds of lock wait timeout -- this is a way # to cause a manageable sleep up to 1000 seconds select get_lock("lock_bug26141_wait", 1000) into @a; end| create trigger trg_bug26141_au after update on t1 for each row begin insert into t3 (c) values (1); end| select get_lock("lock_bug26141_wait", 0); get_lock("lock_bug26141_wait", 0) 1 select get_lock("lock_bug26141_sync", /* must not be priorly locked */ 0); get_lock("lock_bug26141_sync", /* must not be priorly locked */ 0) 1 insert into t1 (c) values (2); select get_lock("lock_bug26141_sync", 1000); get_lock("lock_bug26141_sync", 1000) 1 update t1 set c=3 where c=1; select release_lock("lock_bug26141_sync"); release_lock("lock_bug26141_sync") 1 select release_lock("lock_bug26141_wait"); release_lock("lock_bug26141_wait") 1 select * from t1; c 2 3 select * from t2; c 1 select * from t3; c 1 drop table t1, t2, t3; End of 5.0 tests mysql-test/r/trigger.result +457 −0 Original line number Diff line number Diff line Loading @@ -1476,4 +1476,461 @@ DROP TRIGGER t1_test; DROP TABLE t1,t2; SET SESSION LOW_PRIORITY_UPDATES=DEFAULT; SET GLOBAL LOW_PRIORITY_UPDATES=DEFAULT; Bug#28502 Triggers that update another innodb table will block on X lock unnecessarily Ensure we do not open and lock tables for triggers we do not fire. drop table if exists t1, t2; drop trigger if exists trg_bug28502_au; create table t1 (id int, count int); create table t2 (id int); create trigger trg_bug28502_au before update on t2 for each row begin if (new.id is not null) then update t1 set count= count + 1 where id = old.id; end if; end| insert into t1 (id, count) values (1, 0); lock table t1 write; insert into t2 set id=1; unlock tables; update t2 set id=1 where id=1; select * from t1; id count 1 1 select * from t2; id 1 drop table t1, t2; Additionally, provide test coverage for triggers and all MySQL data changing commands. drop table if exists t1, t2, t1_op_log; drop view if exists v1; drop trigger if exists trg_bug28502_bi; drop trigger if exists trg_bug28502_ai; drop trigger if exists trg_bug28502_bu; drop trigger if exists trg_bug28502_au; drop trigger if exists trg_bug28502_bd; drop trigger if exists trg_bug28502_ad; create table t1 (id int primary key auto_increment, operation varchar(255)); create table t2 (id int primary key); create table t1_op_log(operation varchar(255)); create view v1 as select * from t1; create trigger trg_bug28502_bi before insert on t1 for each row insert into t1_op_log (operation) values (concat("Before INSERT, new=", new.operation)); create trigger trg_bug28502_ai after insert on t1 for each row insert into t1_op_log (operation) values (concat("After INSERT, new=", new.operation)); create trigger trg_bug28502_bu before update on t1 for each row insert into t1_op_log (operation) values (concat("Before UPDATE, new=", new.operation, ", old=", old.operation)); create trigger trg_bug28502_au after update on t1 for each row insert into t1_op_log (operation) values (concat("After UPDATE, new=", new.operation, ", old=", old.operation)); create trigger trg_bug28502_bd before delete on t1 for each row insert into t1_op_log (operation) values (concat("Before DELETE, old=", old.operation)); create trigger trg_bug28502_ad after delete on t1 for each row insert into t1_op_log (operation) values (concat("After DELETE, old=", old.operation)); insert into t1 (operation) values ("INSERT"); set @id=last_insert_id(); select * from t1; id operation 1 INSERT select * from t1_op_log; operation Before INSERT, new=INSERT After INSERT, new=INSERT truncate t1_op_log; update t1 set operation="UPDATE" where id=@id; select * from t1; id operation 1 UPDATE select * from t1_op_log; operation Before UPDATE, new=UPDATE, old=INSERT After UPDATE, new=UPDATE, old=INSERT truncate t1_op_log; delete from t1 where id=@id; select * from t1; id operation select * from t1_op_log; operation Before DELETE, old=UPDATE After DELETE, old=UPDATE truncate t1; truncate t1_op_log; insert into t1 (id, operation) values (NULL, "INSERT ON DUPLICATE KEY UPDATE, inserting a new key") on duplicate key update id=NULL, operation="Should never happen"; set @id=last_insert_id(); select * from t1; id operation 1 INSERT ON DUPLICATE KEY UPDATE, inserting a new key select * from t1_op_log; operation Before INSERT, new=INSERT ON DUPLICATE KEY UPDATE, inserting a new key After INSERT, new=INSERT ON DUPLICATE KEY UPDATE, inserting a new key truncate t1_op_log; insert into t1 (id, operation) values (@id, "INSERT ON DUPLICATE KEY UPDATE, the key value is the same") on duplicate key update id=NULL, operation="INSERT ON DUPLICATE KEY UPDATE, updating the duplicate"; select * from t1; id operation 0 INSERT ON DUPLICATE KEY UPDATE, updating the duplicate select * from t1_op_log; operation Before INSERT, new=INSERT ON DUPLICATE KEY UPDATE, the key value is the same Before UPDATE, new=INSERT ON DUPLICATE KEY UPDATE, updating the duplicate, old=INSERT ON DUPLICATE KEY UPDATE, inserting a new key After UPDATE, new=INSERT ON DUPLICATE KEY UPDATE, updating the duplicate, old=INSERT ON DUPLICATE KEY UPDATE, inserting a new key truncate t1; truncate t1_op_log; replace into t1 values (NULL, "REPLACE, inserting a new key"); set @id=last_insert_id(); select * from t1; id operation 1 REPLACE, inserting a new key select * from t1_op_log; operation Before INSERT, new=REPLACE, inserting a new key After INSERT, new=REPLACE, inserting a new key truncate t1_op_log; replace into t1 values (@id, "REPLACE, deleting the duplicate"); select * from t1; id operation 1 REPLACE, deleting the duplicate select * from t1_op_log; operation Before INSERT, new=REPLACE, deleting the duplicate Before DELETE, old=REPLACE, inserting a new key After DELETE, old=REPLACE, inserting a new key After INSERT, new=REPLACE, deleting the duplicate truncate t1; truncate t1_op_log; create table if not exists t1 select NULL, "CREATE TABLE ... SELECT, inserting a new key"; Warnings: Note 1050 Table 't1' already exists set @id=last_insert_id(); select * from t1; id operation 1 CREATE TABLE ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=CREATE TABLE ... SELECT, inserting a new key After INSERT, new=CREATE TABLE ... SELECT, inserting a new key truncate t1_op_log; create table if not exists t1 replace select @id, "CREATE TABLE ... REPLACE SELECT, deleting a duplicate key"; Warnings: Note 1050 Table 't1' already exists select * from t1; id operation 1 CREATE TABLE ... REPLACE SELECT, deleting a duplicate key select * from t1_op_log; operation Before INSERT, new=CREATE TABLE ... REPLACE SELECT, deleting a duplicate key Before DELETE, old=CREATE TABLE ... SELECT, inserting a new key After DELETE, old=CREATE TABLE ... SELECT, inserting a new key After INSERT, new=CREATE TABLE ... REPLACE SELECT, deleting a duplicate key truncate t1; truncate t1_op_log; insert into t1 (id, operation) select NULL, "INSERT ... SELECT, inserting a new key"; set @id=last_insert_id(); select * from t1; id operation 1 INSERT ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=INSERT ... SELECT, inserting a new key After INSERT, new=INSERT ... SELECT, inserting a new key truncate t1_op_log; insert into t1 (id, operation) select @id, "INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate" on duplicate key update id=NULL, operation="INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate"; select * from t1; id operation 0 INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate select * from t1_op_log; operation Before INSERT, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate Before UPDATE, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate, old=INSERT ... SELECT, inserting a new key After UPDATE, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate, old=INSERT ... SELECT, inserting a new key truncate t1; truncate t1_op_log; replace into t1 (id, operation) select NULL, "REPLACE ... SELECT, inserting a new key"; set @id=last_insert_id(); select * from t1; id operation 1 REPLACE ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=REPLACE ... SELECT, inserting a new key After INSERT, new=REPLACE ... SELECT, inserting a new key truncate t1_op_log; replace into t1 (id, operation) select @id, "REPLACE ... SELECT, deleting a duplicate"; select * from t1; id operation 1 REPLACE ... SELECT, deleting a duplicate select * from t1_op_log; operation Before INSERT, new=REPLACE ... SELECT, deleting a duplicate Before DELETE, old=REPLACE ... SELECT, inserting a new key After DELETE, old=REPLACE ... SELECT, inserting a new key After INSERT, new=REPLACE ... SELECT, deleting a duplicate truncate t1; truncate t1_op_log; insert into t1 (id, operation) values (1, "INSERT for multi-DELETE"); insert into t2 (id) values (1); delete t1.*, t2.* from t1, t2 where t1.id=1; select * from t1; id operation select * from t2; id select * from t1_op_log; operation Before INSERT, new=INSERT for multi-DELETE After INSERT, new=INSERT for multi-DELETE Before DELETE, old=INSERT for multi-DELETE After DELETE, old=INSERT for multi-DELETE truncate t1; truncate t2; truncate t1_op_log; insert into t1 (id, operation) values (1, "INSERT for multi-UPDATE"); insert into t2 (id) values (1); update t1, t2 set t1.id=2, operation="multi-UPDATE" where t1.id=1; update t1, t2 set t2.id=3, operation="multi-UPDATE, SET for t2, but the trigger is fired" where t1.id=2; select * from t1; id operation 2 multi-UPDATE, SET for t2, but the trigger is fired select * from t2; id 3 select * from t1_op_log; operation Before INSERT, new=INSERT for multi-UPDATE After INSERT, new=INSERT for multi-UPDATE Before UPDATE, new=multi-UPDATE, old=INSERT for multi-UPDATE After UPDATE, new=multi-UPDATE, old=INSERT for multi-UPDATE Before UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi-UPDATE After UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi-UPDATE truncate table t1; truncate table t2; truncate table t1_op_log; Now do the same but use a view instead of the base table. insert into v1 (operation) values ("INSERT"); set @id=last_insert_id(); select * from t1; id operation 1 INSERT select * from t1_op_log; operation Before INSERT, new=INSERT After INSERT, new=INSERT truncate t1_op_log; update v1 set operation="UPDATE" where id=@id; select * from t1; id operation 1 UPDATE select * from t1_op_log; operation Before UPDATE, new=UPDATE, old=INSERT After UPDATE, new=UPDATE, old=INSERT truncate t1_op_log; delete from v1 where id=@id; select * from t1; id operation select * from t1_op_log; operation Before DELETE, old=UPDATE After DELETE, old=UPDATE truncate t1; truncate t1_op_log; insert into v1 (id, operation) values (NULL, "INSERT ON DUPLICATE KEY UPDATE, inserting a new key") on duplicate key update id=NULL, operation="Should never happen"; set @id=last_insert_id(); select * from t1; id operation 1 INSERT ON DUPLICATE KEY UPDATE, inserting a new key select * from t1_op_log; operation Before INSERT, new=INSERT ON DUPLICATE KEY UPDATE, inserting a new key After INSERT, new=INSERT ON DUPLICATE KEY UPDATE, inserting a new key truncate t1_op_log; insert into v1 (id, operation) values (@id, "INSERT ON DUPLICATE KEY UPDATE, the key value is the same") on duplicate key update id=NULL, operation="INSERT ON DUPLICATE KEY UPDATE, updating the duplicate"; select * from t1; id operation 0 INSERT ON DUPLICATE KEY UPDATE, updating the duplicate select * from t1_op_log; operation Before INSERT, new=INSERT ON DUPLICATE KEY UPDATE, the key value is the same Before UPDATE, new=INSERT ON DUPLICATE KEY UPDATE, updating the duplicate, old=INSERT ON DUPLICATE KEY UPDATE, inserting a new key After UPDATE, new=INSERT ON DUPLICATE KEY UPDATE, updating the duplicate, old=INSERT ON DUPLICATE KEY UPDATE, inserting a new key truncate t1; truncate t1_op_log; replace into v1 values (NULL, "REPLACE, inserting a new key"); set @id=last_insert_id(); select * from t1; id operation 1 REPLACE, inserting a new key select * from t1_op_log; operation Before INSERT, new=REPLACE, inserting a new key After INSERT, new=REPLACE, inserting a new key truncate t1_op_log; replace into v1 values (@id, "REPLACE, deleting the duplicate"); select * from t1; id operation 1 REPLACE, deleting the duplicate select * from t1_op_log; operation Before INSERT, new=REPLACE, deleting the duplicate Before DELETE, old=REPLACE, inserting a new key After DELETE, old=REPLACE, inserting a new key After INSERT, new=REPLACE, deleting the duplicate truncate t1; truncate t1_op_log; create table if not exists v1 select NULL, "CREATE TABLE ... SELECT, inserting a new key"; Warnings: Note 1050 Table 'v1' already exists set @id=last_insert_id(); select * from t1; id operation 1 CREATE TABLE ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=CREATE TABLE ... SELECT, inserting a new key After INSERT, new=CREATE TABLE ... SELECT, inserting a new key truncate t1_op_log; create table if not exists v1 replace select @id, "CREATE TABLE ... REPLACE SELECT, deleting a duplicate key"; Warnings: Note 1050 Table 'v1' already exists select * from t1; id operation 1 CREATE TABLE ... REPLACE SELECT, deleting a duplicate key select * from t1_op_log; operation Before INSERT, new=CREATE TABLE ... REPLACE SELECT, deleting a duplicate key Before DELETE, old=CREATE TABLE ... SELECT, inserting a new key After DELETE, old=CREATE TABLE ... SELECT, inserting a new key After INSERT, new=CREATE TABLE ... REPLACE SELECT, deleting a duplicate key truncate t1; truncate t1_op_log; insert into v1 (id, operation) select NULL, "INSERT ... SELECT, inserting a new key"; set @id=last_insert_id(); select * from t1; id operation 1 INSERT ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=INSERT ... SELECT, inserting a new key After INSERT, new=INSERT ... SELECT, inserting a new key truncate t1_op_log; insert into v1 (id, operation) select @id, "INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate" on duplicate key update id=NULL, operation="INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate"; select * from t1; id operation 0 INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate select * from t1_op_log; operation Before INSERT, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate Before UPDATE, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate, old=INSERT ... SELECT, inserting a new key After UPDATE, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate, old=INSERT ... SELECT, inserting a new key truncate t1; truncate t1_op_log; replace into v1 (id, operation) select NULL, "REPLACE ... SELECT, inserting a new key"; set @id=last_insert_id(); select * from t1; id operation 1 REPLACE ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=REPLACE ... SELECT, inserting a new key After INSERT, new=REPLACE ... SELECT, inserting a new key truncate t1_op_log; replace into v1 (id, operation) select @id, "REPLACE ... SELECT, deleting a duplicate"; select * from t1; id operation 1 REPLACE ... SELECT, deleting a duplicate select * from t1_op_log; operation Before INSERT, new=REPLACE ... SELECT, deleting a duplicate Before DELETE, old=REPLACE ... SELECT, inserting a new key After DELETE, old=REPLACE ... SELECT, inserting a new key After INSERT, new=REPLACE ... SELECT, deleting a duplicate truncate t1; truncate t1_op_log; insert into v1 (id, operation) values (1, "INSERT for multi-DELETE"); insert into t2 (id) values (1); delete v1.*, t2.* from v1, t2 where v1.id=1; select * from t1; id operation select * from t2; id select * from t1_op_log; operation Before INSERT, new=INSERT for multi-DELETE After INSERT, new=INSERT for multi-DELETE Before DELETE, old=INSERT for multi-DELETE After DELETE, old=INSERT for multi-DELETE truncate t1; truncate t2; truncate t1_op_log; insert into v1 (id, operation) values (1, "INSERT for multi-UPDATE"); insert into t2 (id) values (1); update v1, t2 set v1.id=2, operation="multi-UPDATE" where v1.id=1; update v1, t2 set t2.id=3, operation="multi-UPDATE, SET for t2, but the trigger is fired" where v1.id=2; select * from t1; id operation 2 multi-UPDATE, SET for t2, but the trigger is fired select * from t2; id 3 select * from t1_op_log; operation Before INSERT, new=INSERT for multi-UPDATE After INSERT, new=INSERT for multi-UPDATE Before UPDATE, new=multi-UPDATE, old=INSERT for multi-UPDATE After UPDATE, new=multi-UPDATE, old=INSERT for multi-UPDATE Before UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi-UPDATE After UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi-UPDATE drop view v1; drop table t1, t2, t1_op_log; End of 5.0 tests mysql-test/t/trigger-trans.test +81 −1 Original line number Diff line number Diff line Loading @@ -49,4 +49,84 @@ insert into t1 values ('The Pie', 50, 1, 1); select * from t1; drop table t1; # End of 5.0 tests --echo --echo Bug#26141 mixing table types in trigger causes full --echo table lock on innodb table --echo --echo Ensure we do not open and lock tables for the triggers we do not --echo fire. --echo --disable_warnings drop table if exists t1, t2, t3; drop trigger if exists trg_bug26141_au; drop trigger if exists trg_bug26141_ai; --enable_warnings # Note, for InnoDB to allow concurrent UPDATE and INSERT the # table must have a unique key. create table t1 (c int primary key) engine=innodb; create table t2 (c int) engine=myisam; create table t3 (c int) engine=myisam; insert into t1 (c) values (1); delimiter |; create trigger trg_bug26141_ai after insert on t1 for each row begin insert into t2 (c) values (1); # We need the 'sync' lock to synchronously wait in connection 2 till # the moment when the trigger acquired all the locks. select release_lock("lock_bug26141_sync") into @a; # 1000 is time in seconds of lock wait timeout -- this is a way # to cause a manageable sleep up to 1000 seconds select get_lock("lock_bug26141_wait", 1000) into @a; end| create trigger trg_bug26141_au after update on t1 for each row begin insert into t3 (c) values (1); end| delimiter ;| # Establish an alternative connection. --connect (connection_aux,localhost,root,,test,,) --connect (connection_update,localhost,root,,test,,) connection connection_aux; # Lock the wait lock, it must not be locked, so specify zero timeout. select get_lock("lock_bug26141_wait", 0); # connection default; # # Run the trigger synchronously # select get_lock("lock_bug26141_sync", /* must not be priorly locked */ 0); # Will acquire the table level locks, perform the insert into t2, # release the sync lock and block on the wait lock. send insert into t1 (c) values (2); connection connection_update; # Wait for the trigger to acquire its locks and unlock the sync lock. select get_lock("lock_bug26141_sync", 1000); # # This must continue: after the fix for the bug, we do not # open tables for t2, and with c=4 innobase allows the update # to run concurrently with insert. update t1 set c=3 where c=1; select release_lock("lock_bug26141_sync"); connection connection_aux; select release_lock("lock_bug26141_wait"); connection default; reap; select * from t1; select * from t2; select * from t3; # Drops the trigger as well. drop table t1, t2, t3; disconnect connection_update; disconnect connection_aux; --echo End of 5.0 tests mysql-test/t/trigger.test +365 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes sql/item.h +0 −8 Original line number Diff line number Diff line Loading @@ -2309,14 +2309,6 @@ enum trg_action_time_type TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX }; /* Event on which trigger is invoked. */ enum trg_event_type { TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2, TRG_EVENT_MAX }; class Table_triggers_list; /* Loading Loading
mysql-test/r/trigger-trans.result +59 −0 Original line number Diff line number Diff line Loading @@ -82,3 +82,62 @@ ALICE 33 1 0 THE CROWN 43 1 0 THE PIE 53 1 1 drop table t1; Bug#26141 mixing table types in trigger causes full table lock on innodb table Ensure we do not open and lock tables for the triggers we do not fire. drop table if exists t1, t2, t3; drop trigger if exists trg_bug26141_au; drop trigger if exists trg_bug26141_ai; create table t1 (c int primary key) engine=innodb; create table t2 (c int) engine=myisam; create table t3 (c int) engine=myisam; insert into t1 (c) values (1); create trigger trg_bug26141_ai after insert on t1 for each row begin insert into t2 (c) values (1); # We need the 'sync' lock to synchronously wait in connection 2 till # the moment when the trigger acquired all the locks. select release_lock("lock_bug26141_sync") into @a; # 1000 is time in seconds of lock wait timeout -- this is a way # to cause a manageable sleep up to 1000 seconds select get_lock("lock_bug26141_wait", 1000) into @a; end| create trigger trg_bug26141_au after update on t1 for each row begin insert into t3 (c) values (1); end| select get_lock("lock_bug26141_wait", 0); get_lock("lock_bug26141_wait", 0) 1 select get_lock("lock_bug26141_sync", /* must not be priorly locked */ 0); get_lock("lock_bug26141_sync", /* must not be priorly locked */ 0) 1 insert into t1 (c) values (2); select get_lock("lock_bug26141_sync", 1000); get_lock("lock_bug26141_sync", 1000) 1 update t1 set c=3 where c=1; select release_lock("lock_bug26141_sync"); release_lock("lock_bug26141_sync") 1 select release_lock("lock_bug26141_wait"); release_lock("lock_bug26141_wait") 1 select * from t1; c 2 3 select * from t2; c 1 select * from t3; c 1 drop table t1, t2, t3; End of 5.0 tests
mysql-test/r/trigger.result +457 −0 Original line number Diff line number Diff line Loading @@ -1476,4 +1476,461 @@ DROP TRIGGER t1_test; DROP TABLE t1,t2; SET SESSION LOW_PRIORITY_UPDATES=DEFAULT; SET GLOBAL LOW_PRIORITY_UPDATES=DEFAULT; Bug#28502 Triggers that update another innodb table will block on X lock unnecessarily Ensure we do not open and lock tables for triggers we do not fire. drop table if exists t1, t2; drop trigger if exists trg_bug28502_au; create table t1 (id int, count int); create table t2 (id int); create trigger trg_bug28502_au before update on t2 for each row begin if (new.id is not null) then update t1 set count= count + 1 where id = old.id; end if; end| insert into t1 (id, count) values (1, 0); lock table t1 write; insert into t2 set id=1; unlock tables; update t2 set id=1 where id=1; select * from t1; id count 1 1 select * from t2; id 1 drop table t1, t2; Additionally, provide test coverage for triggers and all MySQL data changing commands. drop table if exists t1, t2, t1_op_log; drop view if exists v1; drop trigger if exists trg_bug28502_bi; drop trigger if exists trg_bug28502_ai; drop trigger if exists trg_bug28502_bu; drop trigger if exists trg_bug28502_au; drop trigger if exists trg_bug28502_bd; drop trigger if exists trg_bug28502_ad; create table t1 (id int primary key auto_increment, operation varchar(255)); create table t2 (id int primary key); create table t1_op_log(operation varchar(255)); create view v1 as select * from t1; create trigger trg_bug28502_bi before insert on t1 for each row insert into t1_op_log (operation) values (concat("Before INSERT, new=", new.operation)); create trigger trg_bug28502_ai after insert on t1 for each row insert into t1_op_log (operation) values (concat("After INSERT, new=", new.operation)); create trigger trg_bug28502_bu before update on t1 for each row insert into t1_op_log (operation) values (concat("Before UPDATE, new=", new.operation, ", old=", old.operation)); create trigger trg_bug28502_au after update on t1 for each row insert into t1_op_log (operation) values (concat("After UPDATE, new=", new.operation, ", old=", old.operation)); create trigger trg_bug28502_bd before delete on t1 for each row insert into t1_op_log (operation) values (concat("Before DELETE, old=", old.operation)); create trigger trg_bug28502_ad after delete on t1 for each row insert into t1_op_log (operation) values (concat("After DELETE, old=", old.operation)); insert into t1 (operation) values ("INSERT"); set @id=last_insert_id(); select * from t1; id operation 1 INSERT select * from t1_op_log; operation Before INSERT, new=INSERT After INSERT, new=INSERT truncate t1_op_log; update t1 set operation="UPDATE" where id=@id; select * from t1; id operation 1 UPDATE select * from t1_op_log; operation Before UPDATE, new=UPDATE, old=INSERT After UPDATE, new=UPDATE, old=INSERT truncate t1_op_log; delete from t1 where id=@id; select * from t1; id operation select * from t1_op_log; operation Before DELETE, old=UPDATE After DELETE, old=UPDATE truncate t1; truncate t1_op_log; insert into t1 (id, operation) values (NULL, "INSERT ON DUPLICATE KEY UPDATE, inserting a new key") on duplicate key update id=NULL, operation="Should never happen"; set @id=last_insert_id(); select * from t1; id operation 1 INSERT ON DUPLICATE KEY UPDATE, inserting a new key select * from t1_op_log; operation Before INSERT, new=INSERT ON DUPLICATE KEY UPDATE, inserting a new key After INSERT, new=INSERT ON DUPLICATE KEY UPDATE, inserting a new key truncate t1_op_log; insert into t1 (id, operation) values (@id, "INSERT ON DUPLICATE KEY UPDATE, the key value is the same") on duplicate key update id=NULL, operation="INSERT ON DUPLICATE KEY UPDATE, updating the duplicate"; select * from t1; id operation 0 INSERT ON DUPLICATE KEY UPDATE, updating the duplicate select * from t1_op_log; operation Before INSERT, new=INSERT ON DUPLICATE KEY UPDATE, the key value is the same Before UPDATE, new=INSERT ON DUPLICATE KEY UPDATE, updating the duplicate, old=INSERT ON DUPLICATE KEY UPDATE, inserting a new key After UPDATE, new=INSERT ON DUPLICATE KEY UPDATE, updating the duplicate, old=INSERT ON DUPLICATE KEY UPDATE, inserting a new key truncate t1; truncate t1_op_log; replace into t1 values (NULL, "REPLACE, inserting a new key"); set @id=last_insert_id(); select * from t1; id operation 1 REPLACE, inserting a new key select * from t1_op_log; operation Before INSERT, new=REPLACE, inserting a new key After INSERT, new=REPLACE, inserting a new key truncate t1_op_log; replace into t1 values (@id, "REPLACE, deleting the duplicate"); select * from t1; id operation 1 REPLACE, deleting the duplicate select * from t1_op_log; operation Before INSERT, new=REPLACE, deleting the duplicate Before DELETE, old=REPLACE, inserting a new key After DELETE, old=REPLACE, inserting a new key After INSERT, new=REPLACE, deleting the duplicate truncate t1; truncate t1_op_log; create table if not exists t1 select NULL, "CREATE TABLE ... SELECT, inserting a new key"; Warnings: Note 1050 Table 't1' already exists set @id=last_insert_id(); select * from t1; id operation 1 CREATE TABLE ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=CREATE TABLE ... SELECT, inserting a new key After INSERT, new=CREATE TABLE ... SELECT, inserting a new key truncate t1_op_log; create table if not exists t1 replace select @id, "CREATE TABLE ... REPLACE SELECT, deleting a duplicate key"; Warnings: Note 1050 Table 't1' already exists select * from t1; id operation 1 CREATE TABLE ... REPLACE SELECT, deleting a duplicate key select * from t1_op_log; operation Before INSERT, new=CREATE TABLE ... REPLACE SELECT, deleting a duplicate key Before DELETE, old=CREATE TABLE ... SELECT, inserting a new key After DELETE, old=CREATE TABLE ... SELECT, inserting a new key After INSERT, new=CREATE TABLE ... REPLACE SELECT, deleting a duplicate key truncate t1; truncate t1_op_log; insert into t1 (id, operation) select NULL, "INSERT ... SELECT, inserting a new key"; set @id=last_insert_id(); select * from t1; id operation 1 INSERT ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=INSERT ... SELECT, inserting a new key After INSERT, new=INSERT ... SELECT, inserting a new key truncate t1_op_log; insert into t1 (id, operation) select @id, "INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate" on duplicate key update id=NULL, operation="INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate"; select * from t1; id operation 0 INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate select * from t1_op_log; operation Before INSERT, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate Before UPDATE, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate, old=INSERT ... SELECT, inserting a new key After UPDATE, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate, old=INSERT ... SELECT, inserting a new key truncate t1; truncate t1_op_log; replace into t1 (id, operation) select NULL, "REPLACE ... SELECT, inserting a new key"; set @id=last_insert_id(); select * from t1; id operation 1 REPLACE ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=REPLACE ... SELECT, inserting a new key After INSERT, new=REPLACE ... SELECT, inserting a new key truncate t1_op_log; replace into t1 (id, operation) select @id, "REPLACE ... SELECT, deleting a duplicate"; select * from t1; id operation 1 REPLACE ... SELECT, deleting a duplicate select * from t1_op_log; operation Before INSERT, new=REPLACE ... SELECT, deleting a duplicate Before DELETE, old=REPLACE ... SELECT, inserting a new key After DELETE, old=REPLACE ... SELECT, inserting a new key After INSERT, new=REPLACE ... SELECT, deleting a duplicate truncate t1; truncate t1_op_log; insert into t1 (id, operation) values (1, "INSERT for multi-DELETE"); insert into t2 (id) values (1); delete t1.*, t2.* from t1, t2 where t1.id=1; select * from t1; id operation select * from t2; id select * from t1_op_log; operation Before INSERT, new=INSERT for multi-DELETE After INSERT, new=INSERT for multi-DELETE Before DELETE, old=INSERT for multi-DELETE After DELETE, old=INSERT for multi-DELETE truncate t1; truncate t2; truncate t1_op_log; insert into t1 (id, operation) values (1, "INSERT for multi-UPDATE"); insert into t2 (id) values (1); update t1, t2 set t1.id=2, operation="multi-UPDATE" where t1.id=1; update t1, t2 set t2.id=3, operation="multi-UPDATE, SET for t2, but the trigger is fired" where t1.id=2; select * from t1; id operation 2 multi-UPDATE, SET for t2, but the trigger is fired select * from t2; id 3 select * from t1_op_log; operation Before INSERT, new=INSERT for multi-UPDATE After INSERT, new=INSERT for multi-UPDATE Before UPDATE, new=multi-UPDATE, old=INSERT for multi-UPDATE After UPDATE, new=multi-UPDATE, old=INSERT for multi-UPDATE Before UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi-UPDATE After UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi-UPDATE truncate table t1; truncate table t2; truncate table t1_op_log; Now do the same but use a view instead of the base table. insert into v1 (operation) values ("INSERT"); set @id=last_insert_id(); select * from t1; id operation 1 INSERT select * from t1_op_log; operation Before INSERT, new=INSERT After INSERT, new=INSERT truncate t1_op_log; update v1 set operation="UPDATE" where id=@id; select * from t1; id operation 1 UPDATE select * from t1_op_log; operation Before UPDATE, new=UPDATE, old=INSERT After UPDATE, new=UPDATE, old=INSERT truncate t1_op_log; delete from v1 where id=@id; select * from t1; id operation select * from t1_op_log; operation Before DELETE, old=UPDATE After DELETE, old=UPDATE truncate t1; truncate t1_op_log; insert into v1 (id, operation) values (NULL, "INSERT ON DUPLICATE KEY UPDATE, inserting a new key") on duplicate key update id=NULL, operation="Should never happen"; set @id=last_insert_id(); select * from t1; id operation 1 INSERT ON DUPLICATE KEY UPDATE, inserting a new key select * from t1_op_log; operation Before INSERT, new=INSERT ON DUPLICATE KEY UPDATE, inserting a new key After INSERT, new=INSERT ON DUPLICATE KEY UPDATE, inserting a new key truncate t1_op_log; insert into v1 (id, operation) values (@id, "INSERT ON DUPLICATE KEY UPDATE, the key value is the same") on duplicate key update id=NULL, operation="INSERT ON DUPLICATE KEY UPDATE, updating the duplicate"; select * from t1; id operation 0 INSERT ON DUPLICATE KEY UPDATE, updating the duplicate select * from t1_op_log; operation Before INSERT, new=INSERT ON DUPLICATE KEY UPDATE, the key value is the same Before UPDATE, new=INSERT ON DUPLICATE KEY UPDATE, updating the duplicate, old=INSERT ON DUPLICATE KEY UPDATE, inserting a new key After UPDATE, new=INSERT ON DUPLICATE KEY UPDATE, updating the duplicate, old=INSERT ON DUPLICATE KEY UPDATE, inserting a new key truncate t1; truncate t1_op_log; replace into v1 values (NULL, "REPLACE, inserting a new key"); set @id=last_insert_id(); select * from t1; id operation 1 REPLACE, inserting a new key select * from t1_op_log; operation Before INSERT, new=REPLACE, inserting a new key After INSERT, new=REPLACE, inserting a new key truncate t1_op_log; replace into v1 values (@id, "REPLACE, deleting the duplicate"); select * from t1; id operation 1 REPLACE, deleting the duplicate select * from t1_op_log; operation Before INSERT, new=REPLACE, deleting the duplicate Before DELETE, old=REPLACE, inserting a new key After DELETE, old=REPLACE, inserting a new key After INSERT, new=REPLACE, deleting the duplicate truncate t1; truncate t1_op_log; create table if not exists v1 select NULL, "CREATE TABLE ... SELECT, inserting a new key"; Warnings: Note 1050 Table 'v1' already exists set @id=last_insert_id(); select * from t1; id operation 1 CREATE TABLE ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=CREATE TABLE ... SELECT, inserting a new key After INSERT, new=CREATE TABLE ... SELECT, inserting a new key truncate t1_op_log; create table if not exists v1 replace select @id, "CREATE TABLE ... REPLACE SELECT, deleting a duplicate key"; Warnings: Note 1050 Table 'v1' already exists select * from t1; id operation 1 CREATE TABLE ... REPLACE SELECT, deleting a duplicate key select * from t1_op_log; operation Before INSERT, new=CREATE TABLE ... REPLACE SELECT, deleting a duplicate key Before DELETE, old=CREATE TABLE ... SELECT, inserting a new key After DELETE, old=CREATE TABLE ... SELECT, inserting a new key After INSERT, new=CREATE TABLE ... REPLACE SELECT, deleting a duplicate key truncate t1; truncate t1_op_log; insert into v1 (id, operation) select NULL, "INSERT ... SELECT, inserting a new key"; set @id=last_insert_id(); select * from t1; id operation 1 INSERT ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=INSERT ... SELECT, inserting a new key After INSERT, new=INSERT ... SELECT, inserting a new key truncate t1_op_log; insert into v1 (id, operation) select @id, "INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate" on duplicate key update id=NULL, operation="INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate"; select * from t1; id operation 0 INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate select * from t1_op_log; operation Before INSERT, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate Before UPDATE, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate, old=INSERT ... SELECT, inserting a new key After UPDATE, new=INSERT ... SELECT ... ON DUPLICATE KEY UPDATE, updating a duplicate, old=INSERT ... SELECT, inserting a new key truncate t1; truncate t1_op_log; replace into v1 (id, operation) select NULL, "REPLACE ... SELECT, inserting a new key"; set @id=last_insert_id(); select * from t1; id operation 1 REPLACE ... SELECT, inserting a new key select * from t1_op_log; operation Before INSERT, new=REPLACE ... SELECT, inserting a new key After INSERT, new=REPLACE ... SELECT, inserting a new key truncate t1_op_log; replace into v1 (id, operation) select @id, "REPLACE ... SELECT, deleting a duplicate"; select * from t1; id operation 1 REPLACE ... SELECT, deleting a duplicate select * from t1_op_log; operation Before INSERT, new=REPLACE ... SELECT, deleting a duplicate Before DELETE, old=REPLACE ... SELECT, inserting a new key After DELETE, old=REPLACE ... SELECT, inserting a new key After INSERT, new=REPLACE ... SELECT, deleting a duplicate truncate t1; truncate t1_op_log; insert into v1 (id, operation) values (1, "INSERT for multi-DELETE"); insert into t2 (id) values (1); delete v1.*, t2.* from v1, t2 where v1.id=1; select * from t1; id operation select * from t2; id select * from t1_op_log; operation Before INSERT, new=INSERT for multi-DELETE After INSERT, new=INSERT for multi-DELETE Before DELETE, old=INSERT for multi-DELETE After DELETE, old=INSERT for multi-DELETE truncate t1; truncate t2; truncate t1_op_log; insert into v1 (id, operation) values (1, "INSERT for multi-UPDATE"); insert into t2 (id) values (1); update v1, t2 set v1.id=2, operation="multi-UPDATE" where v1.id=1; update v1, t2 set t2.id=3, operation="multi-UPDATE, SET for t2, but the trigger is fired" where v1.id=2; select * from t1; id operation 2 multi-UPDATE, SET for t2, but the trigger is fired select * from t2; id 3 select * from t1_op_log; operation Before INSERT, new=INSERT for multi-UPDATE After INSERT, new=INSERT for multi-UPDATE Before UPDATE, new=multi-UPDATE, old=INSERT for multi-UPDATE After UPDATE, new=multi-UPDATE, old=INSERT for multi-UPDATE Before UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi-UPDATE After UPDATE, new=multi-UPDATE, SET for t2, but the trigger is fired, old=multi-UPDATE drop view v1; drop table t1, t2, t1_op_log; End of 5.0 tests
mysql-test/t/trigger-trans.test +81 −1 Original line number Diff line number Diff line Loading @@ -49,4 +49,84 @@ insert into t1 values ('The Pie', 50, 1, 1); select * from t1; drop table t1; # End of 5.0 tests --echo --echo Bug#26141 mixing table types in trigger causes full --echo table lock on innodb table --echo --echo Ensure we do not open and lock tables for the triggers we do not --echo fire. --echo --disable_warnings drop table if exists t1, t2, t3; drop trigger if exists trg_bug26141_au; drop trigger if exists trg_bug26141_ai; --enable_warnings # Note, for InnoDB to allow concurrent UPDATE and INSERT the # table must have a unique key. create table t1 (c int primary key) engine=innodb; create table t2 (c int) engine=myisam; create table t3 (c int) engine=myisam; insert into t1 (c) values (1); delimiter |; create trigger trg_bug26141_ai after insert on t1 for each row begin insert into t2 (c) values (1); # We need the 'sync' lock to synchronously wait in connection 2 till # the moment when the trigger acquired all the locks. select release_lock("lock_bug26141_sync") into @a; # 1000 is time in seconds of lock wait timeout -- this is a way # to cause a manageable sleep up to 1000 seconds select get_lock("lock_bug26141_wait", 1000) into @a; end| create trigger trg_bug26141_au after update on t1 for each row begin insert into t3 (c) values (1); end| delimiter ;| # Establish an alternative connection. --connect (connection_aux,localhost,root,,test,,) --connect (connection_update,localhost,root,,test,,) connection connection_aux; # Lock the wait lock, it must not be locked, so specify zero timeout. select get_lock("lock_bug26141_wait", 0); # connection default; # # Run the trigger synchronously # select get_lock("lock_bug26141_sync", /* must not be priorly locked */ 0); # Will acquire the table level locks, perform the insert into t2, # release the sync lock and block on the wait lock. send insert into t1 (c) values (2); connection connection_update; # Wait for the trigger to acquire its locks and unlock the sync lock. select get_lock("lock_bug26141_sync", 1000); # # This must continue: after the fix for the bug, we do not # open tables for t2, and with c=4 innobase allows the update # to run concurrently with insert. update t1 set c=3 where c=1; select release_lock("lock_bug26141_sync"); connection connection_aux; select release_lock("lock_bug26141_wait"); connection default; reap; select * from t1; select * from t2; select * from t3; # Drops the trigger as well. drop table t1, t2, t3; disconnect connection_update; disconnect connection_aux; --echo End of 5.0 tests
mysql-test/t/trigger.test +365 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes
sql/item.h +0 −8 Original line number Diff line number Diff line Loading @@ -2309,14 +2309,6 @@ enum trg_action_time_type TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX }; /* Event on which trigger is invoked. */ enum trg_event_type { TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2, TRG_EVENT_MAX }; class Table_triggers_list; /* Loading