[Commits] Rev 3977: RBR triggers merged with 5.5.34 in file:///home/bell/maria/bzr/work-maria-5.5.34/

sanja at askmonty.org sanja at askmonty.org
Tue Dec 3 14:18:44 EET 2013


At file:///home/bell/maria/bzr/work-maria-5.5.34/

------------------------------------------------------------
revno: 3977 [merge]
revision-id: sanja at askmonty.org-20131203121820-m3uy9i4klm540m8j
parent: svoj at mariadb.org-20131118114801-if1r6nevnou5axbi
parent: sanja at askmonty.org-20131202135028-h476cfe06kvhor53
committer: sanja at askmonty.org
branch nick: work-maria-5.5.34
timestamp: Tue 2013-12-03 14:18:20 +0200
message:
  RBR triggers merged with 5.5.34
added:
  mysql-test/r/rpl_row_triggers.result rpl_row_triggers.res-20131121204240-bvrr2wy2en8i4x4y-1
  mysql-test/r/rpl_row_triggers_sbr.result rpl_row_triggers_sbr-20131124215254-6vlgdumlgg83q9ip-1
  mysql-test/suite/sys_vars/r/slave_run_triggers_for_rbr_basic.result slave_run_triggers_f-20131122113710-r0o07f2athzj4he0-1
  mysql-test/suite/sys_vars/t/slave_run_triggers_for_rbr_basic.test slave_run_triggers_f-20131122113719-g79pu6bwynsucryd-1
  mysql-test/t/rpl_row_triggers.test rpl_row_triggers.tes-20131121204206-epb4c2lrju2giwmc-1
  mysql-test/t/rpl_row_triggers_sbr.test rpl_row_triggers_sbr-20131124215125-xq8k91cizcw7gtjr-1
modified:
  mysql-test/r/mysqld--help.result mysqldhelp.result-20091210121810-wnsq93ex4gn8t8su-1
  sql/log_event.cc               sp1f-log_event.cc-19700101030959-msmqlflsngxosswid2hpzxly5vfqdddc
  sql/log_event.h                sp1f-log_event.h-19700101030959-clq6ett55tcqbpys2i4cpfrdccq7j4om
  sql/mysqld.cc                  sp1f-mysqld.cc-19700101030959-zpswdvekpvixxzxf7gdtofzel7nywtfj
  sql/mysqld.h                   mysqld.h-20100331135644-cgcb6oowzqyx7fi3-11
  sql/rpl_utility.h              sp1f-rpl_utility.h-20060503130029-u44nzzcbdenh2gegnnyzro26kbk5quw7
  sql/sql_class.h                sp1f-sql_class.h-19700101030959-jnqnbrjyqsvgncsibnumsmg3lyi7pa5s
  sql/sys_vars.cc                set_var_new.cc-20090803110928-jyk836zs40b2z8e3-1
-------------- next part --------------
=== modified file 'mysql-test/r/mysqld--help.result'
--- a/mysql-test/r/mysqld--help.result	2012-10-18 21:33:06 +0000
+++ b/mysql-test/r/mysqld--help.result	2013-11-22 11:39:05 +0000
@@ -747,6 +747,14 @@ The following options may be given as th
  --slave-net-timeout=# 
  Number of seconds to wait for more data from a
  master/slave connection before aborting the read
+ --slave-run-triggers-for-rbr=name 
+ Modes for how triggers in row-base replication on slave
+ side will be executed. Legal values are NO (default), YES
+ and LOGGING. NO means that trigger for RBR will not be
+ running on slave YES and LOGGING means that triggers will
+ be running on slave (if there was not triggers running on
+ the naster), LOGGING also mens that flag about executed
+ triggers will be written to binlog.
  --slave-skip-errors=name 
  Tells the slave thread to continue replication when a
  query event returns an error from the provided list
@@ -1066,6 +1074,7 @@ slave-compressed-protocol FALSE
 slave-exec-mode STRICT
 slave-max-allowed-packet 1073741824
 slave-net-timeout 3600
+slave-run-triggers-for-rbr NO
 slave-skip-errors (No default value)
 slave-sql-verify-checksum TRUE
 slave-transaction-retries 10

