mirror of
https://github.com/MariaDB/server.git
synced 2026-05-09 08:34:28 +02:00
MDEV-35207 ignored error at binlogging by CREATE-TABLE-SELECT leads to assert
MDEV-35499 Errored-out CREATE-or-REPLACE-SELECT does not log DROP table into binlog
MDEV-35502 Failed at ROW-format binlogging CREATE-TABLE-SELECT should
not generate Incident event
When a CREATE TABLE .. SELECT errors while inserting data, a user
would expect that all changes are rolled back
and the table would not exist after executing the query.
However CREATE-TABLE-SELECT can face an error near the end of its execution
select_create::send_eof() so that the error was never checked which
led to various assert inside binlogging path that should not be
attended at all.
Specifically when binlog_commit() of ha_commit_one_phase() that
CREATE-TABLE-SELECT employs errored out because of a limited cache size
(binlog_commit may try writing to a transactional cache) the cache
was not flushed to binlog. The missed error check allowed further
execution down to trans_commit_implicit() in whose stack
DBUG_ASSERT(!(entry->using_trx_cache && !mngr->trx_cache.empty() &&
mngr->get_binlog_cache_log(TRUE)->error));
fired. In a non-debug build that table remains created/populated
inconsistently with binlog.
The fixes need and install the error checking in select_create::send_eof().
That prevents from any further execution when ha_commit_one_phase() fails
for any reason (typically due to binlog_commit()).
This commit also covers CREATE-or-REPLACE-SELECT that additionally had
a specific issue in that DROP TABLE was not logged the binary log, MDEV-35499.
See changes select_create::abort_result_set().
The current commit also corrects an unnecessary Incident event
logging when CREATE-TABLE-SELECT encounters a binloging issue, MDEV-35502.
The Incident was actually only harmful in this case as the table was
never going to be created, therefore replicated, in such a case.
In "normal" cases when the SELECT phase errors due to binlogging, an
internal incident flag gets reset inside select_create::abort_result_set().
A hunk in select_insert::prepare_eof() addresses a specific kind of
this issue that deals with incorrect computation of the binlog cache type.
Because of that in the OLD version execution was allowed to proceed along
ha_commit_trans()..binlog_commit() while a Pending event was not
flushed to the transactional cache. That might lead to the unnecessary
binlogged Incident despite the select_create::abort_result_set()
measures. However now with the corrected cache type any binlogging error
to flush the Pending event is covered according to the normal case.
non-transaction table, updates to the non-transactional table
NOTE the commit contains few tests overlapping with unfixed yet MDEV-36027.
Thanks to Brandon Nesterenko and Kristian Nielsen for thorough review,
and Kristian additionally for ideas to simplify the patch and some
code contribution.
This commit is contained in:
parent
58a3677309
commit
1b4efbeb8c
5 changed files with 374 additions and 7 deletions
|
|
@ -4349,7 +4349,11 @@ bool select_insert::store_values(List<Item> &values)
|
|||
bool select_insert::prepare_eof()
|
||||
{
|
||||
int error;
|
||||
bool const trans_table= table->file->has_transactions_and_rollback();
|
||||
// make sure any ROW format pending event is logged in the same binlog cache
|
||||
bool const trans_table= (thd->is_current_stmt_binlog_format_row() &&
|
||||
table->file->row_logging) ?
|
||||
table->file->row_logging_has_trans :
|
||||
table->file->has_transactions_and_rollback();
|
||||
bool changed;
|
||||
bool binary_logged= 0;
|
||||
killed_state killed_status= thd->killed;
|
||||
|
|
@ -4574,7 +4578,8 @@ void select_insert::abort_result_set()
|
|||
query_cache_invalidate3(thd, table, 1);
|
||||
}
|
||||
DBUG_ASSERT(transactional_table || !changed ||
|
||||
thd->transaction->stmt.modified_non_trans_table);
|
||||
(thd->transaction->stmt.modified_non_trans_table ||
|
||||
thd->transaction->all.modified_non_trans_table));
|
||||
|
||||
table->s->table_creation_was_logged|= binary_logged;
|
||||
table->file->ha_release_auto_increment();
|
||||
|
|
@ -5267,9 +5272,14 @@ bool select_create::send_eof()
|
|||
/* Remember xid's for the case of row based logging */
|
||||
ddl_log_update_xid(&ddl_log_state_create, thd->binlog_xid);
|
||||
ddl_log_update_xid(&ddl_log_state_rm, thd->binlog_xid);
|
||||
trans_commit_stmt(thd);
|
||||
if (!(thd->variables.option_bits & OPTION_GTID_BEGIN))
|
||||
trans_commit_implicit(thd);
|
||||
if (trans_commit_stmt(thd) ||
|
||||
(!(thd->variables.option_bits & OPTION_GTID_BEGIN) &&
|
||||
trans_commit_implicit(thd)))
|
||||
{
|
||||
abort_result_set();
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
|
||||
thd->binlog_xid= 0;
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
|
|
@ -5389,7 +5399,13 @@ void select_create::abort_result_set()
|
|||
|
||||
/* possible error of writing binary log is ignored deliberately */
|
||||
(void) thd->binlog_flush_pending_rows_event(TRUE, TRUE);
|
||||
/*
|
||||
In the error case, we remove any partially created table. So clear any
|
||||
incident event generates due to cache error, as it no longer relevant.
|
||||
*/
|
||||
binlog_clear_incident(thd);
|
||||
|
||||
bool drop_table_was_logged= false;
|
||||
if (table)
|
||||
{
|
||||
bool tmp_table= table->s->tmp_table;
|
||||
|
|
@ -5436,6 +5452,7 @@ void select_create::abort_result_set()
|
|||
create_info->db_type == partition_hton,
|
||||
&create_info->tabledef_version,
|
||||
tmp_table);
|
||||
drop_table_was_logged= true;
|
||||
debug_crash_here("ddl_log_create_after_binlog");
|
||||
thd->binlog_xid= 0;
|
||||
}
|
||||
|
|
@ -5460,8 +5477,21 @@ void select_create::abort_result_set()
|
|||
|
||||
if (create_info->table_was_deleted)
|
||||
{
|
||||
/* Unlock locked table that was dropped by CREATE. */
|
||||
(void) trans_rollback_stmt(thd);
|
||||
if (drop_table_was_logged)
|
||||
{
|
||||
/* for DROP binlogging the error status has to be canceled first */
|
||||
Diagnostics_area new_stmt_da(thd->query_id, false, true);
|
||||
Diagnostics_area *old_stmt_da= thd->get_stmt_da();
|
||||
|
||||
thd->set_stmt_da(&new_stmt_da);
|
||||
(void) trans_rollback_stmt(thd);
|
||||
thd->set_stmt_da(old_stmt_da);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unlock locked table that was dropped by CREATE. */
|
||||
(void) trans_rollback_stmt(thd);
|
||||
}
|
||||
thd->locked_tables_list.unlock_locked_table(thd, create_info->mdl_ticket);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue