diff --git a/mysql-test/r/mysqld--help-notwin-profiling.result b/mysql-test/r/mysqld--help-notwin-profiling.result index 3961ee834753..d0a14d031b35 100644 --- a/mysql-test/r/mysqld--help-notwin-profiling.result +++ b/mysql-test/r/mysqld--help-notwin-profiling.result @@ -1084,6 +1084,11 @@ The following options may be given as the first argument: --sporadic-binlog-dump-fail Option used by mysql-test for debugging and testing of replication. + --sql-log-bin-triggers + The row changes generated by execution of triggers are + not logged inbinlog if this option is FALSE. Default is + TRUE. + (Defaults to on; use --skip-sql-log-bin-triggers to disable.) --sql-mode=name Syntax: sql-mode=mode[,mode[,mode...]]. See the manual for the complete list of valid sql modes --stored-program-cache=# @@ -1482,6 +1487,7 @@ slow-query-log FALSE socket-umask 0 sort-buffer-size 262144 sporadic-binlog-dump-fail FALSE +sql-log-bin-triggers TRUE sql-mode NO_ENGINE_SUBSTITUTION stored-program-cache 256 super-read-only FALSE diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index 7b50bbe87353..79eee6985033 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -1082,6 +1082,11 @@ The following options may be given as the first argument: --sporadic-binlog-dump-fail Option used by mysql-test for debugging and testing of replication. + --sql-log-bin-triggers + The row changes generated by execution of triggers are + not logged inbinlog if this option is FALSE. Default is + TRUE. + (Defaults to on; use --skip-sql-log-bin-triggers to disable.) --sql-mode=name Syntax: sql-mode=mode[,mode[,mode...]]. See the manual for the complete list of valid sql modes --stored-program-cache=# @@ -1478,6 +1483,7 @@ slow-query-log FALSE socket-umask 0 sort-buffer-size 262144 sporadic-binlog-dump-fail FALSE +sql-log-bin-triggers TRUE sql-mode NO_ENGINE_SUBSTITUTION stored-program-cache 256 super-read-only FALSE diff --git a/mysql-test/suite/rpl/r/rpl_sql_log_bin_triggers.result b/mysql-test/suite/rpl/r/rpl_sql_log_bin_triggers.result new file mode 100644 index 000000000000..7d5b9d0d0668 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_sql_log_bin_triggers.result @@ -0,0 +1,45 @@ +include/master-slave.inc +Warnings: +Note #### Sending passwords in plain text without SSL/TLS is extremely insecure. +Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information. +[connection master] +set @@session.sql_log_bin_triggers = OFF; +create table t1 (c1 char(1) primary key, c2 char(1)); +set @@session.sql_log_bin=0; +create table t2 (id char(2) primary key, cnt int, o char(1), n char(1)); +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'; +insert into t2 values +('u0', 0, ' ', ' '),('u1', 0, ' ', ' '), +('d0', 0, ' ', ' '),('d1', 0, ' ', ' '), +('i0', 0, ' ', ' '),('i1', 0, ' ', ' '); +set @@session.sql_log_bin=1; +# INSERT triggers test +insert into t1 values ('a','b'); +select * from t1; +c1 c2 +a b +# UPDATE triggers test +update t1 set C1= 'd'; +select * from t1; +c1 c2 +d b +# DELETE triggers test +delete from t1 where C1='d'; +select * from t1; +c1 c2 +set @@session.sql_log_bin=0; +drop table t2; +set @@session.sql_log_bin=1; +drop table t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_sql_log_bin_triggers.test b/mysql-test/suite/rpl/t/rpl_sql_log_bin_triggers.test new file mode 100644 index 000000000000..61159228fc4a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sql_log_bin_triggers.test @@ -0,0 +1,61 @@ +# This test verifies the functionality of sql_log_bin_triggers configuration +# option using the following steps: +# 1. Create master side triggers and table, don't propogate them to slave by turning off sql_log_bin +# 2. Execute SQL statements on master which run the triggers +# 3. Sync slave with master and verify slave is not broken + +source include/master-slave.inc; +source include/have_binlog_format_row.inc; + +connection master; +set @@session.sql_log_bin_triggers = OFF; + +create table t1 (c1 char(1) primary key, c2 char(1)); +set @@session.sql_log_bin=0; +create table t2 (id char(2) primary key, cnt int, o char(1), n char(1)); +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'; +insert into t2 values + ('u0', 0, ' ', ' '),('u1', 0, ' ', ' '), + ('d0', 0, ' ', ' '),('d1', 0, ' ', ' '), + ('i0', 0, ' ', ' '),('i1', 0, ' ', ' '); + +set @@session.sql_log_bin=1; +sync_slave_with_master; + +connection master; +--echo # INSERT triggers test +insert into t1 values ('a','b'); +sync_slave_with_master; +select * from t1; + +connection master; +--echo # UPDATE triggers test +update t1 set C1= 'd'; +sync_slave_with_master; +select * from t1; + +connection master; +--echo # DELETE triggers test +delete from t1 where C1='d'; +sync_slave_with_master; +select * from t1; + +connection master; +set @@session.sql_log_bin=0; +drop table t2; +set @@session.sql_log_bin=1; + +drop table t1; + +source include/rpl_end.inc; diff --git a/mysql-test/suite/sys_vars/r/sql_log_bin_triggers_basic.result b/mysql-test/suite/sys_vars/r/sql_log_bin_triggers_basic.result new file mode 100644 index 000000000000..a529f74f120c --- /dev/null +++ b/mysql-test/suite/sys_vars/r/sql_log_bin_triggers_basic.result @@ -0,0 +1,66 @@ +SET @start_sql_log_bin_triggers = @@global.sql_log_bin_triggers; +SELECT @start_sql_log_bin_triggers; +@start_sql_log_bin_triggers +1 +SET @@global.sql_log_bin_triggers = false; +SET @@global.sql_log_bin_triggers = DEFAULT; +SELECT @@global.sql_log_bin_triggers; +@@global.sql_log_bin_triggers +1 +SET @@global.sql_log_bin_triggers = @start_sql_log_bin_triggers; +SELECT @@global.sql_log_bin_triggers = true; +@@global.sql_log_bin_triggers = true +1 +SET @@global.sql_log_bin_triggers = false; +SELECT @@global.sql_log_bin_triggers; +@@global.sql_log_bin_triggers +0 +SET @@global.sql_log_bin_triggers = true; +SELECT @@global.sql_log_bin_triggers; +@@global.sql_log_bin_triggers +1 +SET @@global.sql_log_bin_triggers = 1; +SELECT @@global.sql_log_bin_triggers; +@@global.sql_log_bin_triggers +1 +SET @@global.sql_log_bin_triggers = 0; +SELECT @@global.sql_log_bin_triggers; +@@global.sql_log_bin_triggers +0 +SET @@global.sql_log_bin_triggers = -1; +ERROR 42000: Variable 'sql_log_bin_triggers' can't be set to the value of '-1' +SELECT @@global.sql_log_bin_triggers; +@@global.sql_log_bin_triggers +0 +SET @@global.sql_log_bin_triggers = 100; +ERROR 42000: Variable 'sql_log_bin_triggers' can't be set to the value of '100' +SELECT @@global.sql_log_bin_triggers; +@@global.sql_log_bin_triggers +0 +SET @@global.sql_log_bin_triggers = 1000.01; +ERROR 42000: Incorrect argument type to variable 'sql_log_bin_triggers' +SELECT @@global.sql_log_bin_triggers; +@@global.sql_log_bin_triggers +0 +SET @@session.sql_log_bin_triggers = FALSE; +SELECT @@session.sql_log_bin_triggers; +@@session.sql_log_bin_triggers +0 +SELECT @@global.sql_log_bin_triggers = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='sql_log_bin_triggers'; +@@global.sql_log_bin_triggers = VARIABLE_VALUE +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'OFF' +SELECT @@sql_log_bin_triggers = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.SESSION_VARIABLES +WHERE VARIABLE_NAME='sql_log_bin_triggers'; +@@sql_log_bin_triggers = VARIABLE_VALUE +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'OFF' +SET @@global.sql_log_bin_triggers = @start_sql_log_bin_triggers; +SELECT @@global.sql_log_bin_triggers; +@@global.sql_log_bin_triggers +1 diff --git a/mysql-test/suite/sys_vars/t/sql_log_bin_triggers_basic.test b/mysql-test/suite/sys_vars/t/sql_log_bin_triggers_basic.test new file mode 100644 index 000000000000..8e55faf75553 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/sql_log_bin_triggers_basic.test @@ -0,0 +1,46 @@ +source include/load_sysvars.inc; + +SET @start_sql_log_bin_triggers = @@global.sql_log_bin_triggers; +SELECT @start_sql_log_bin_triggers; + +SET @@global.sql_log_bin_triggers = false; +SET @@global.sql_log_bin_triggers = DEFAULT; +SELECT @@global.sql_log_bin_triggers; + +SET @@global.sql_log_bin_triggers = @start_sql_log_bin_triggers; +SELECT @@global.sql_log_bin_triggers = true; + +SET @@global.sql_log_bin_triggers = false; +SELECT @@global.sql_log_bin_triggers; +SET @@global.sql_log_bin_triggers = true; +SELECT @@global.sql_log_bin_triggers; + +SET @@global.sql_log_bin_triggers = 1; +SELECT @@global.sql_log_bin_triggers; +SET @@global.sql_log_bin_triggers = 0; +SELECT @@global.sql_log_bin_triggers; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.sql_log_bin_triggers = -1; +SELECT @@global.sql_log_bin_triggers; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.sql_log_bin_triggers = 100; +SELECT @@global.sql_log_bin_triggers; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.sql_log_bin_triggers = 1000.01; +SELECT @@global.sql_log_bin_triggers; + +SET @@session.sql_log_bin_triggers = FALSE; +SELECT @@session.sql_log_bin_triggers; + +SELECT @@global.sql_log_bin_triggers = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='sql_log_bin_triggers'; + +SELECT @@sql_log_bin_triggers = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.SESSION_VARIABLES +WHERE VARIABLE_NAME='sql_log_bin_triggers'; + + +SET @@global.sql_log_bin_triggers = @start_sql_log_bin_triggers; +SELECT @@global.sql_log_bin_triggers; diff --git a/sql/handler.cc b/sql/handler.cc index 91a8a3cbb434..faeb1c710339 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7310,6 +7310,8 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) - The binary log is open - The database the table resides in shall be binlogged (binlog_*_db rules) - table is not mysql.event + - This is not a table opened when executing triggers or sql_log_bin_triggers + is TRUE. */ static bool check_table_binlog_row_based(THD *thd, TABLE *table) @@ -7328,7 +7330,8 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table) return (thd->is_current_stmt_binlog_format_row() && table->s->cached_row_logging_check && (thd->variables.option_bits & OPTION_BIN_LOG) && - mysql_bin_log.is_open()); + mysql_bin_log.is_open() && + !table->pos_in_table_list->disable_sql_log_bin_triggers); } diff --git a/sql/log_event.cc b/sql/log_event.cc index 220980f2aec2..be21d12d0071 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -12386,7 +12386,9 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, (tbl->s->db.str[tbl->s->db.length] == 0)); DBUG_ASSERT(tbl->s->table_name.str[tbl->s->table_name.length] == 0); - if (tbl->triggers) + // Trigger changes are not logged if sql_log_bin_triggers is FALSE. + // In this case, slaves should execute triggers while applying row events. + if (tbl->triggers && thd->variables.sql_log_bin_triggers) m_flags |= TM_BIT_HAS_TRIGGERS_F; m_data_size= TABLE_MAP_HEADER_LEN; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b0dea7b90b75..18f767f49277 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1939,7 +1939,8 @@ bool sp_head::add_used_tables_to_table_list(THD *thd, table->lock_type >= TL_WRITE_ALLOW_WRITE ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION); - + table->disable_sql_log_bin_triggers = + !thd->variables.sql_log_bin_triggers; /* Everyting else should be zeroed */ **query_tables_last_ptr= table; diff --git a/sql/sp_instr.cc b/sql/sp_instr.cc index 45e99329ef22..3606ab48945d 100644 --- a/sql/sp_instr.cc +++ b/sql/sp_instr.cc @@ -327,6 +327,20 @@ bool sp_lex_instr::reset_lex_and_exec_core(THD *thd, reinit_stmt_before_use(thd, m_lex); + /* + Set disable_sql_log_bin_triggers flag for query_tables if binlog is + truned OFF for trigger statements. This is necessary to avoid writing down + Table_map_log_events. + */ + if (!thd->variables.sql_log_bin_triggers) + { + for (TABLE_LIST *tables = m_lex->query_tables; tables; + tables=tables->next_global) + { + tables->disable_sql_log_bin_triggers = TRUE; + } + } + /* Open tables if needed. */ if (open_tables) diff --git a/sql/sql_class.h b/sql/sql_class.h index ed4f41ab4997..dd6a2351a963 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -596,6 +596,7 @@ typedef struct system_variables my_bool expand_fast_index_creation; my_bool use_fbson_output_format; + my_bool sql_log_bin_triggers; } SV; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index a5ff450425bd..20361dd06b4c 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -2173,6 +2173,14 @@ bool Table_triggers_list::process_triggers(THD *thd, thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); + my_bool disable_binlog = !thd->variables.sql_log_bin_triggers; + if (disable_binlog) + { + // option_bits restored back using statement_state in + // restore_sub_statement_state(). + thd->variables.option_bits &= ~OPTION_BIN_LOG; + } + /* Reset current_select before call execute_trigger() and restore it after return from one. This way error is set diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5fbdccf446dc..3c4ba93bcbaf 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2967,6 +2967,12 @@ static Sys_var_enum Slave_run_triggers_for_rbr( slave_run_triggers_for_rbr_names, DEFAULT(SLAVE_RUN_TRIGGERS_FOR_RBR_NO)); +static Sys_var_mybool sql_log_bin_triggers( + "sql_log_bin_triggers", + "The row changes generated by execution of triggers are not logged in" + "binlog if this option is FALSE. Default is TRUE.", + SESSION_VAR(sql_log_bin_triggers), CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + const char *slave_type_conversions_name[]= {"ALL_LOSSY", "ALL_NON_LOSSY", "ALL_UNSIGNED", "ALL_SIGNED", 0}; static Sys_var_set Slave_type_conversions( diff --git a/sql/table.h b/sql/table.h index 82f605d7b618..ae682165a337 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2085,6 +2085,8 @@ struct TABLE_LIST enum enum_table_ref_type m_table_ref_type; /** See comments for TABLE_SHARE::get_table_ref_version() */ ulonglong m_table_ref_version; +public: + my_bool disable_sql_log_bin_triggers; };