=== added file 'mysql-test/r/rpl_row_triggers.result'
--- a/mysql-test/r/rpl_row_triggers.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/rpl_row_triggers.result	2013-11-27 08:08:32 +0000
@@ -0,0 +1,221 @@
+include/master-slave.inc
+[connection master]
+# Test of row replication with triggers on the slave side
+CREATE TABLE t1 (C1 CHAR(1) primary key, C2 CHAR(1)) engine=innodb;
+SELECT * FROM t1;
+C1	C2
+SET @old_slave_exec_mode= @@global.slave_exec_mode;
+SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
+SET @@global.slave_exec_mode= IDEMPOTENT;
+SET @@global.slave_run_triggers_for_rbr= YES;
+SELECT * FROM t1;
+C1	C2
+create table t2 (id char(2) primary key, cnt int, o char(1), n char(1));
+insert into t2 values
+('u0', 0, ' ', ' '),('u1', 0, ' ', ' '),
+('d0', 0, ' ', ' '),('d1', 0, ' ', ' '),
+('i0', 0, ' ', ' '),('i1', 0, ' ', ' ');
+create trigger t1_cnt_b before update on t1 for each row
+update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u0';
+create trigger t1_cnt_db before delete on t1 for each row
+update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd0';
+create trigger t1_cnt_ib before insert on t1 for each row
+update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i0';
+create trigger t1_cnt_a after update on t1 for each row
+update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u1';
+create trigger t1_cnt_da after delete on t1 for each row
+update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd1';
+create trigger t1_cnt_ia after insert on t1 for each row
+update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i1';
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	0		
+i1	0		
+u0	0		
+u1	0		
+# INSERT triggers test
+insert into t1 values ('a','b');
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	1		a
+i1	1		a
+u0	0		
+u1	0		
+# UPDATE triggers test
+update t1 set C1= 'd';
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	1		a
+i1	1		a
+u0	1	a	d
+u1	1	a	d
+# DELETE triggers test
+delete from t1 where C1='d';
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	1	d	
+d1	1	d	
+i0	1		a
+i1	1		a
+u0	1	a	d
+u1	1	a	d
+# INSERT triggers which cause also UPDATE test (insert duplicate row)
+insert into t1 values ('0','1');
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	1	d	
+d1	1	d	
+i0	2		0
+i1	2		0
+u0	1	a	d
+u1	1	a	d
+insert into t1 values ('0','1');
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	1	d	
+d1	1	d	
+i0	3		0
+i1	3		0
+u0	2	0	0
+u1	2	0	0
+# INSERT triggers which cause also DELETE test
+# (insert duplicate row in table referenced by foreign key)
+insert into t1 values ('1','1');
+CREATE TABLE t3 (C1 CHAR(1) primary key, FOREIGN KEY (C1) REFERENCES t1(C1) ) engine=innodb;
+insert into t1 values ('1','1');
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	2	1	
+d1	2	1	
+i0	5		1
+i1	5		1
+u0	2	0	0
+u1	2	0	0
+drop table t3,t1;
+SET @@global.slave_exec_mode= @old_slave_exec_mode;
+SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
+drop table t2;
+CREATE TABLE t1 (i INT) ENGINE=InnoDB;
+CREATE TABLE t2 (i INT) ENGINE=InnoDB;
+SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
+SET GLOBAL slave_run_triggers_for_rbr=YES;
+CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW
+INSERT INTO t2 VALUES (new.i);
+BEGIN;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+COMMIT;
+select * from t2;
+i
+1
+2
+SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
+drop tables t2,t1;
+# Triggers on slave do not work if master has some
+CREATE TABLE t1 (C1 CHAR(1) primary key, C2 CHAR(1)) engine=innodb;
+SELECT * FROM t1;
+C1	C2
+create trigger t1_dummy before delete on t1 for each row
+set @dummy= 1;
+SET @old_slave_exec_mode= @@global.slave_exec_mode;
+SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
+SET @@global.slave_exec_mode= IDEMPOTENT;
+SET @@global.slave_run_triggers_for_rbr= YES;
+SELECT * FROM t1;
+C1	C2
+create table t2 (id char(2) primary key, cnt int, o char(1), n char(1));
+insert into t2 values
+('u0', 0, ' ', ' '),('u1', 0, ' ', ' '),
+('d0', 0, ' ', ' '),('d1', 0, ' ', ' '),
+('i0', 0, ' ', ' '),('i1', 0, ' ', ' ');
+create trigger t1_cnt_b before update on t1 for each row
+update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u0';
+create trigger t1_cnt_ib before insert on t1 for each row
+update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i0';
+create trigger t1_cnt_a after update on t1 for each row
+update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u1';
+create trigger t1_cnt_da after delete on t1 for each row
+update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd1';
+create trigger t1_cnt_ia after insert on t1 for each row
+update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i1';
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	0		
+i1	0		
+u0	0		
+u1	0		
+# INSERT triggers test
+insert into t1 values ('a','b');
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	0		
+i1	0		
+u0	0		
+u1	0		
+# UPDATE triggers test
+update t1 set C1= 'd';
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	0		
+i1	0		
+u0	0		
+u1	0		
+# DELETE triggers test
+delete from t1 where C1='d';
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	0		
+i1	0		
+u0	0		
+u1	0		
+# INSERT triggers which cause also UPDATE test (insert duplicate row)
+insert into t1 values ('0','1');
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	1		0
+i1	1		0
+u0	0		
+u1	0		
+insert into t1 values ('0','1');
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	1		0
+i1	1		0
+u0	0		
+u1	0		
+# INSERT triggers which cause also DELETE test
+# (insert duplicate row in table referenced by foreign key)
+insert into t1 values ('1','1');
+CREATE TABLE t3 (C1 CHAR(1) primary key, FOREIGN KEY (C1) REFERENCES t1(C1) ) engine=innodb;
+insert into t1 values ('1','1');
+SELECT * FROM t2 order by id;
+id	cnt	o	n
+d0	0		
+d1	0		
+i0	2		1
+i1	2		1
+u0	0		
+u1	0		
+drop table t3,t1;
+SET @@global.slave_exec_mode= @old_slave_exec_mode;
+SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
+drop table t2;
+include/rpl_end.inc

=== added file 'mysql-test/r/rpl_row_triggers_sbr.result'
--- a/mysql-test/r/rpl_row_triggers_sbr.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/rpl_row_triggers_sbr.result	2013-11-24 21:53:25 +0000
@@ -0,0 +1,14 @@
+include/master-slave.inc
+[connection master]
+set binlog_format = row;
+create table t1 (i int);
+create table t2 (i int);
+SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
+set global slave_run_triggers_for_rbr=YES;
+create trigger tr_before before insert on t1 for each row
+insert into t2 values (1);
+insert into t1 values (1);
+include/wait_for_slave_sql_error_and_skip.inc [errno=1666]
+drop tables t1,t2;
+SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
+include/rpl_end.inc

