diff --git a/mysql-test/suite/versioning/r/rpl.result b/mysql-test/suite/versioning/r/rpl.result index 4f0b0fc07ff..9a6c403c096 100644 --- a/mysql-test/suite/versioning/r/rpl.result +++ b/mysql-test/suite/versioning/r/rpl.result @@ -192,4 +192,196 @@ PARTITIONS 3 connection master; drop table t1; set timestamp= default; +# +# MDEV-25477 Auto-create breaks replication when triggering event was not replicated +# +set timestamp= unix_timestamp('2001-01-01 01:00:00'); +# ROLLBACK +create table t (a int) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); +set @@timestamp= @@timestamp + 3601; +start transaction; +delete from t; +rollback; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 01:00:00' AUTO +PARTITIONS 3 +connection slave; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 01:00:00' AUTO +PARTITIONS 3 +connection master; +alter table t drop partition p0; +connection slave; +# INSERT .. ODKU +connection master; +create or replace table t (a int primary key) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); +set @@timestamp= @@timestamp + 3601; +insert into t values (1) on duplicate key update a= a; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 02:00:00' AUTO +PARTITIONS 3 +connection slave; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 02:00:00' AUTO +PARTITIONS 3 +connection master; +alter table t drop partition p0; +connection slave; +# INSERT .. SELECT .. ODKU +connection master; +create or replace table t (a int primary key) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); +set @@timestamp= @@timestamp + 3601; +call mtr.add_suppression("Unsafe statement written to the binary log"); +insert t select a from t where a = 1 limit 0 on duplicate key update a= 1; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 03:00:00' AUTO +PARTITIONS 3 +connection slave; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 03:00:00' AUTO +PARTITIONS 3 +connection master; +alter table t drop partition p0; +connection slave; +# UPDATE +connection master; +create or replace table t (a int) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); +set @@timestamp= @@timestamp + 3601; +update t set a= 3 limit 0; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 04:00:00' AUTO +PARTITIONS 3 +connection slave; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 04:00:00' AUTO +PARTITIONS 3 +connection master; +alter table t drop partition p0; +connection slave; +# DELETE +connection master; +create or replace table t (a int) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); +set @@timestamp= @@timestamp + 3601; +delete from t limit 0; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 05:00:00' AUTO +PARTITIONS 3 +connection slave; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 05:00:00' AUTO +PARTITIONS 3 +connection master; +alter table t drop partition p0; +connection slave; +# Multi-update +connection master; +create or replace table t (a int) with system versioning +partition by system_time interval 1 hour auto; +create or replace table t2 (b int); +insert into t values (0), (1); +insert into t2 values (10), (20); +set @@timestamp= @@timestamp + 3601; +update t left join t2 on a > b set a= 4; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 06:00:00' AUTO +PARTITIONS 3 +connection slave; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 06:00:00' AUTO +PARTITIONS 3 +connection master; +alter table t drop partition p0; +connection slave; +# Multi-delete +connection master; +create or replace table t (a int) with system versioning +partition by system_time interval 1 hour auto; +create or replace table t2 (b int); +insert into t values (0), (1); +insert into t2 values (10), (20); +set @@timestamp= @@timestamp + 3601; +delete t, t2 from t join t2 where a > b; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 07:00:00' AUTO +PARTITIONS 3 +connection slave; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `a` int(11) DEFAULT NULL +) ENGINE=ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING + PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2001-01-01 07:00:00' AUTO +PARTITIONS 3 +connection master; +alter table t drop partition p0; +connection slave; +connection master; +drop tables t, t2; +set timestamp= default; include/rpl_end.inc diff --git a/mysql-test/suite/versioning/t/rpl.test b/mysql-test/suite/versioning/t/rpl.test index 7ce293d7eed..45ac3e62d7f 100644 --- a/mysql-test/suite/versioning/t/rpl.test +++ b/mysql-test/suite/versioning/t/rpl.test @@ -152,4 +152,148 @@ show create table t1; drop table t1; set timestamp= default; +--echo # +--echo # MDEV-25477 Auto-create breaks replication when triggering event was not replicated +--echo # + +set timestamp= unix_timestamp('2001-01-01 01:00:00'); +--echo # ROLLBACK +create table t (a int) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); +set @@timestamp= @@timestamp + 3601; + +start transaction; +delete from t; +--disable_warnings +rollback; +# Warning: Some non-transactional changed tables couldn't be rolled back +--enable_warnings + +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--sync_slave_with_master +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--connection master +alter table t drop partition p0; +--sync_slave_with_master + +--echo # INSERT .. ODKU +--connection master +create or replace table t (a int primary key) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); + +set @@timestamp= @@timestamp + 3601; +insert into t values (1) on duplicate key update a= a; +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--sync_slave_with_master +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--connection master +alter table t drop partition p0; +--sync_slave_with_master + +--echo # INSERT .. SELECT .. ODKU +--connection master +create or replace table t (a int primary key) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); + +set @@timestamp= @@timestamp + 3601; +--disable_warnings +call mtr.add_suppression("Unsafe statement written to the binary log"); +insert t select a from t where a = 1 limit 0 on duplicate key update a= 1; +--enable_warnings +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--sync_slave_with_master +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--connection master +alter table t drop partition p0; +--sync_slave_with_master + +--echo # UPDATE +--connection master +create or replace table t (a int) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); + +set @@timestamp= @@timestamp + 3601; +update t set a= 3 limit 0; +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--sync_slave_with_master +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--connection master +alter table t drop partition p0; +--sync_slave_with_master + +--echo # DELETE +--connection master +create or replace table t (a int) with system versioning +partition by system_time interval 1 hour auto; +insert into t values (1), (2); + +set @@timestamp= @@timestamp + 3601; +delete from t limit 0; +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--sync_slave_with_master +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--connection master +alter table t drop partition p0; +--sync_slave_with_master + +--echo # Multi-update +--connection master +create or replace table t (a int) with system versioning +partition by system_time interval 1 hour auto; +create or replace table t2 (b int); + +insert into t values (0), (1); +insert into t2 values (10), (20); +set @@timestamp= @@timestamp + 3601; +# Note: limit 0 is not important for multi-update/delete because they work +# via mysql_select(). OTOH limit 0 makes unwanted "unsafe" warning. +update t left join t2 on a > b set a= 4; + +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--sync_slave_with_master +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--connection master +alter table t drop partition p0; +--sync_slave_with_master + +--echo # Multi-delete +--connection master +create or replace table t (a int) with system versioning +partition by system_time interval 1 hour auto; +create or replace table t2 (b int); + +insert into t values (0), (1); +insert into t2 values (10), (20); +set @@timestamp= @@timestamp + 3601; +delete t, t2 from t join t2 where a > b; + +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--sync_slave_with_master +--replace_result InnoDB ENGINE MyISAM ENGINE MEMORY ENGINE +show create table t; +--connection master +alter table t drop partition p0; +--sync_slave_with_master + +--connection master +drop tables t, t2; +set timestamp= default; + --source include/rpl_end.inc diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 7d33f042431..5c2237fb3d2 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -921,6 +921,8 @@ bool partition_info::vers_set_hist_part(THD *thd, uint *create_count) /** @brief Run fast_alter_partition_table() to add new history partitions for tables requiring them. + + @param num_parts Number of partitions to create */ bool vers_create_partitions(THD *thd, TABLE_LIST* tl, uint num_parts) { @@ -937,6 +939,7 @@ bool vers_create_partitions(THD *thd, TABLE_LIST* tl, uint num_parts) TABLE *table= tl->table; DBUG_ASSERT(!thd->is_error()); + DBUG_ASSERT(num_parts); { DBUG_ASSERT(table->s->get_table_ref_type() == TABLE_REF_BASE_TABLE); @@ -1025,6 +1028,7 @@ bool vers_create_partitions(THD *thd, TABLE_LIST* tl, uint num_parts) // NOTE: we have to return DA_EMPTY for new command DBUG_ASSERT(thd->get_stmt_da()->is_ok()); thd->get_stmt_da()->reset_diagnostics_area(); + thd->variables.option_bits|= OPTION_BINLOG_THIS; exit: thd->work_part_info= save_part_info; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 73bfa7290e5..50371b3e722 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1674,6 +1674,7 @@ bool TABLE::vers_switch_partition(THD *thd, TABLE_LIST *table_list, { switch (thd->lex->sql_command) { + case SQLCOM_INSERT_SELECT: case SQLCOM_INSERT: if (thd->lex->duplicates != DUP_UPDATE) return false; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1d6409db25d..f902f12481e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -7327,6 +7327,26 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) } +/* + DML that doesn't change the table normally is not logged, + but it needs to be logged if it auto-created a partition as a side effect. +*/ +bool THD::binlog_for_noop_dml(bool transactional_table) +{ + if (log_current_statement()) + { + reset_unsafe_warnings(); + if (binlog_query(THD::STMT_QUERY_TYPE, query(), query_length(), + transactional_table, FALSE, FALSE, 0) > 0) + { + my_error(ER_ERROR_ON_WRITE, MYF(0), "binary log", -1); + return true; + } + } + return false; +} + + #if !defined(DBUG_OFF) && !defined(_lint) static const char * show_query_type(THD::enum_binlog_query_type qtype) diff --git a/sql/sql_class.h b/sql/sql_class.h index a2439e96564..47d4f9fee6a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2918,6 +2918,14 @@ public: int binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional); int binlog_remove_pending_rows_event(bool clear_maps, bool is_transactional); + bool binlog_need_stmt_format(bool is_transactional) const + { + return log_current_statement() && + !binlog_get_pending_rows_event(is_transactional); + } + + bool binlog_for_noop_dml(bool transactional_table); + /** Determine the binlog format of the current statement. @@ -7738,24 +7746,25 @@ public: void dbug_serve_apcs(THD *thd, int n_calls); #endif -class ScopedStatementReplication +class StatementBinlog { -public: - ScopedStatementReplication(THD *thd) : - saved_binlog_format(thd - ? thd->set_current_stmt_binlog_format_stmt() - : BINLOG_FORMAT_MIXED), - thd(thd) - {} - ~ScopedStatementReplication() - { - if (thd) - thd->restore_stmt_binlog_format(saved_binlog_format); - } - -private: const enum_binlog_format saved_binlog_format; THD *const thd; + +public: + StatementBinlog(THD *thd, bool need_stmt) : + saved_binlog_format(thd->get_current_stmt_binlog_format()), + thd(thd) + { + if (need_stmt && saved_binlog_format != BINLOG_FORMAT_STMT) + { + thd->set_current_stmt_binlog_format_stmt(); + } + } + ~StatementBinlog() + { + thd->set_current_stmt_binlog_format(saved_binlog_format); + } }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 95adf17987c..65a3a76e98b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -450,6 +450,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ has_triggers= table->triggers && table->triggers->has_delete_triggers(); + transactional_table= table->file->has_transactions_and_rollback(); if (!returning && !using_limit && const_cond_result && (!thd->is_current_stmt_binlog_format_row() && !has_triggers) @@ -508,6 +509,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (thd->lex->describe || thd->lex->analyze_stmt) goto produce_explain_and_leave; + if (thd->binlog_for_noop_dml(transactional_table)) + DBUG_RETURN(1); + my_ok(thd, 0); DBUG_RETURN(0); } @@ -538,6 +542,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if (unlikely(thd->is_error())) DBUG_RETURN(TRUE); + + if (thd->binlog_for_noop_dml(transactional_table)) + DBUG_RETURN(1); + my_ok(thd, 0); DBUG_RETURN(0); // Nothing to delete } @@ -916,14 +924,14 @@ cleanup: deltempfile=NULL; delete select; select= NULL; - transactional_table= table->file->has_transactions_and_rollback(); if (!transactional_table && deleted > 0) thd->transaction->stmt.modified_non_trans_table= thd->transaction->all.modified_non_trans_table= TRUE; /* See similar binlogging code in sql_update.cc, for comments */ - if (likely((error < 0) || thd->transaction->stmt.modified_non_trans_table)) + if (likely((error < 0) || thd->transaction->stmt.modified_non_trans_table + || thd->log_current_statement())) { if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { @@ -933,8 +941,8 @@ cleanup: else errcode= query_error_code(thd, killed_status == NOT_KILLED); - ScopedStatementReplication scoped_stmt_rpl( - table->versioned(VERS_TRX_ID) ? thd : NULL); + StatementBinlog stmt_binlog(thd, table->versioned(VERS_TRX_ID) || + thd->binlog_need_stmt_format(transactional_table)); /* [binlog]: If 'handler::delete_all_rows()' was called and the storage engine does not inject the rows itself, we replicate @@ -1438,13 +1446,15 @@ void multi_delete::abort_result_set() DBUG_VOID_RETURN; } - if (thd->transaction->stmt.modified_non_trans_table) + if (thd->transaction->stmt.modified_non_trans_table || + thd->log_current_statement()) { /* there is only side effects; to binlog with the error */ if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { + StatementBinlog stmt_binlog(thd, thd->binlog_need_stmt_format(transactional_tables)); int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* possible error of writing binary log is ignored deliberately */ (void) thd->binlog_query(THD::ROW_QUERY_TYPE, @@ -1618,7 +1628,8 @@ bool multi_delete::send_eof() query_cache_invalidate3(thd, delete_tables, 1); } if (likely((local_error == 0) || - thd->transaction->stmt.modified_non_trans_table)) + thd->transaction->stmt.modified_non_trans_table) || + thd->log_current_statement()) { if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { @@ -1628,6 +1639,7 @@ bool multi_delete::send_eof() else errcode= query_error_code(thd, killed_status == NOT_KILLED); thd->thread_specific_used= TRUE; + StatementBinlog stmt_binlog(thd, thd->binlog_need_stmt_format(transactional_tables)); if (unlikely(thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_tables, FALSE, FALSE, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 87177eac3bc..e498daca83c 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1207,6 +1207,7 @@ values_loop_end: if (error <= 0 || thd->transaction->stmt.modified_non_trans_table || + thd->log_current_statement() || was_insert_delayed) { if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) @@ -1229,8 +1230,8 @@ values_loop_end: else errcode= query_error_code(thd, thd->killed == NOT_KILLED); - ScopedStatementReplication scoped_stmt_rpl( - table->versioned(VERS_TRX_ID) ? thd : NULL); + StatementBinlog stmt_binlog(thd, table->versioned(VERS_TRX_ID) || + thd->binlog_need_stmt_format(transactional_table)); /* bug#22725: A query which per-row-loop can not be interrupted with @@ -4223,7 +4224,8 @@ bool select_insert::prepare_eof() ha_autocommit_or_rollback() is issued below. */ if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) && - (likely(!error) || thd->transaction->stmt.modified_non_trans_table)) + (likely(!error) || thd->transaction->stmt.modified_non_trans_table || + thd->log_current_statement())) { int errcode= 0; int res; @@ -4231,6 +4233,8 @@ bool select_insert::prepare_eof() thd->clear_error(); else errcode= query_error_code(thd, killed_status == NOT_KILLED); + StatementBinlog stmt_binlog(thd, !can_rollback_data() && + thd->binlog_need_stmt_format(trans_table)); res= thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), trans_table, FALSE, FALSE, errcode); @@ -4351,6 +4355,8 @@ void select_insert::abort_result_set() if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { + StatementBinlog stmt_binlog(thd, !can_rollback_data() && + thd->binlog_need_stmt_format(transactional_table)); int errcode= query_error_code(thd, thd->killed == NOT_KILLED); int res; /* error of writing binary log is ignored */ diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 843966f13c8..82ef47608b9 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -552,6 +552,7 @@ int mysql_update(THD *thd, // Don't count on usage of 'only index' when calculating which key to use table->covering_keys.clear_all(); + transactional_table= table->file->has_transactions_and_rollback(); #ifdef WITH_PARTITION_STORAGE_ENGINE if (prune_partitions(thd, table, conds)) @@ -564,6 +565,9 @@ int mysql_update(THD *thd, if (thd->is_error()) DBUG_RETURN(1); + if (thd->binlog_for_noop_dml(transactional_table)) + DBUG_RETURN(1); + my_ok(thd); // No matching records DBUG_RETURN(0); } @@ -593,6 +597,10 @@ int mysql_update(THD *thd, { DBUG_RETURN(1); // Error in where } + + if (thd->binlog_for_noop_dml(transactional_table)) + DBUG_RETURN(1); + my_ok(thd); // No matching records DBUG_RETURN(0); } @@ -957,7 +965,6 @@ update_begin: thd->count_cuted_fields= CHECK_FIELD_WARN; thd->cuted_fields=0L; - transactional_table= table->file->has_transactions_and_rollback(); thd->abort_on_warning= !ignore && thd->is_strict_mode(); if (do_direct_update) @@ -1296,7 +1303,8 @@ update_end: Sometimes we want to binlog even if we updated no rows, in case user used it to be sure master and slave are in same state. */ - if (likely(error < 0) || thd->transaction->stmt.modified_non_trans_table) + if (likely(error < 0) || thd->transaction->stmt.modified_non_trans_table || + thd->log_current_statement()) { if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { @@ -1306,9 +1314,8 @@ update_end: else errcode= query_error_code(thd, killed_status == NOT_KILLED); - ScopedStatementReplication scoped_stmt_rpl( - table->versioned(VERS_TRX_ID) ? thd : NULL); - + StatementBinlog stmt_binlog(thd, table->versioned(VERS_TRX_ID) || + thd->binlog_need_stmt_format(transactional_table)); if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_table, FALSE, FALSE, errcode) > 0) @@ -2722,7 +2729,8 @@ void multi_update::abort_result_set() (void) do_updates(); } } - if (thd->transaction->stmt.modified_non_trans_table) + if (thd->transaction->stmt.modified_non_trans_table || + thd->log_current_statement()) { /* The query has to binlog because there's a modified non-transactional table @@ -2730,6 +2738,7 @@ void multi_update::abort_result_set() */ if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { + StatementBinlog stmt_binlog(thd, thd->binlog_need_stmt_format(transactional_tables)); /* THD::killed status might not have been set ON at time of an error got caught and if happens later the killed error is written @@ -3058,7 +3067,8 @@ bool multi_update::send_eof() (thd->transaction->stmt.m_unsafe_rollback_flags & THD_TRANS::DID_WAIT); if (likely(local_error == 0 || - thd->transaction->stmt.modified_non_trans_table)) + thd->transaction->stmt.modified_non_trans_table) || + thd->log_current_statement()) { if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { @@ -3068,25 +3078,21 @@ bool multi_update::send_eof() else errcode= query_error_code(thd, killed_status == NOT_KILLED); - bool force_stmt= false; - for (TABLE *table= all_tables->table; table; table= table->next) - { - if (table->versioned(VERS_TRX_ID)) + bool force_stmt= thd->binlog_need_stmt_format(transactional_tables); + if (!force_stmt) + for (TABLE *table= all_tables->table; table; table= table->next) { - force_stmt= true; - break; + if (table->versioned(VERS_TRX_ID)) + { + force_stmt= true; + break; + } } - } - enum_binlog_format save_binlog_format; - save_binlog_format= thd->get_current_stmt_binlog_format(); - if (force_stmt) - thd->set_current_stmt_binlog_format_stmt(); - + StatementBinlog stmt_binlog(thd, force_stmt); if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_tables, FALSE, FALSE, errcode) > 0) local_error= 1; // Rollback update - thd->set_current_stmt_binlog_format(save_binlog_format); } } DBUG_ASSERT(trans_safe || !updated ||