mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
MDEV-25477 Auto-create breaks replication when triggering event was not replicated
If UPDATE/DELETE does not change data it is skipped from replication. We now force replication of such events when they trigger partition auto-creation. For ROLLBACK it is as simple as set OPTION_KEEP_LOG flag. trans_cannot_safely_rollback() does the rest. For UPDATE/DELETE .. LIMIT 0 we make additional binlog_query() calls at the early points of return. As a safety measure we also convert row format into statement if it is needed. The condition is decided by binlog_need_stmt_format(). Basically if there are some row events in cache we don't need that: table open of row event will trigger auto-creation anyway. Multi-update/delete works via mysql_select(). There is no early points of return, so binlogging is always checked by send_eof()/abort_resultset(). But we must comply with the above measure of converting into statement.
This commit is contained in:
@@ -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 ||
|
||||
|
Reference in New Issue
Block a user