=== added file 'mysql-test/suite/sys_vars/r/slave_run_triggers_for_rbr_basic.result'
--- a/mysql-test/suite/sys_vars/r/slave_run_triggers_for_rbr_basic.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/sys_vars/r/slave_run_triggers_for_rbr_basic.result	2013-11-22 11:39:05 +0000
@@ -0,0 +1,31 @@
+set @saved_slave_run_triggers_for_rbr = @@global.slave_run_triggers_for_rbr;
+SELECT @@global.slave_run_triggers_for_rbr;
+@@global.slave_run_triggers_for_rbr
+NO
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR=default;
+SELECT @@global.slave_run_triggers_for_rbr;
+@@global.slave_run_triggers_for_rbr
+NO
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='YES';
+SELECT @@global.slave_run_triggers_for_rbr;
+@@global.slave_run_triggers_for_rbr
+YES
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='NO';
+SELECT @@global.slave_run_triggers_for_rbr;
+@@global.slave_run_triggers_for_rbr
+NO
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='LOGGING';
+SELECT @@global.slave_run_triggers_for_rbr;
+@@global.slave_run_triggers_for_rbr
+LOGGING
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='0';
+ERROR 42000: Variable 'slave_run_triggers_for_rbr' can't be set to the value of '0'
+SELECT @@global.slave_run_triggers_for_rbr;
+@@global.slave_run_triggers_for_rbr
+LOGGING
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='TRUE';
+ERROR 42000: Variable 'slave_run_triggers_for_rbr' can't be set to the value of 'TRUE'
+SELECT @@global.slave_run_triggers_for_rbr;
+@@global.slave_run_triggers_for_rbr
+LOGGING
+set global slave_run_triggers_for_rbr = @saved_slave_run_triggers_for_rbr;

=== added file 'mysql-test/suite/sys_vars/t/slave_run_triggers_for_rbr_basic.test'
--- a/mysql-test/suite/sys_vars/t/slave_run_triggers_for_rbr_basic.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/sys_vars/t/slave_run_triggers_for_rbr_basic.test	2013-11-22 11:39:05 +0000
@@ -0,0 +1,36 @@
+--source include/not_embedded.inc
+--source include/load_sysvars.inc
+
+
+######################################################################## 
+#     Saving initial value of slave_exec_mode in a temporary variable  #
+######################################################################## 
+
+set @saved_slave_run_triggers_for_rbr = @@global.slave_run_triggers_for_rbr;
+
+SELECT @@global.slave_run_triggers_for_rbr;
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR=default;
+SELECT @@global.slave_run_triggers_for_rbr;
+
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='YES';
+SELECT @@global.slave_run_triggers_for_rbr;
+
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='NO';
+SELECT @@global.slave_run_triggers_for_rbr;
+
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='LOGGING';
+SELECT @@global.slave_run_triggers_for_rbr;
+
+# checking that setting variable to a non existing value raises error
+--error ER_WRONG_VALUE_FOR_VAR
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='0';
+SELECT @@global.slave_run_triggers_for_rbr;
+--error ER_WRONG_VALUE_FOR_VAR
+SET GLOBAL SLAVE_RUN_TRIGGERS_FOR_RBR='TRUE';
+SELECT @@global.slave_run_triggers_for_rbr;
+
+set global slave_run_triggers_for_rbr = @saved_slave_run_triggers_for_rbr;
+
+######################################################################## 
+#                    END OF slave_exec_mode TESTS                      #
+######################################################################## 

=== added file 'mysql-test/t/rpl_row_triggers.test'
--- a/mysql-test/t/rpl_row_triggers.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/rpl_row_triggers.test	2013-11-27 08:08:32 +0000
@@ -0,0 +1,239 @@
+-- source include/have_binlog_format_row.inc
+-- source include/master-slave.inc
+-- source include/have_innodb.inc
+
+-- echo # Test of row replication with triggers on the slave side
+
+connection master;
+CREATE TABLE t1 (C1 CHAR(1) primary key, C2 CHAR(1)) engine=innodb;
+SELECT * FROM t1;
+
+sync_slave_with_master;
+
+connection slave;
+SET @old_slave_exec_mode= @@global.slave_exec_mode;
+SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
+SET @@global.slave_exec_mode= IDEMPOTENT;
+SET @@global.slave_run_triggers_for_rbr= YES;
+SELECT * FROM t1;
+create table t2 (id char(2) primary key, cnt int, o char(1), n char(1));
+insert into t2 values
+      ('u0', 0, ' ', ' '),('u1', 0, ' ', ' '),
+      ('d0', 0, ' ', ' '),('d1', 0, ' ', ' '),
+      ('i0', 0, ' ', ' '),('i1', 0, ' ', ' ');
+create trigger t1_cnt_b before update on t1 for each row
+  update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u0';
+create trigger t1_cnt_db before delete on t1 for each row
+  update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd0';
+create trigger t1_cnt_ib before insert on t1 for each row
+  update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i0';
+create trigger t1_cnt_a after update on t1 for each row
+  update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u1';
+create trigger t1_cnt_da after delete on t1 for each row
+  update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd1';
+create trigger t1_cnt_ia after insert on t1 for each row
+  update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i1';
+SELECT * FROM t2 order by id;
+
+connection master;
+--echo # INSERT triggers test
+insert into t1 values ('a','b');
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+connection master;
+
+--echo # UPDATE triggers test
+update t1 set C1= 'd';
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+connection master;
+--echo # DELETE triggers test
+delete from t1 where C1='d';
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+--echo # INSERT triggers which cause also UPDATE test (insert duplicate row)
+insert into t1 values ('0','1');
+
+SELECT * FROM t2 order by id;
+
+connection master;
+
+insert into t1 values ('0','1');
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+
+--echo # INSERT triggers which cause also DELETE test
+--echo # (insert duplicate row in table referenced by foreign key)
+insert into t1 values ('1','1');
+
+connection master;
+
+CREATE TABLE t3 (C1 CHAR(1) primary key, FOREIGN KEY (C1) REFERENCES t1(C1) ) engine=innodb;
+
+insert into t1 values ('1','1');
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+connection master;
+
+drop table t3,t1;
+
+sync_slave_with_master;
+
+connection slave;
+SET @@global.slave_exec_mode= @old_slave_exec_mode;
+SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
+drop table t2;
+
+--connection master
+
+CREATE TABLE t1 (i INT) ENGINE=InnoDB;
+CREATE TABLE t2 (i INT) ENGINE=InnoDB;
+
+--sync_slave_with_master
+
+SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
+SET GLOBAL slave_run_triggers_for_rbr=YES;
+
+CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW
+  INSERT INTO t2 VALUES (new.i);
+
+--connection master
+
+BEGIN;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+COMMIT;
+
+--sync_slave_with_master
+select * from t2;
+SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
+
+--connection master
+drop tables t2,t1;
+
+--sync_slave_with_master
+
+-- echo # Triggers on slave do not work if master has some
+
+connection master;
+CREATE TABLE t1 (C1 CHAR(1) primary key, C2 CHAR(1)) engine=innodb;
+SELECT * FROM t1;
+
+create trigger t1_dummy before delete on t1 for each row
+  set @dummy= 1;
+
+sync_slave_with_master;
+
+connection slave;
+SET @old_slave_exec_mode= @@global.slave_exec_mode;
+SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
+SET @@global.slave_exec_mode= IDEMPOTENT;
+SET @@global.slave_run_triggers_for_rbr= YES;
+SELECT * FROM t1;
+create table t2 (id char(2) primary key, cnt int, o char(1), n char(1));
+insert into t2 values
+      ('u0', 0, ' ', ' '),('u1', 0, ' ', ' '),
+      ('d0', 0, ' ', ' '),('d1', 0, ' ', ' '),
+      ('i0', 0, ' ', ' '),('i1', 0, ' ', ' ');
+create trigger t1_cnt_b before update on t1 for each row
+  update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u0';
+create trigger t1_cnt_ib before insert on t1 for each row
+  update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i0';
+create trigger t1_cnt_a after update on t1 for each row
+  update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u1';
+create trigger t1_cnt_da after delete on t1 for each row
+  update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd1';
+create trigger t1_cnt_ia after insert on t1 for each row
+  update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i1';
+SELECT * FROM t2 order by id;
+
+connection master;
+--echo # INSERT triggers test
+insert into t1 values ('a','b');
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+connection master;
+
+--echo # UPDATE triggers test
+update t1 set C1= 'd';
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+connection master;
+--echo # DELETE triggers test
+delete from t1 where C1='d';
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+--echo # INSERT triggers which cause also UPDATE test (insert duplicate row)
+insert into t1 values ('0','1');
+
+SELECT * FROM t2 order by id;
+
+connection master;
+
+insert into t1 values ('0','1');
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+
+--echo # INSERT triggers which cause also DELETE test
+--echo # (insert duplicate row in table referenced by foreign key)
+insert into t1 values ('1','1');
+
+connection master;
+
+CREATE TABLE t3 (C1 CHAR(1) primary key, FOREIGN KEY (C1) REFERENCES t1(C1) ) engine=innodb;
+
+insert into t1 values ('1','1');
+
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t2 order by id;
+
+connection master;
+
+drop table t3,t1;
+
+sync_slave_with_master;
+
+connection slave;
+SET @@global.slave_exec_mode= @old_slave_exec_mode;
+SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
+drop table t2;
+
+--source include/rpl_end.inc

