[MDEV-24203] Function Rows_log_event::process_triggers seems to always run m_table->triggers->process_triggers Created: 2020-11-12  Updated: 2020-11-18

Status: Open
Project: MariaDB Server
Component/s: Replication, Triggers
Affects Version/s: 10.5
Fix Version/s: 10.5

Type: Bug Priority: Major
Reporter: Alexander Rubin Assignee: Sergei Golubchik
Resolution: Unresolved Votes: 1
Labels: None


 Description   

The code from here: https://github.com/MariaDB/server/blob/6ce0a6f9ad77e7934e27db1b73d6d98064352928/sql/log_event_server.cc#L7114

Shows

 if (slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_YES)
  {
    result= m_table->triggers->process_triggers(thd, event,
                                                time_type,
                                                old_row_is_record1);
  }
  else
    result= m_table->triggers->process_triggers(thd, event,
                                                time_type,
                                                old_row_is_record1);

Which seems to run the exact same function despite of the condition. At the same time, RBR triggers seems to work correctly.



 Comments   
Comment by Sergei Golubchik [ 2020-11-13 ]

It looks like we don't have a test for slave_run_triggers_for_rbr=YES, so this change went unnoticed.

slave_run_triggers_for_rbr=YES differs from slave_run_triggers_for_rbr=LOGGING in that rbr changes are not replicated further. The test would need a chain of replication master->slave1->slave2 with slave_run_triggers_for_rbr=YES on the middle slave and a check whether trigger-made changes were replicated to slave2. Or may be one can do with a simple master-slave and SHOW BINLOG EVENTS on the slave.

This test could also check that with LOGGING or ENFORCE changes are replicated indeed.

Comment by Alice Sherepa [ 2020-11-18 ]

The change should be reverted, as now slave_run_triggers_for_rbr= LOGGING and=YES work the same way,
changes are written in the binlog. =enforce and =logging work as expected
test below is just to demonstrate it:

-- source include/have_binlog_format_row.inc
-- source include/have_innodb.inc
-- source include/master-slave.inc
 
connection master;
CREATE TABLE t1 (i int primary key  NOT NULL auto_increment) engine=innodb;
CREATE TABLE t2 (j int primary key  NOT NULL auto_increment) engine=innodb;
CREATE TABLE t3 (k int primary key  NOT NULL auto_increment) engine=innodb;
sync_slave_with_master;
 
connection slave;
SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
SET @@global.slave_run_triggers_for_rbr= YES;
 
create trigger tr_s1 after insert on t1 for each row insert into t2 values(default);
create trigger tr_s2 after insert on t2 for each row insert into t3 values(default);
 
connection master;
insert into t1 values (1);
sync_slave_with_master;
 
select * from t2;
select * from t3;
 
SET @@global.slave_run_triggers_for_rbr= LOGGING;
 
connection master;
insert into t1 values (2);
sync_slave_with_master;
 
select * from t2;
select * from t3;
 
connection master;
create trigger tr_m1 after insert on t1 for each row set @a:=1;
insert into t1 values (3);
sync_slave_with_master;
 
#triggers should not work as now there is a trigger on master
select * from t2;
select * from t3;
 
SET @@global.slave_run_triggers_for_rbr= ENFORCE;
 
connection master;
insert into t1 values (4);
sync_slave_with_master;
 
select * from t1;
select * from t2;
select * from t3;
source include/show_binlog_events.inc;
 
connection master;
drop table t1,t2,t3;
sync_slave_with_master;
SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
--source include/rpl_end.inc

