Skip to content

Commit 980108c

Browse files
sanja-byelkinandrelkin
authored andcommitted
MDEV-21833 Make slave_run_triggers_for_rbr enforce triggers to run on slave, even when there are triggers on the master
A bit changed patch of Anders Karlsson with examples added. New parameters "ENFORCE" to slave-run-triggers-for-rbr added.
1 parent 1f5a8e1 commit 980108c

File tree

8 files changed

+278
-23
lines changed

8 files changed

+278
-23
lines changed

mysql-test/main/mysqld--help.result

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,13 +1187,15 @@ The following specify which files/extra groups are read (specified before remain
11871187
Alias for slave_parallel_threads
11881188
--slave-run-triggers-for-rbr=name
11891189
Modes for how triggers in row-base replication on slave
1190-
side will be executed. Legal values are NO (default), YES
1191-
and LOGGING. NO means that trigger for RBR will not be
1192-
running on slave. YES and LOGGING means that triggers
1193-
will be running on slave, if there was not triggers
1194-
running on the master for the statement. LOGGING also
1195-
means results of that the executed triggers work will be
1196-
written to the binlog.
1190+
side will be executed. Legal values are NO (default),
1191+
YES, LOGGING and ENFORCE. NO means that trigger for RBR
1192+
will not be running on slave. YES and LOGGING means that
1193+
triggers will be running on slave, if there was not
1194+
triggers running on the master for the statement. LOGGING
1195+
also means results of that the executed triggers work
1196+
will be written to the binlog. ENFORCE means that
1197+
triggers will always be run on the slave, even if there
1198+
are triggers on the master. ENFORCE implies LOGGING.
11971199
--slave-skip-errors=name
11981200
Tells the slave thread to continue replication when a
11991201
query event returns an error from the provided list

mysql-test/suite/rpl/r/rpl_row_triggers.result

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,4 +338,136 @@ connection master;
338338
set binlog_row_image = @binlog_row_image.saved;
339339
drop table t1;
340340
connection slave;
341+
#
342+
# enterprise 10.4 tests start
343+
#
344+
#
345+
# MENT-607 : Make slave_run_triggers_for_rbr enforce triggers to run
346+
# on slave, even when there are triggers on the master
347+
#
348+
# Triggers on slave WILL work (with ENFORCE) if master has some
349+
connection master;
350+
CREATE TABLE t1 (C1 CHAR(1) primary key, C2 CHAR(1)) engine=innodb;
351+
SELECT * FROM t1;
352+
C1 C2
353+
create trigger t1_dummy before delete on t1 for each row
354+
set @dummy= 1;
355+
connection slave;
356+
connection slave;
357+
SET @old_slave_exec_mode= @@global.slave_exec_mode;
358+
SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
359+
SET @@global.slave_exec_mode= IDEMPOTENT;
360+
SET @@global.slave_run_triggers_for_rbr= ENFORCE;
361+
SELECT * FROM t1;
362+
C1 C2
363+
create table t2 (id char(2) primary key, cnt int, o char(1), n char(1));
364+
insert into t2 values
365+
('u0', 0, ' ', ' '),('u1', 0, ' ', ' '),
366+
('d0', 0, ' ', ' '),('d1', 0, ' ', ' '),
367+
('i0', 0, ' ', ' '),('i1', 0, ' ', ' ');
368+
create trigger t1_cnt_b before update on t1 for each row
369+
update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u0';
370+
create trigger t1_cnt_ib before insert on t1 for each row
371+
update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i0';
372+
create trigger t1_cnt_a after update on t1 for each row
373+
update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u1';
374+
create trigger t1_cnt_da after delete on t1 for each row
375+
update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd1';
376+
create trigger t1_cnt_ia after insert on t1 for each row
377+
update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i1';
378+
SELECT * FROM t2 order by id;
379+
id cnt o n
380+
d0 0
381+
d1 0
382+
i0 0
383+
i1 0
384+
u0 0
385+
u1 0
386+
connection master;
387+
# INSERT triggers test
388+
insert into t1 values ('a','b');
389+
connection slave;
390+
connection slave;
391+
SELECT * FROM t2 order by id;
392+
id cnt o n
393+
d0 0
394+
d1 0
395+
i0 1 a
396+
i1 1 a
397+
u0 0
398+
u1 0
399+
connection master;
400+
# UPDATE triggers test
401+
update t1 set C1= 'd';
402+
connection slave;
403+
connection slave;
404+
SELECT * FROM t2 order by id;
405+
id cnt o n
406+
d0 0
407+
d1 0
408+
i0 1 a
409+
i1 1 a
410+
u0 1 a d
411+
u1 1 a d
412+
connection master;
413+
# DELETE triggers test
414+
delete from t1 where C1='d';
415+
connection slave;
416+
connection slave;
417+
SELECT * FROM t2 order by id;
418+
id cnt o n
419+
d0 0
420+
d1 1 d
421+
i0 1 a
422+
i1 1 a
423+
u0 1 a d
424+
u1 1 a d
425+
# INSERT triggers which cause also UPDATE test (insert duplicate row)
426+
insert into t1 values ('0','1');
427+
SELECT * FROM t2 order by id;
428+
id cnt o n
429+
d0 0
430+
d1 1 d
431+
i0 2 0
432+
i1 2 0
433+
u0 1 a d
434+
u1 1 a d
435+
connection master;
436+
insert into t1 values ('0','1');
437+
connection slave;
438+
connection slave;
439+
SELECT * FROM t2 order by id;
440+
id cnt o n
441+
d0 0
442+
d1 2 0
443+
i0 3 0
444+
i1 3 0
445+
u0 1 a d
446+
u1 1 a d
447+
# INSERT triggers which cause also DELETE test
448+
# (insert duplicate row in table referenced by foreign key)
449+
insert into t1 values ('1','1');
450+
connection master;
451+
CREATE TABLE t3 (C1 CHAR(1) primary key, FOREIGN KEY (C1) REFERENCES t1(C1) ) engine=innodb;
452+
insert into t1 values ('1','1');
453+
connection slave;
454+
connection slave;
455+
SELECT * FROM t2 order by id;
456+
id cnt o n
457+
d0 0
458+
d1 3 1
459+
i0 5 1
460+
i1 5 1
461+
u0 1 a d
462+
u1 1 a d
463+
connection master;
464+
drop table t3,t1;
465+
connection slave;
466+
connection slave;
467+
SET @@global.slave_exec_mode= @old_slave_exec_mode;
468+
SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
469+
drop table t2;
470+
#
471+
# enterprise 10.4 tests end
472+
#
341473
include/rpl_end.inc

mysql-test/suite/rpl/t/rpl_row_triggers.test

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,4 +323,120 @@ drop table t1;
323323

324324
--sync_slave_with_master
325325

326+
--echo #
327+
--echo # enterprise 10.4 tests start
328+
--echo #
329+
330+
--echo #
331+
--echo # MENT-607 : Make slave_run_triggers_for_rbr enforce triggers to run
332+
--echo # on slave, even when there are triggers on the master
333+
--echo #
334+
335+
--echo # Triggers on slave WILL work (with ENFORCE) if master has some
336+
337+
connection master;
338+
CREATE TABLE t1 (C1 CHAR(1) primary key, C2 CHAR(1)) engine=innodb;
339+
SELECT * FROM t1;
340+
341+
create trigger t1_dummy before delete on t1 for each row
342+
set @dummy= 1;
343+
344+
sync_slave_with_master;
345+
346+
connection slave;
347+
SET @old_slave_exec_mode= @@global.slave_exec_mode;
348+
SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr;
349+
SET @@global.slave_exec_mode= IDEMPOTENT;
350+
SET @@global.slave_run_triggers_for_rbr= ENFORCE;
351+
SELECT * FROM t1;
352+
create table t2 (id char(2) primary key, cnt int, o char(1), n char(1));
353+
insert into t2 values
354+
('u0', 0, ' ', ' '),('u1', 0, ' ', ' '),
355+
('d0', 0, ' ', ' '),('d1', 0, ' ', ' '),
356+
('i0', 0, ' ', ' '),('i1', 0, ' ', ' ');
357+
create trigger t1_cnt_b before update on t1 for each row
358+
update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u0';
359+
create trigger t1_cnt_ib before insert on t1 for each row
360+
update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i0';
361+
create trigger t1_cnt_a after update on t1 for each row
362+
update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u1';
363+
create trigger t1_cnt_da after delete on t1 for each row
364+
update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd1';
365+
create trigger t1_cnt_ia after insert on t1 for each row
366+
update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i1';
367+
SELECT * FROM t2 order by id;
368+
369+
connection master;
370+
--echo # INSERT triggers test
371+
insert into t1 values ('a','b');
372+
373+
sync_slave_with_master;
374+
375+
connection slave;
376+
SELECT * FROM t2 order by id;
377+
378+
connection master;
379+
380+
--echo # UPDATE triggers test
381+
update t1 set C1= 'd';
382+
383+
sync_slave_with_master;
384+
385+
connection slave;
386+
SELECT * FROM t2 order by id;
387+
388+
connection master;
389+
--echo # DELETE triggers test
390+
delete from t1 where C1='d';
391+
392+
sync_slave_with_master;
393+
394+
connection slave;
395+
SELECT * FROM t2 order by id;
396+
397+
--echo # INSERT triggers which cause also UPDATE test (insert duplicate row)
398+
insert into t1 values ('0','1');
399+
400+
SELECT * FROM t2 order by id;
401+
402+
connection master;
403+
404+
insert into t1 values ('0','1');
405+
406+
sync_slave_with_master;
407+
408+
connection slave;
409+
SELECT * FROM t2 order by id;
410+
411+
412+
--echo # INSERT triggers which cause also DELETE test
413+
--echo # (insert duplicate row in table referenced by foreign key)
414+
insert into t1 values ('1','1');
415+
416+
connection master;
417+
418+
CREATE TABLE t3 (C1 CHAR(1) primary key, FOREIGN KEY (C1) REFERENCES t1(C1) ) engine=innodb;
419+
420+
insert into t1 values ('1','1');
421+
422+
sync_slave_with_master;
423+
424+
connection slave;
425+
SELECT * FROM t2 order by id;
426+
427+
connection master;
428+
429+
drop table t3,t1;
430+
431+
sync_slave_with_master;
432+
433+
connection slave;
434+
SET @@global.slave_exec_mode= @old_slave_exec_mode;
435+
SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr;
436+
drop table t2;
437+
438+
--echo #
439+
--echo # enterprise 10.4 tests end
440+
--echo #
441+
326442
--source include/rpl_end.inc

mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3616,11 +3616,11 @@ COMMAND_LINE_ARGUMENT REQUIRED
36163616
VARIABLE_NAME SLAVE_RUN_TRIGGERS_FOR_RBR
36173617
VARIABLE_SCOPE GLOBAL
36183618
VARIABLE_TYPE ENUM
3619-
VARIABLE_COMMENT 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 master for the statement. LOGGING also means results of that the executed triggers work will be written to the binlog.
3619+
VARIABLE_COMMENT Modes for how triggers in row-base replication on slave side will be executed. Legal values are NO (default), YES, LOGGING and ENFORCE. 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 master for the statement. LOGGING also means results of that the executed triggers work will be written to the binlog. ENFORCE means that triggers will always be run on the slave, even if there are triggers on the master. ENFORCE implies LOGGING.
36203620
NUMERIC_MIN_VALUE NULL
36213621
NUMERIC_MAX_VALUE NULL
36223622
NUMERIC_BLOCK_SIZE NULL
3623-
ENUM_VALUE_LIST NO,YES,LOGGING
3623+
ENUM_VALUE_LIST NO,YES,LOGGING,ENFORCE
36243624
READ_ONLY NO
36253625
COMMAND_LINE_ARGUMENT REQUIRED
36263626
VARIABLE_NAME SLAVE_SKIP_ERRORS

sql/log_event.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4880,6 +4880,12 @@ class Rows_log_event : public Log_event
48804880

48814881
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
48824882
virtual uint8 get_trg_event_map()= 0;
4883+
4884+
inline bool do_invoke_trigger()
4885+
{
4886+
return (slave_run_triggers_for_rbr && !master_had_triggers) ||
4887+
slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_ENFORCE;
4888+
}
48834889
#endif
48844890

48854891
protected:

sql/log_event_server.cc

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6809,7 +6809,7 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability
68096809
m_table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
68106810
m_table->file->extra(HA_EXTRA_IGNORE_NO_KEY);
68116811
}
6812-
if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers )
6812+
if (m_table->triggers && do_invoke_trigger())
68136813
m_table->prepare_triggers_for_insert_stmt_or_event();
68146814