=== added file 'mysql-test/t/rpl_row_triggers_sbr.test'
--- a/mysql-test/t/rpl_row_triggers_sbr.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/rpl_row_triggers_sbr.test	2013-11-24 21:53:25 +0000
@@ -0,0 +1,42 @@
+--source include/master-slave.inc
+--source include/have_binlog_format_statement.inc
+
+--disable_query_log
+CALL mtr.add_suppression("Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT");
+--enable_query_log
+
+set binlog_format = row;
+
+create table t1 (i int);
+create table t2 (i int);
+
+--sync_slave_with_master
+--disable_query_log
+CALL mtr.add_suppression("impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT");
+--enable_query_log
+
+SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
+set global slave_run_triggers_for_rbr=YES;
+
+create trigger tr_before before insert on t1 for each row
+  insert into t2 values (1);
+
+--connection master
+
+insert into t1 values (1);
+
+--connection slave
+
+--let $slave_sql_errno= 1666
+--source include/wait_for_slave_sql_error_and_skip.inc
+
+--connection master
+
+drop tables t1,t2;
+
+--sync_slave_with_master
+SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
+
+--connection master
+
+--source include/rpl_end.inc

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2013-11-19 12:16:25 +0000
+++ b/sql/log_event.cc	2013-12-03 12:18:20 +0000
@@ -8025,7 +8025,8 @@ Rows_log_event::Rows_log_event(THD *thd_
     m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0) 
 #ifdef HAVE_REPLICATION
     , m_curr_row(NULL), m_curr_row_end(NULL),
-    m_key(NULL), m_key_info(NULL), m_key_nr(0)
+    m_key(NULL), m_key_info(NULL), m_key_nr(0),
+    master_had_triggers(0)
 #endif
 {
   /*
@@ -8074,7 +8075,8 @@ Rows_log_event::Rows_log_event(const cha
     m_table_id(0), m_rows_buf(0), m_rows_cur(0), m_rows_end(0)
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
     , m_curr_row(NULL), m_curr_row_end(NULL),
-    m_key(NULL), m_key_info(NULL), m_key_nr(0)
+    m_key(NULL), m_key_info(NULL), m_key_nr(0),
+    master_had_triggers(0)
 #endif
 {
   DBUG_ENTER("Rows_log_event::Rows_log_event(const char*,...)");
@@ -8266,7 +8268,16 @@ int Rows_log_event::do_add_row_data(ucha
 }
 #endif
 
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+
+static void restore_empty_query_table_list(LEX *lex)
+{
+  if (lex->first_not_own_table())
+      (*lex->first_not_own_table()->prev_global)= NULL;
+  lex->query_tables= NULL;
+  lex->query_tables_last= &lex->query_tables;
+}
+
 int Rows_log_event::do_apply_event(Relay_log_info const *rli)
 {
   DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
@@ -8347,6 +8358,22 @@ int Rows_log_event::do_apply_event(Relay
     /* A small test to verify that objects have consistent types */
     DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
 
+    if (slave_run_triggers_for_rbr)
+    {
+      LEX *lex= thd->lex;
+      uint8 new_trg_event_map= get_trg_event_map();
+
+      DBUG_ASSERT(lex->query_tables == NULL);
+      if ((lex->query_tables= rli->tables_to_lock))
+        rli->tables_to_lock->prev_global= &lex->query_tables;
+
+      for (TABLE_LIST *tables= rli->tables_to_lock; tables;
+           tables= tables->next_global)
+      {
+        tables->trg_event_map= new_trg_event_map;
+        lex->query_tables_last= &tables->next_global;
+      }
+    }
     if (open_and_lock_tables(thd, rli->tables_to_lock, FALSE, 0))
     {
       uint actual_error= thd->stmt_da->sql_errno();
@@ -8364,6 +8391,9 @@ int Rows_log_event::do_apply_event(Relay
                      "unexpected success or fatal error"));
         thd->is_slave_error= 1;
       }