include/master-slave.inc
[connection master]
connection master;
CREATE TABLE t1 (i int primary key  NOT NULL auto_increment) engine=innodb;
CREATE TABLE t2 (j int primary key  NOT NULL auto_increment) engine=innodb;
CREATE TABLE t3 (k int primary key  NOT NULL auto_increment) engine=innodb;
connection slave;
connection slave;
SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
SET @@global.slave_run_triggers_for_rbr= YES;
create trigger tr_s1 after insert on t1 for each row insert into t2 values(default);
create trigger tr_s2 after insert on t2 for each row insert into t3 values(default);
connection master;
insert into t1 values (1);
connection slave;
select * from t2;
j
1
select * from t3;
k
1
SET @@global.slave_run_triggers_for_rbr= LOGGING;
connection master;
insert into t1 values (2);
connection slave;
select * from t2;
j
1
2
select * from t3;
k
1
2
connection master;
create trigger tr_m1 after insert on t1 for each row set @a:=1;
insert into t1 values (3);
connection slave;
select * from t2;
j
1
2
select * from t3;
k
1
2
SET @@global.slave_run_triggers_for_rbr= ENFORCE;
connection master;
insert into t1 values (4);
connection slave;
select * from t1;
i
1
2
3
4
select * from t2;
j
1
2
3
select * from t3;
k
1
2
3
include/show_binlog_events.inc
Log_name	Pos	Event_type	Server_id	End_log_pos	Info
slave-bin.000001	#	Gtid	#	#	GTID #-#-#
slave-bin.000001	#	Query	#	#	use `test`; CREATE TABLE t1 (i int primary key  NOT NULL auto_increment) engine=innodb
slave-bin.000001	#	Gtid	#	#	GTID #-#-#
slave-bin.000001	#	Query	#	#	use `test`; CREATE TABLE t2 (j int primary key  NOT NULL auto_increment) engine=innodb
slave-bin.000001	#	Gtid	#	#	GTID #-#-#
slave-bin.000001	#	Query	#	#	use `test`; CREATE TABLE t3 (k int primary key  NOT NULL auto_increment) engine=innodb
slave-bin.000001	#	Gtid	#	#	GTID #-#-#
slave-bin.000001	#	Query	#	#	use `test`; CREATE DEFINER=`root`@`localhost` trigger tr_s1 after insert on t1 for each row insert into t2 values(default)
slave-bin.000001	#	Gtid	#	#	GTID #-#-#
slave-bin.000001	#	Query	#	#	use `test`; CREATE DEFINER=`root`@`localhost` trigger tr_s2 after insert on t2 for each row insert into t3 values(default)
slave-bin.000001	#	Gtid	#	#	BEGIN GTID #-#-#
slave-bin.000001	#	Annotate_rows	#	#	insert into t1 values (1)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t1)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t3)
slave-bin.000001	#	Write_rows_v1	#	#	table_id: #
slave-bin.000001	#	Write_rows_v1	#	#	table_id: #
slave-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
slave-bin.000001	#	Xid	#	#	COMMIT /* XID */
slave-bin.000001	#	Gtid	#	#	BEGIN GTID #-#-#
slave-bin.000001	#	Annotate_rows	#	#	insert into t1 values (2)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t1)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t3)
slave-bin.000001	#	Write_rows_v1	#	#	table_id: #
slave-bin.000001	#	Write_rows_v1	#	#	table_id: #
slave-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
slave-bin.000001	#	Xid	#	#	COMMIT /* XID */
slave-bin.000001	#	Gtid	#	#	GTID #-#-#
slave-bin.000001	#	Query	#	#	use `test`; CREATE DEFINER=`root`@`localhost` trigger tr_m1 after insert on t1 for each row set @a:=1
slave-bin.000001	#	Gtid	#	#	BEGIN GTID #-#-#
slave-bin.000001	#	Annotate_rows	#	#	insert into t1 values (3)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t1)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t3)
slave-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
slave-bin.000001	#	Xid	#	#	COMMIT /* XID */
slave-bin.000001	#	Gtid	#	#	BEGIN GTID #-#-#
slave-bin.000001	#	Annotate_rows	#	#	insert into t1 values (4)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t1)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t2)
slave-bin.000001	#	Table_map	#	#	table_id: # (test.t3)
slave-bin.000001	#	Write_rows_v1	#	#	table_id: #
slave-bin.000001	#	Write_rows_v1	#	#	table_id: #
slave-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
slave-bin.000001	#	Xid	#	#	COMMIT /* XID */
connection master;
drop table t1,t2,t3;
connection slave;
SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
include/rpl_end.inc

Generated at Thu Feb 08 09:28:13 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.