68156815
/* Honor next number column if present */
@@ -6989,8 +6989,7 @@ Rows_log_event::write_row(rpl_group_info *rgi,
69896989
TABLE *table= m_table; // pointer to event's table
69906990
int error;
69916991
int UNINIT_VAR(keynum);
6992-
const bool invoke_triggers=
6993-
slave_run_triggers_for_rbr && !master_had_triggers && table->triggers;
6992+
const bool invoke_triggers= (m_table->triggers && do_invoke_trigger());
69946993
auto_afree_ptr<char> key(NULL);
69956994

69966995
prepare_record(table, m_width, true);
@@ -7866,7 +7865,7 @@ Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability
78667865
*/
78677866
return 0;
78687867
}
7869-
if (slave_run_triggers_for_rbr && !master_had_triggers)
7868+
if (do_invoke_trigger())
78707869
m_table->prepare_triggers_for_delete_stmt_or_event();
78717870

78727871
return find_key();
@@ -7889,8 +7888,7 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
78897888
int error;
78907889
const char *tmp= thd->get_proc_info();
78917890
const char *message= "Delete_rows_log_event::find_row()";
7892-
const bool invoke_triggers=
7893-
slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
7891+
const bool invoke_triggers= (m_table->triggers && do_invoke_trigger());
78947892
DBUG_ASSERT(m_table != NULL);
78957893