+      /* remove trigger's tables */
+      if (slave_run_triggers_for_rbr)
+        restore_empty_query_table_list(thd->lex);
       const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
       DBUG_RETURN(actual_error);
     }
@@ -8409,6 +8439,9 @@ int Rows_log_event::do_apply_event(Relay
             having severe errors which should not be skiped.
           */
           thd->is_slave_error= 1;
+          /* remove trigger's tables */
+          if (slave_run_triggers_for_rbr)
+            restore_empty_query_table_list(thd->lex);
           const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
           DBUG_RETURN(ERR_BAD_TABLE_DEF);
         }
@@ -8436,8 +8469,11 @@ int Rows_log_event::do_apply_event(Relay
      */
     TABLE_LIST *ptr= rli->tables_to_lock;
     for (uint i=0 ;  ptr && (i < rli->tables_to_lock_count); ptr= ptr->next_global, i++)
+    {
       const_cast<Relay_log_info*>(rli)->m_table_map.set_table(ptr->table_id, ptr->table);
-
+      if (m_table_id == ptr->table_id)
+        master_had_triggers= ((RPL_TABLE_LIST*)ptr)->master_had_triggers;
+    }
 #ifdef HAVE_QUERY_CACHE
     query_cache.invalidate_locked_for_write(thd, rli->tables_to_lock);
 #endif
@@ -8447,8 +8483,10 @@ int Rows_log_event::do_apply_event(Relay
     table= 
     m_table= const_cast<Relay_log_info*>(rli)->m_table_map.get_table(m_table_id);
 
-  DBUG_PRINT("debug", ("m_table: 0x%lx, m_table_id: %lu", (ulong) m_table, m_table_id));
-
+  DBUG_PRINT("debug", ("m_table: 0x%lx, m_table_id: %lu%s",
+                       (ulong) m_table, m_table_id,
+                       table && master_had_triggers ?
+                       " (master had triggers)" : ""));
   if (table)
   {
     bool transactional_table= table->file->has_transactions();
@@ -8625,6 +8663,9 @@ int Rows_log_event::do_apply_event(Relay
     */
     thd->reset_current_stmt_binlog_format_row();
     thd->is_slave_error= 1;
+    /* remove trigger's tables */
+    if (slave_run_triggers_for_rbr)
+      restore_empty_query_table_list(thd->lex);
     DBUG_RETURN(error);
   }
 
@@ -8719,6 +8760,10 @@ static int rows_event_stmt_cleanup(Relay
     */
     thd->reset_current_stmt_binlog_format_row();
 
+    /* remove trigger's tables */
+    if (slave_run_triggers_for_rbr)
+      restore_empty_query_table_list(thd->lex);
+
     const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 0);
   }
   return error;
@@ -9098,6 +9143,7 @@ Table_map_log_event::Table_map_log_event
 {
   uchar cbuf[sizeof(m_colcnt) + 1];
   uchar *cbuf_end;
+  DBUG_ENTER("Table_map_log_event::Table_map_log_event(TABLE)");
   DBUG_ASSERT(m_table_id != ~0UL);
   /*
     In TABLE_SHARE, "db" and "table_name" are 0-terminated (see this comment in
@@ -9118,6 +9164,9 @@ Table_map_log_event::Table_map_log_event
   DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
   m_data_size+= (cbuf_end - cbuf) + m_colcnt;	// COLCNT and column types
 
+  if (tbl->triggers)
+    m_flags|= TM_BIT_HAS_TRIGGERS_F;
+
   /* If malloc fails, caught in is_valid() */
   if ((m_memory= (uchar*) my_malloc(m_colcnt, MYF(MY_WME))))
   {
@@ -9162,6 +9211,7 @@ Table_map_log_event::Table_map_log_event
     if (m_table->field[i]->maybe_null())
       m_null_bits[(i / 8)]+= 1 << (i % 8);
 
+  DBUG_VOID_RETURN;
 }
 #endif /* !defined(MYSQL_CLIENT) */
 
@@ -9520,7 +9570,11 @@ int Table_map_log_event::do_apply_event(
   table_list->table_id= DBUG_EVALUATE_IF("inject_tblmap_same_id_maps_diff_table", 0, m_table_id);
   table_list->updating= 1;
   table_list->required_type= FRMTYPE_TABLE;
-  DBUG_PRINT("debug", ("table: %s is mapped to %u", table_list->table_name, table_list->table_id));
+  table_list->master_had_triggers= ((m_flags & TM_BIT_HAS_TRIGGERS_F) ? 1 : 0);
+  DBUG_PRINT("debug", ("table: %s is mapped to %u%s",
+                       table_list->table_name, table_list->table_id,
+                       (table_list->master_had_triggers ?
+                        " (master had triggers)" : "")));
   enum_tbl_map_status tblmap_status= check_table_map(rli, table_list);
   if (tblmap_status == OK_TO_PROCESS)
   {
@@ -9692,8 +9746,10 @@ void Table_map_log_event::print(FILE *,
   {
     print_header(&print_event_info->head_cache, print_event_info, TRUE);
     my_b_printf(&print_event_info->head_cache,
-                "\tTable_map: %`s.%`s mapped to number %lu\n",
-                m_dbnam, m_tblnam, m_table_id);
+                "\tTable_map: %`s.%`s mapped to number %lu%s\n",
+                m_dbnam, m_tblnam, m_table_id,
+                ((m_flags & TM_BIT_HAS_TRIGGERS_F) ?
+                 " (has triggers)" : ""));
     print_base64(&print_event_info->body_cache, print_event_info, TRUE);
   }
 }
@@ -9769,6 +9825,8 @@ Write_rows_log_event::do_before_row_oper
     /* 
        NDB specific: update from ndb master wrapped as Write_rows
        so that the event should be applied to replace slave's row
+
+       Also following is needed in case if we have AFTER DELETE triggers.
     */
     m_table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
     /* 
@@ -9783,6 +9841,29 @@ Write_rows_log_event::do_before_row_oper
       from the start.
     */
   }
+  if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers )
+  {
+    if (m_table->triggers->has_triggers(TRG_EVENT_DELETE,
+                                        TRG_ACTION_AFTER))
+    {
+      /*
+        The table has AFTER DELETE triggers that might access to 
+        subject table and therefore might need delete to be done 
+        immediately. So we turn-off the batching.
+      */ 
+      (void) m_table->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
+    }
+    if (m_table->triggers->has_triggers(TRG_EVENT_UPDATE,
+                                        TRG_ACTION_AFTER))
+    {
+      /*
+        The table has AFTER UPDATE triggers that might access to subject 
+        table and therefore might need update to be done immediately. 
+        So we turn-off the batching.
+      */ 
+      (void) m_table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
+    }
+  }
 
   /*
     We need TIMESTAMP_NO_AUTO_SET otherwise ha_write_row() will not use fill
@@ -9845,6 +9926,25 @@ Write_rows_log_event::do_after_row_opera
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 
+bool Rows_log_event::process_triggers(trg_event_type event,
+                                      trg_action_time_type time_type,
+                                      bool old_row_is_record1)
+{
+  bool result;
+  DBUG_ENTER("Rows_log_event::process_triggers");
+  if (slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_YES)
+  {
+    tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
+    result= m_table->triggers->process_triggers(thd, event,
+                                              time_type, old_row_is_record1);
+    reenable_binlog(thd);
+  }
+  else
+    result= m_table->triggers->process_triggers(thd, event,
+                                              time_type, old_row_is_record1);
+
+  DBUG_RETURN(result);
+}
 /*
   Check if there are more UNIQUE keys after the given key.
 */
@@ -9927,6 +10027,8 @@ Rows_log_event::write_row(const Relay_lo
   TABLE *table= m_table;  // pointer to event's table
   int error;
   int UNINIT_VAR(keynum);
+  bool invoke_triggers=
+    slave_run_triggers_for_rbr && !master_had_triggers && table->triggers;
   auto_afree_ptr<char> key(NULL);
 
   prepare_record(table, m_width,
@@ -9936,13 +10038,17 @@ Rows_log_event::write_row(const Relay_lo
   if ((error= unpack_current_row(rli)))
     DBUG_RETURN(error);
 
-  if (m_curr_row == m_rows_buf)
+  if (m_curr_row == m_rows_buf && !invoke_triggers)
   {
-    /* this is the first row to be inserted, we estimate the rows with
+    /*
+       This table has no triggers so we can do bulk insert.
+
+       This is the first row to be inserted, we estimate the rows with
        the size of the first row and use that value to initialize
-       storage engine for bulk insertion */
+       storage engine for bulk insertion.
+    */
     ulong estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
-    m_table->file->ha_start_bulk_insert(estimated_rows);
+    table->file->ha_start_bulk_insert(estimated_rows);
   }
   
   
@@ -9952,6 +10058,12 @@ Rows_log_event::write_row(const Relay_lo
   DBUG_PRINT_BITSET("debug", "read_set = %s", table->read_set);
 #endif
 
+  if (invoke_triggers &&
+      process_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE, TRUE))
+  {
+      DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
+  }
+
   /* 
     Try to write record. If a corresponding record already exists in the table,
     we try to change it using ha_update_row() if possible. Otherwise we delete
@@ -10078,38 +10190,61 @@ Rows_log_event::write_row(const Relay_lo
         !table->file->referenced_by_foreign_key())
     {
       DBUG_PRINT("info",("Updating row using ha_update_row()"));
-      error=table->file->ha_update_row(table->record[1],
-                                       table->record[0]);
-      switch (error) {
-                
-      case HA_ERR_RECORD_IS_THE_SAME:
-        DBUG_PRINT("info",("ignoring HA_ERR_RECORD_IS_THE_SAME error from"
-                           " ha_update_row()"));
-        error= 0;
-      
-      case 0:
-        break;
-        
-      default:    
-        DBUG_PRINT("info",("ha_update_row() returns error %d",error));
-        table->file->print_error(error, MYF(0));
+      if (invoke_triggers &&
+          process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, FALSE))
+        error= HA_ERR_GENERIC; // in case if error is not set yet
+      else
+      {
+        error= table->file->ha_update_row(table->record[1],
+                                         table->record[0]);
+        switch (error) {
+
+        case HA_ERR_RECORD_IS_THE_SAME:
+          DBUG_PRINT("info",("ignoring HA_ERR_RECORD_IS_THE_SAME error from"
+                             " ha_update_row()"));
+          error= 0;
+
+        case 0:
+          break;
+
+        default:
+          DBUG_PRINT("info",("ha_update_row() returns error %d",error));
+          table->file->print_error(error, MYF(0));
+        }
+        if (invoke_triggers && !error &&
+            (process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE) ||
+             process_triggers(TRG_EVENT_INSERT, TRG_ACTION_AFTER, TRUE)))
+          error= HA_ERR_GENERIC; // in case if error is not set yet
       }
-      
+
       DBUG_RETURN(error);
     }
     else
     {
       DBUG_PRINT("info",("Deleting offending row and trying to write new one again"));
-      if ((error= table->file->ha_delete_row(table->record[1])))
+      if (invoke_triggers &&
+          process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, TRUE))
+        error= HA_ERR_GENERIC; // in case if error is not set yet
+      else
       {
-        DBUG_PRINT("info",("ha_delete_row() returns error %d",error));
-        table->file->print_error(error, MYF(0));
-        DBUG_RETURN(error);
+        if ((error= table->file->ha_delete_row(table->record[1])))
+        {
+          DBUG_PRINT("info",("ha_delete_row() returns error %d",error));
+          table->file->print_error(error, MYF(0));
+          DBUG_RETURN(error);
+        }
+        if (invoke_triggers &&
+            process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER, TRUE))
+          DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
       }
       /* Will retry ha_write_row() with the offending row removed. */
     }
   }
 
+  if (invoke_triggers &&
+      process_triggers(TRG_EVENT_INSERT, TRG_ACTION_AFTER, TRUE))
+    error= HA_ERR_GENERIC; // in case if error is not set yet
+
   DBUG_RETURN(error);
 }
 
@@ -10141,6 +10276,16 @@ void Write_rows_log_event::print(FILE *f
 }
 #endif
 
+
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+uint8 Write_rows_log_event::get_trg_event_map()
+{
+  return (static_cast<uint8> (1 << static_cast<int>(TRG_EVENT_INSERT)) |
+          static_cast<uint8> (1 << static_cast<int>(TRG_EVENT_UPDATE)) |
+          static_cast<uint8> (1 << static_cast<int>(TRG_EVENT_DELETE)));
+}
+#endif
+
 /**************************************************************************
 	Delete_rows_log_event member functions
 **************************************************************************/
@@ -10759,6 +10904,17 @@ Delete_rows_log_event::do_before_row_ope
     */
     return 0;
   }
+  if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers &&
+      m_table->triggers->has_triggers(TRG_EVENT_DELETE,
+                                    TRG_ACTION_AFTER))
+  {
+    /*
+      The table has AFTER DELETE triggers that might access to subject table
+      and therefore might need delete to be done immediately. So we turn-off
+      the batching.
+    */
+    (void) m_table->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
+  }
 
   return find_key();
 }
