[Commits] Rev 3916: MDEV-5095: Executing triggers on slave in row-based replication in file:///home/bell/maria/bzr/work-maria-10.0-MDEV-5095/

sanja at montyprogram.com sanja at montyprogram.com
Mon Dec 9 00:08:37 EET 2013


At file:///home/bell/maria/bzr/work-maria-10.0-MDEV-5095/

------------------------------------------------------------
revno: 3916
revision-id: sanja at montyprogram.com-20131208220835-k5hl11lf9aaor0l8
parent: bar at mnogosearch.org-20131206150255-und2j89f85by7imn
committer: sanja at montyprogram.com
branch nick: work-maria-10.0-MDEV-5095
timestamp: Mon 2013-12-09 00:08:35 +0200
message:
  MDEV-5095: Executing triggers on slave in row-based replication
  
  Pre-review version for 10.0
-------------- next part --------------
=== modified file 'mysql-test/r/mysqld--help.result'
--- a/mysql-test/r/mysqld--help.result	2013-11-25 14:49:40 +0000
+++ b/mysql-test/r/mysqld--help.result	2013-12-08 22:08:35 +0000
@@ -883,6 +883,14 @@ The following options may be given as th
  in parallel events on the slave that were group-committed
  on the master or were logged with GTID in different
  replication domains.
+ --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
@@ -1264,6 +1272,7 @@ slave-max-allowed-packet 1073741824
 slave-net-timeout 3600
 slave-parallel-max-queued 131072
 slave-parallel-threads 0
+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/suite/rpl/r/rpl_row_triggers.result'
--- a/mysql-test/suite/rpl/r/rpl_row_triggers.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_row_triggers.result	2013-12-08 22:08:35 +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/suite/rpl/r/rpl_row_triggers_sbr.result'
--- a/mysql-test/suite/rpl/r/rpl_row_triggers_sbr.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_row_triggers_sbr.result	2013-12-08 22:08:35 +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/rpl/t/rpl_row_triggers.test'
--- a/mysql-test/suite/rpl/t/rpl_row_triggers.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_row_triggers.test	2013-12-08 22:08:35 +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/suite/rpl/t/rpl_row_triggers_sbr.test'
--- a/mysql-test/suite/rpl/t/rpl_row_triggers_sbr.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_row_triggers_sbr.test	2013-12-08 22:08:35 +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-13 22:03:48 +0000
+++ b/sql/log_event.cc	2013-12-08 22:08:35 +0000
@@ -9041,7 +9041,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
 {
   /*
@@ -9090,7 +9091,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*,...)");
@@ -9282,7 +9284,17 @@ 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(rpl_group_info *rgi)
 {
   Relay_log_info const *rli= rgi->rli;
@@ -9365,6 +9377,22 @@ int Rows_log_event::do_apply_event(rpl_g
     /* 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= rgi->tables_to_lock))
+        rgi->tables_to_lock->prev_global= &lex->query_tables;
+
+      for (TABLE_LIST *tables= rgi->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, rgi->tables_to_lock, FALSE, 0))
     {
       uint actual_error= thd->get_stmt_da()->sql_errno();
@@ -9382,6 +9410,9 @@ int Rows_log_event::do_apply_event(rpl_g
                      "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);
       rgi->slave_close_thread_tables(thd);
       DBUG_RETURN(actual_error);
     }
@@ -9427,6 +9458,9 @@ int Rows_log_event::do_apply_event(rpl_g
             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);
           rgi->slave_close_thread_tables(thd);
           DBUG_RETURN(ERR_BAD_TABLE_DEF);
         }
@@ -9454,7 +9488,11 @@ int Rows_log_event::do_apply_event(rpl_g
      */
     TABLE_LIST *ptr= rgi->tables_to_lock;
     for (uint i=0 ;  ptr && (i < rgi->tables_to_lock_count); ptr= ptr->next_global, i++)
+    {
       rgi->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, rgi->tables_to_lock);
@@ -9465,8 +9503,10 @@ int Rows_log_event::do_apply_event(rpl_g
     table= 
     m_table= rgi->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();
@@ -9632,9 +9672,15 @@ int Rows_log_event::do_apply_event(rpl_g
     */
     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);
   }
 
+  /* remove trigger's tables */
+  if (slave_run_triggers_for_rbr)
+    restore_empty_query_table_list(thd->lex);
   if (get_flags(STMT_END_F) && (error= rows_event_stmt_cleanup(rgi, thd)))
     slave_rows_error_report(ERROR_LEVEL,
                             thd->is_error() ? 0 : error,
@@ -10112,6 +10158,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
@@ -10132,6 +10179,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))))
   {
@@ -10176,6 +10226,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) */
 