78967894
#ifdef WSREP_PROC_INFO
@@ -8016,7 +8014,7 @@ Update_rows_log_event::do_before_row_operations(const Slave_reporting_capability
80168014
if ((err= find_key()))
80178015
return err;
80188016

8019-
if (slave_run_triggers_for_rbr && !master_had_triggers)
8017+
if (do_invoke_trigger())
80208018
m_table->prepare_triggers_for_update_stmt_or_event();
80218019

80228020
return 0;
@@ -8035,11 +8033,10 @@ Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability
80358033
return error;
80368034
}
80378035

8038-
int
8036+
int
80398037
Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
80408038
{
8041-
const bool invoke_triggers=
8042-
slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
8039+
const bool invoke_triggers= (m_table->triggers && do_invoke_trigger());
80438040
const char *tmp= thd->get_proc_info();
80448041
const char *message= "Update_rows_log_event::find_row()";
80458042
DBUG_ASSERT(m_table != NULL);

sql/sql_class.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT,
106106
SLAVE_EXEC_MODE_LAST_BIT };
107107
enum enum_slave_run_triggers_for_rbr { SLAVE_RUN_TRIGGERS_FOR_RBR_NO,
108108
SLAVE_RUN_TRIGGERS_FOR_RBR_YES,
109-
SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING};
109+
SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING,
110+
SLAVE_RUN_TRIGGERS_FOR_RBR_ENFORCE};
110111
enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY,
111112
SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY};
112113