@@ -10779,6 +10935,8 @@ Delete_rows_log_event::do_after_row_oper
 int Delete_rows_log_event::do_exec_row(const Relay_log_info *const rli)
 {
   int error;
+  bool invoke_triggers=
+    slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
   DBUG_ASSERT(m_table != NULL);
 
   if (!(error= find_row(rli))) 
@@ -10786,7 +10944,14 @@ int Delete_rows_log_event::do_exec_row(c
     /*
       Delete the record found, located in record[0]
     */
-    error= m_table->file->ha_delete_row(m_table->record[0]);
+    if (invoke_triggers &&
+        process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE))
+      error= HA_ERR_GENERIC; // in case if error is not set yet
+    if (!error)
+      error= m_table->file->ha_delete_row(m_table->record[0]);
+    if (invoke_triggers && !error &&
+        process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE))
+      error= HA_ERR_GENERIC; // in case if error is not set yet
     m_table->file->ha_index_or_rnd_end();
   }
   return error;
@@ -10803,6 +10968,13 @@ void Delete_rows_log_event::print(FILE *
 #endif
 
 
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+uint8 Delete_rows_log_event::get_trg_event_map()
+{
+  return static_cast<uint8> (1 << static_cast<int>(TRG_EVENT_DELETE));
+}
+#endif
+
 /**************************************************************************
 	Update_rows_log_event member functions
 **************************************************************************/
@@ -10887,6 +11059,18 @@ Update_rows_log_event::do_before_row_ope
 
   m_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
 
+  if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers &&
+      m_table->triggers->has_triggers(TRG_EVENT_UPDATE,
+                                      TRG_ACTION_AFTER))
+  {
+    /*
+      The table has AFTER UPDATE triggers that might access to subject
+      table and therefore might need update to be done immediately.
+      So we turn-off the batching.
+    */ 
+    (void) m_table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
+  }
+
   return 0;
 }
 