@@ -10538,7 +10589,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(rgi, table_list);
   if (tblmap_status == OK_TO_PROCESS)
   {
@@ -10710,8 +10765,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, (ulong) 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);
   }
 }
@@ -10787,6 +10844,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);
     /* 
@@ -10801,6 +10860,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);
+    }
+  }
 
   /* Honor next number column if present */
   m_table->next_number_field= m_table->found_next_number_field;
@@ -10846,6 +10928,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.
 */
@@ -10928,6 +11029,8 @@ Rows_log_event::write_row(rpl_group_info
   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,
@@ -10937,13 +11040,17 @@ Rows_log_event::write_row(rpl_group_info
   if ((error= unpack_current_row(rgi)))
     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);
   }
   
   
@@ -10953,6 +11060,12 @@ Rows_log_event::write_row(rpl_group_info
   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
@@ -11079,38 +11192,61 @@ Rows_log_event::write_row(rpl_group_info
         !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);
 }
 
@@ -11142,6 +11278,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
 **************************************************************************/
@@ -11766,6 +11912,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();
 }
@@ -11786,6 +11943,8 @@ Delete_rows_log_event::do_after_row_oper
 int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
 {
   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(rgi))) 
@@ -11793,7 +11952,14 @@ int Delete_rows_log_event::do_exec_row(r
     /*
       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;
@@ -11810,6 +11976,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
 **************************************************************************/
@@ -11892,6 +12065,18 @@ Update_rows_log_event::do_before_row_ope
   if ((err= find_key()))
     return err;
 
+  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;
 }
 
@@ -11911,6 +12096,8 @@ Update_rows_log_event::do_after_row_oper
 int 
 Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
 {
+  bool invoke_triggers=
+    slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
   DBUG_ASSERT(m_table != NULL);
 
   int error= find_row(rgi); 
@@ -11957,10 +12144,21 @@ Update_rows_log_event::do_exec_row(rpl_g
   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;
@@ -11976,6 +12174,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-11-01 11:00:11 +0000
+++ b/sql/log_event.h	2013-12-08 22:08:35 +0000
@@ -4026,7 +4026,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; }
@@ -4226,6 +4228,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
@@ -4274,6 +4280,7 @@ protected:
 
   flag_set m_flags;		/* Flags for row-level events */
 
+
   /* helper functions */
 
 #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
@@ -4282,6 +4289,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(rpl_group_info *);
@@ -4301,6 +4309,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:
@@ -4405,6 +4416,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; }
 
@@ -4479,6 +4494,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; }
 
@@ -4543,7 +4562,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-25 14:49:40 +0000
+++ b/sql/mysqld.cc	2013-12-08 22:08:35 +0000
@@ -478,6 +478,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-25 14:49:40 +0000
+++ b/sql/mysqld.h	2013-12-08 22:08:35 +0000
@@ -98,6 +98,7 @@ extern my_bool opt_safe_show_db, opt_loc
 extern my_bool opt_slave_compressed_protocol, use_temp_pool;
 extern ulong slave_exec_mode_options;
 extern ulong slave_retried_transactions;
+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-11-01 11:00:11 +0000
+++ b/sql/rpl_utility.h	2013-12-08 22:08:35 +0000
@@ -238,6 +238,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-13 22:03:48 +0000
+++ b/sql/sql_class.h	2013-12-08 22:08:35 +0000
@@ -80,6 +80,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-25 14:49:40 +0000
+++ b/sql/sys_vars.cc	2013-12-08 22:08:35 +0000
@@ -2601,6 +2601,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