sql/sys_vars.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3102,16 +3102,17 @@ static Sys_var_enum Slave_ddl_exec_mode(
31023102
slave_exec_mode_names, DEFAULT(SLAVE_EXEC_MODE_IDEMPOTENT));
31033103

31043104
static const char *slave_run_triggers_for_rbr_names[]=
3105-
{"NO", "YES", "LOGGING", 0};
3105+
{"NO", "YES", "LOGGING", "ENFORCE", 0};
31063106
static Sys_var_enum Slave_run_triggers_for_rbr(
31073107
"slave_run_triggers_for_rbr",
31083108
"Modes for how triggers in row-base replication on slave side will be "
3109-
"executed. Legal values are NO (default), YES and LOGGING. NO means "
3109+
"executed. Legal values are NO (default), YES, LOGGING and ENFORCE. NO means "
31103110
"that trigger for RBR will not be running on slave. YES and LOGGING "
31113111
"means that triggers will be running on slave, if there was not "
31123112
"triggers running on the master for the statement. LOGGING also means "
31133113
"results of that the executed triggers work will be written to "
3114-
"the binlog.",
3114+
"the binlog. ENFORCE means that triggers will always be run on the slave, "
3115+
"even if there are triggers on the master. ENFORCE implies LOGGING.",
31153116
GLOBAL_VAR(slave_run_triggers_for_rbr), CMD_LINE(REQUIRED_ARG),
31163117
slave_run_triggers_for_rbr_names,
31173118
DEFAULT(SLAVE_RUN_TRIGGERS_FOR_RBR_NO));

0 commit comments

Comments
 (0)