1
0
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:
Alfranio Correia
2010-06-30 16:25:13 +01:00
parent 759aabe371
commit e662b51eef
23 changed files with 625 additions and 1282 deletions

View File

@ -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()));