@@ -10906,6 +11090,8 @@ Update_rows_log_event::do_after_row_oper
 int 
 Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
 {
+  bool invoke_triggers=
+    slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
   DBUG_ASSERT(m_table != NULL);
 
   int error= find_row(rli); 
@@ -10952,10 +11138,21 @@ Update_rows_log_event::do_exec_row(const
   DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength);
 #endif
 
+  if (invoke_triggers &&
+      process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE))
+  {
+    error= HA_ERR_GENERIC; // in case if error is not set yet
+    goto err;
+  }
+
   error= m_table->file->ha_update_row(m_table->record[1], m_table->record[0]);
   if (error == HA_ERR_RECORD_IS_THE_SAME)
     error= 0;
 
+  if (invoke_triggers && !error &&
+      process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE))
+    error= HA_ERR_GENERIC; // in case if error is not set yet
+
 err:
   m_table->file->ha_index_or_rnd_end();
   return error;
@@ -10971,6 +11168,12 @@ void Update_rows_log_event::print(FILE *
 }
 #endif
 
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+uint8 Update_rows_log_event::get_trg_event_map()
+{
+  return static_cast<uint8> (1 << static_cast<int>(TRG_EVENT_UPDATE));
+}
+#endif
 
 Incident_log_event::Incident_log_event(const char *buf, uint event_len,
                                        const Format_description_log_event *descr_event)

