mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
BUG#53259 Unsafe statement binlogged in statement format w/MyIsam temp tables
BUG#54872 MBR: replication failure caused by using tmp table inside transaction Changed criteria to classify a statement as unsafe in order to reduce the number of spurious warnings. So a statement is classified as unsafe when there is on-going transaction at any point of the execution if: 1. The mixed statement is about to update a transactional table and a non-transactional table. 2. The mixed statement is about to update a temporary transactional table and a non-transactional table. 3. The mixed statement is about to update a transactional table and read from a non-transactional table. 4. The mixed statement is about to update a temporary transactional table and read from a non-transactional table. 5. The mixed statement is about to update a non-transactional table and read from a transactional table when the isolation level is lower than repeatable read. After updating a transactional table if: 6. The mixed statement is about to update a non-transactional table and read from a temporary transactional table. 7. The mixed statement is about to update a non-transactional table and read from a temporary transactional table. 8. The mixed statement is about to update a non-transactionala table and read from a temporary non-transactional table. 9. The mixed statement is about to update a temporary non-transactional table and update a non-transactional table. 10. The mixed statement is about to update a temporary non-transactional table and read from a non-transactional table. 11. A statement is about to update a non-transactional table and the option variables.binlog_direct_non_trans_update is OFF. The reason for this is that locks acquired may not protected a concurrent transaction of interfering in the current execution and by consequence in the result. So the patch reduced the number of spurious unsafe warnings. Besides we fixed a regression caused by BUG#51894, which makes temporary tables to go into the trx-cache if there is an on-going transaction. In MIXED mode, the patch for BUG#51894 ignores that the trx-cache may have updates to temporary non-transactional tables that must be written to the binary log while rolling back the transaction. So we fix this problem by writing the content of the trx-cache to the binary log while rolling back a transaction if a non-transactional temporary table was updated and the binary logging format is MIXED.
This commit is contained in:
68
sql/log.cc
68
sql/log.cc
@ -209,7 +209,7 @@ class binlog_cache_data
|
||||
{
|
||||
public:
|
||||
binlog_cache_data(): m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF),
|
||||
incident(FALSE)
|
||||
incident(FALSE), changes_to_non_trans_temp_table_flag(FALSE)
|
||||
{
|
||||
cache_log.end_of_file= max_binlog_cache_size;
|
||||
}
|
||||
@ -245,9 +245,20 @@ public:
|
||||
return(incident);
|
||||
}
|
||||
|
||||
void set_changes_to_non_trans_temp_table()
|
||||
{
|
||||
changes_to_non_trans_temp_table_flag= TRUE;
|
||||
}
|
||||
|
||||
bool changes_to_non_trans_temp_table()
|
||||
{
|
||||
return (changes_to_non_trans_temp_table_flag);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
truncate(0);
|
||||
changes_to_non_trans_temp_table_flag= FALSE;
|
||||
incident= FALSE;
|
||||
before_stmt_pos= MY_OFF_T_UNDEF;
|
||||
cache_log.end_of_file= max_binlog_cache_size;
|
||||
@ -304,6 +315,12 @@ private:
|
||||
*/
|
||||
bool incident;
|
||||
|
||||
/*
|
||||
This flag indicates if the cache has changes to temporary tables.
|
||||
@TODO This a temporary fix and should be removed after BUG#54562.
|
||||
*/
|
||||
bool changes_to_non_trans_temp_table_flag;
|
||||
|
||||
/*
|
||||
It truncates the cache to a certain position. This includes deleting the
|
||||
pending event.
|
||||
@ -1772,13 +1789,23 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
|
||||
/*
|
||||
We flush the cache wrapped in a beging/rollback if:
|
||||
. aborting a single or multi-statement transaction and;
|
||||
. the format is STMT and non-trans engines were updated or;
|
||||
. the OPTION_KEEP_LOG is activate.
|
||||
. the OPTION_KEEP_LOG is active or;
|
||||
. the format is STMT and a non-trans table was updated or;
|
||||
. the format is MIXED and a temporary non-trans table was
|
||||
updated or;
|
||||
. the format is MIXED, non-trans table was updated and
|
||||
aborting a single statement transaction;
|
||||
*/
|
||||
|
||||
if (ending_trans(thd, all) &&
|
||||
((thd->variables.option_bits & OPTION_KEEP_LOG) ||
|
||||
(trans_has_updated_non_trans_table(thd) &&
|
||||
thd->variables.binlog_format == BINLOG_FORMAT_STMT)))
|
||||
thd->variables.binlog_format == BINLOG_FORMAT_STMT) ||
|
||||
(cache_mngr->trx_cache.changes_to_non_trans_temp_table() &&
|
||||
thd->variables.binlog_format == BINLOG_FORMAT_MIXED) ||
|
||||
(trans_has_updated_non_trans_table(thd) &&
|
||||
ending_single_stmt_trans(thd,all) &&
|
||||
thd->variables.binlog_format == BINLOG_FORMAT_MIXED)))
|
||||
{
|
||||
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0);
|
||||
error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
|
||||
@ -1786,13 +1813,17 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
|
||||
/*
|
||||
Truncate the cache if:
|
||||
. aborting a single or multi-statement transaction or;
|
||||
. the OPTION_KEEP_LOG is not activate and;
|
||||
. the format is not STMT or no non-trans were updated.
|
||||
. the OPTION_KEEP_LOG is not active and;
|
||||
. the format is not STMT or no non-trans was updated and;
|
||||
. the format is not MIXED or no temporary non-trans was
|
||||
updated.
|
||||
*/
|
||||
else if (ending_trans(thd, all) ||
|
||||
(!(thd->variables.option_bits & OPTION_KEEP_LOG) &&
|
||||
((!stmt_has_updated_non_trans_table(thd) ||
|
||||
thd->variables.binlog_format != BINLOG_FORMAT_STMT))))
|
||||
(!stmt_has_updated_non_trans_table(thd) ||
|
||||
thd->variables.binlog_format != BINLOG_FORMAT_STMT) &&
|
||||
(!cache_mngr->trx_cache.changes_to_non_trans_temp_table() ||
|
||||
thd->variables.binlog_format != BINLOG_FORMAT_MIXED)))
|
||||
error= binlog_truncate_trx_cache(thd, cache_mngr, all);
|
||||
}
|
||||
|
||||
@ -4254,7 +4285,23 @@ bool use_trans_cache(const THD* thd, bool is_transactional)
|
||||
*/
|
||||
bool ending_trans(THD* thd, const bool all)
|
||||
{
|
||||
return (all || (!all && !thd->in_multi_stmt_transaction_mode()));
|
||||
return (all || ending_single_stmt_trans(thd, all));
|
||||
}
|
||||
|
||||
/**
|
||||
This function checks if a single statement transaction is about
|
||||
to commit or not.
|
||||
|
||||
@param thd The client thread that executed the current statement.
|
||||
@param all Committing a transaction (i.e. TRUE) or a statement
|
||||
(i.e. FALSE).
|
||||
@return
|
||||
@c true if committing a single statement transaction, otherwise
|
||||
@c false.
|
||||
*/
|
||||
bool ending_single_stmt_trans(THD* thd, const bool all)
|
||||
{
|
||||
return (!all && !thd->in_multi_stmt_transaction_mode());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4653,6 +4700,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
|
||||
file= cache_mngr->get_binlog_cache_log(is_trans_cache);
|
||||
cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);
|
||||
|
||||
if (thd->stmt_accessed_non_trans_temp_table())
|
||||
cache_data->set_changes_to_non_trans_temp_table();
|
||||
|
||||
thd->binlog_start_trans_and_stmt();
|
||||
}
|
||||
DBUG_PRINT("info",("event type: %d",event_info->get_type_code()));
|
||||
|
Reference in New Issue
Block a user