=== modified file 'sql/log_event.h'
--- a/sql/log_event.h	2013-09-06 20:31:30 +0000
+++ b/sql/log_event.h	2013-12-02 13:50:28 +0000
@@ -3642,7 +3642,9 @@ public:
   enum 
   {
     TM_NO_FLAGS = 0U,
-    TM_BIT_LEN_EXACT_F = (1U << 0)
+    TM_BIT_LEN_EXACT_F = (1U << 0),
+    // MariaDB flags (we starts from the other end)
+    TM_BIT_HAS_TRIGGERS_F= (1U << 14)
   };
 
   flag_set get_flags(flag_set flag) const { return m_flags & flag; }
@@ -3840,6 +3842,10 @@ public:
 
   uint     m_row_count;         /* The number of rows added to the event */
 
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+  virtual uint8 get_trg_event_map()= 0;
+#endif
+
 protected:
   /* 
      The constructors are protected since you're supposed to inherit
@@ -3888,6 +3894,7 @@ protected:
 
   flag_set m_flags;		/* Flags for row-level events */
 
+
   /* helper functions */
 
 #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
@@ -3896,6 +3903,7 @@ protected:
   uchar    *m_key;      /* Buffer to keep key value during searches */
   KEY      *m_key_info; /* Pointer to KEY info for m_key_nr */
   uint      m_key_nr;   /* Key number */
+  bool master_had_triggers;     /* set after tables opening */
 
   int find_key(); // Find a best key to use in find_row()
   int find_row(const Relay_log_info *const);
@@ -3915,6 +3923,9 @@ protected:
     ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
     return result;
   }
+  bool process_triggers(trg_event_type event,
+                        trg_action_time_type time_type,
+                        bool old_row_is_record1);
 #endif
 
 private:
@@ -4019,6 +4030,10 @@ public:
   }
 #endif
 
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+  uint8 get_trg_event_map();
+#endif
+
 private:
   virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
 
@@ -4093,6 +4108,10 @@ public:
     return Rows_log_event::is_valid() && m_cols_ai.bitmap;
   }
 
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+  uint8 get_trg_event_map();
+#endif
+
 protected:
   virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
 
@@ -4157,7 +4176,11 @@ public:
                                   cols, fields, before_record);
   }
 #endif
-  
+
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+  uint8 get_trg_event_map();
+#endif
+
 protected:
   virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
 

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2013-11-19 12:16:25 +0000
+++ b/sql/mysqld.cc	2013-12-03 12:18:20 +0000
@@ -475,6 +475,7 @@ ulong open_files_limit, max_binlog_size,
 ulong slave_trans_retries;
 uint  slave_net_timeout;
 ulong slave_exec_mode_options;
+ulong slave_run_triggers_for_rbr;
 ulonglong slave_type_conversions_options;
 ulong thread_cache_size=0;
 ulonglong binlog_cache_size=0;

=== modified file 'sql/mysqld.h'
--- a/sql/mysqld.h	2013-11-19 12:16:25 +0000
+++ b/sql/mysqld.h	2013-12-03 12:18:20 +0000
@@ -95,6 +95,7 @@ extern my_bool opt_safe_user_create;
 extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap;
 extern my_bool opt_slave_compressed_protocol, use_temp_pool;
 extern ulong slave_exec_mode_options;
+extern ulong slave_run_triggers_for_rbr;
 extern ulonglong slave_type_conversions_options;
 extern my_bool read_only, opt_readonly;
 extern my_bool lower_case_file_system;

=== modified file 'sql/rpl_utility.h'
--- a/sql/rpl_utility.h	2013-05-07 11:05:09 +0000
+++ b/sql/rpl_utility.h	2013-11-27 08:08:32 +0000
@@ -230,6 +230,7 @@ struct RPL_TABLE_LIST
   bool m_tabledef_valid;
   table_def m_tabledef;
   TABLE *m_conv_table;
+  bool master_had_triggers;
 };
 
 

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2013-11-19 12:16:25 +0000
+++ b/sql/sql_class.h	2013-12-03 12:18:20 +0000
@@ -68,6 +68,9 @@ enum enum_delay_key_write { DELAY_KEY_WR
 enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT,
                             SLAVE_EXEC_MODE_IDEMPOTENT,
                             SLAVE_EXEC_MODE_LAST_BIT};
+enum enum_slave_run_triggers_for_rbr { SLAVE_RUN_TRIGGERS_FOR_RBR_NO,
+                                       SLAVE_RUN_TRIGGERS_FOR_RBR_YES,
+                                       SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING};
 enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY,
                                    SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY};
 enum enum_mark_columns

=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc	2013-11-19 12:16:25 +0000
+++ b/sql/sys_vars.cc	2013-12-03 12:18:20 +0000
@@ -1996,6 +1996,21 @@ static Sys_var_enum Slave_exec_mode(
        GLOBAL_VAR(slave_exec_mode_options), CMD_LINE(REQUIRED_ARG),
        slave_exec_mode_names, DEFAULT(SLAVE_EXEC_MODE_STRICT));
 
+static const char *slave_run_triggers_for_rbr_names[]=
+  {"NO", "YES", "LOGGING", 0};
+static Sys_var_enum Slave_run_triggers_for_rbr(
+       "slave_run_triggers_for_rbr",
+       "Modes for how triggers in row-base replication on slave side will "
+       "be executed. Legal values "
+       "are NO (default), YES and LOGGING. "
+       "NO means that trigger for RBR will not be running on slave "
+       "YES and LOGGING means that triggers will be running on slave "
+       "(if there was not triggers running on the naster), LOGGING also "
+       "mens that flag about executed triggers will be written to binlog.",
+       GLOBAL_VAR(slave_run_triggers_for_rbr), CMD_LINE(REQUIRED_ARG),
+       slave_run_triggers_for_rbr_names,
+       DEFAULT(SLAVE_RUN_TRIGGERS_FOR_RBR_NO));
+
 static const char *slave_type_conversions_name[]= {"ALL_LOSSY", "ALL_NON_LOSSY", 0};
 static Sys_var_set Slave_type_conversions(
        "slave_type_conversions",



More information about the commits mailing list