mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and problems with extra warnings. Problem 1: The sub-statement where an unsafe warning was detected was printed as part of the warning. This was ok for statements that were unsafe due to, e.g., calls to UUID(), but did not make sense for statements that were unsafe because there was more than one autoincrement column (unsafeness in this case comes from the combination of several sub-statements). Fix 1: Instead of printing the sub-statement, print an explanation of why the statement is unsafe. Problem 2: When a recursive construct (i.e., stored proceure, stored function, trigger, view, prepared statement) contained several sub-statements, and at least one of them was unsafe, there would be one unsafeness warning per sub-statement - even for safe sub-statements. Fix 2: Ensure that each type of warning is printed at most once, by remembering throughout the execution of the statement which types of warnings have been printed. mysql-test/extra/rpl_tests/create_recursive_construct.inc: - Clarified comment per review request. - Added checks for the number of warnings in each invocation. mysql-test/extra/rpl_tests/rpl_insert_delayed.test: Per review request, replaced @@session.binlog_format by @@global.binlog_format, since INSERT DELAYED reads the global variable. (In this test case, the two variables have the same value, so the change is cosmetic.) mysql-test/r/sp_trans.result: updated result file mysql-test/suite/binlog/r/binlog_statement_insert_delayed.result: updated result file mysql-test/suite/binlog/r/binlog_stm_ps.result: updated result file mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result: updated result file mysql-test/suite/binlog/r/binlog_unsafe.result: Updated result file. Note that duplicate warnings are now gone. mysql-test/suite/binlog/t/binlog_unsafe.test: - Added tests for: (1) a statement that is unsafe in many ways; (2) a statement that is unsafe in the same way several times. - Use -- style to invoke mysqltest commands. mysql-test/suite/rpl/r/rpl_stm_found_rows.result: updated result file mysql-test/suite/rpl/r/rpl_stm_loadfile.result: updated result file mysql-test/suite/rpl/t/rpl_mix_found_rows.test: Per review request, added comment explaining what the test case does (copied from rpl_stm_found_rows.test) mysql-test/suite/rpl/t/rpl_stm_found_rows.test: Clarified grammar in comment. mysql-test/suite/rpl_ndb/r/rpl_ndb_binlog_format_errors.result: Updated result file. sql/item_create.cc: Made set_stmt_unsafe take one parameter, describing the type of unsafeness. sql/sp_head.cc: Added unsafe_flags field and made it hold all the unsafe flags. sql/sp_head.h: - Removed the BINLOG_ROW_BASED_IF_MIXED flag from m_flags. Instead, we use the new unsafe_flags field to hold the unsafeness state of the sp. - Made propagate_attributes() copy all unsafe flags. sql/sql_base.cc: - Made LEX::set_stmt_unsafe() take an extra argument. - Made binlog_unsafe_warning_flags store the type of unsafeness. - Per review requests, clarified comments - Added DBUG printouts sql/sql_class.cc: - Made warnings be generated in issue_warnings() and call that from binlog_query(). Wrote issue_warnings(), which prints zero or more warnings, avoiding to print warnings more than once per statement. - Per review request, added @todo so that we remember to assert correct behavior in binlog_query. sql/sql_class.h: - Removed BINLOG_WARNING_PRINTED - Use [set|clear]_current_stmt_binlog_row_based() instead of modifying the flag directly. - added issue_unsafe_warnings() (only called from binlog_unsafe) - Per review request, improved some documentation. sql/sql_insert.cc: Added extra argument to LEX::set_stmt_unsafe() sql/sql_lex.h: - Added enum_binlog_stmt_unsafe, listing all types of unsafe statements. - Per review requests, improved many comments for member functions. - Added [get|set]_stmt_unsafe_flags(), which return/set all the unsafe flags for a statement. sql/sql_parse.cc: - Renamed binlog_warning_flags to binlog_unsafe_warning_flags. - Per review requests, improved comment. sql/sql_view.cc: Made views propagate all the new unsafe flags. sql/sql_yacc.yy: Added parameter to set_stmt_unsafe(). storage/innobase/handler/ha_innodb.cc: Per review requests, replaced DBUG_EXECUTE_IF() by DBUG_EVALUATE_IF().
This commit is contained in:
100
sql/sql_class.h
100
sql/sql_class.h
@ -1422,38 +1422,79 @@ public:
|
||||
int binlog_flush_pending_rows_event(bool stmt_end);
|
||||
int binlog_remove_pending_rows_event(bool clear_maps);
|
||||
|
||||
int is_current_stmt_binlog_format_row() {
|
||||
/**
|
||||
Determine the binlog format of the current statement.
|
||||
|
||||
@retval 0 if the current statement will be logged in statement
|
||||
format.
|
||||
@retval nonzero if the current statement will be logged in row
|
||||
format.
|
||||
*/
|
||||
int is_current_stmt_binlog_format_row() const {
|
||||
DBUG_ASSERT(current_stmt_binlog_format == BINLOG_FORMAT_STMT ||
|
||||
current_stmt_binlog_format == BINLOG_FORMAT_ROW);
|
||||
return current_stmt_binlog_format == BINLOG_FORMAT_ROW;
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
Tells if current statement should binlog row-based(1) or stmt-based(0)
|
||||
/**
|
||||
Indicates the format in which the current statement will be
|
||||
logged. This can only be set from @c decide_logging_format().
|
||||
*/
|
||||
enum_binlog_format current_stmt_binlog_format;
|
||||
|
||||
enum enum_binlog_warning_flag {
|
||||
/* ER_BINLOG_UNSAFE_AND_STMT_ENGINE affects current stmt */
|
||||
BINLOG_WARNING_FLAG_UNSAFE_AND_STMT_ENGINE = 0,
|
||||
/* ER_BINLOG_UNSAFE_AND_STMT_MODE affects current stmt */
|
||||
BINLOG_WARNING_FLAG_UNSAFE_AND_STMT_MODE,
|
||||
/* One of the warnings has already been printed */
|
||||
BINLOG_WARNING_FLAG_PRINTED,
|
||||
/* number of elements of this enum; insert new members above */
|
||||
BINLOG_WARNING_FLAG_COUNT
|
||||
};
|
||||
/**
|
||||
Flags holding the status of binlog-related warnings for the
|
||||
current statement. This is a binary combination of (1<<flag),
|
||||
where flag is a member of @c enum_binlog_warning_flag.
|
||||
|
||||
The warnings are determined in @c THD::decide_logging_format, but
|
||||
issued only later, after the statement has been written to the
|
||||
binlog. Hence it must be stored in the @c THD object.
|
||||
Enumeration listing binlog-related warnings that a statement can
|
||||
cause.
|
||||
*/
|
||||
uint32 binlog_warning_flags;
|
||||
enum enum_binlog_stmt_warning {
|
||||
|
||||
/* ER_BINLOG_UNSAFE_AND_STMT_ENGINE affects current stmt */
|
||||
BINLOG_STMT_WARNING_UNSAFE_AND_STMT_ENGINE= 0,
|
||||
|
||||
/* ER_BINLOG_UNSAFE_STATEMENT affects current stmt */
|
||||
BINLOG_STMT_WARNING_UNSAFE_AND_STMT_MODE,
|
||||
|
||||
/** The last element of this enumeration type. */
|
||||
BINLOG_STMT_WARNING_COUNT
|
||||
};
|
||||
|
||||
/**
|
||||
Bit field for the state of binlog warnings.
|
||||
|
||||
There are three groups of bits:
|
||||
|
||||
- The low BINLOG_STMT_WARNING_COUNT bits indicate the type of
|
||||
warning that the current (top-level) statement will issue. At
|
||||
most one of these bits should be set (this is ensured by the
|
||||
logic in decide_logging_format).
|
||||
|
||||
- The following Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types
|
||||
of unsafeness that the current statement has.
|
||||
|
||||
- The following Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types
|
||||
of unsafeness that the current statement has issued warnings
|
||||
for.
|
||||
|
||||
Hence, this variable must be big enough to hold
|
||||
BINLOG_STMT_WARNING_COUNT + 2 * Lex::BINLOG_STMT_UNSAFE_COUNT
|
||||
bits. This is asserted in @c issue_unsafe_warnings().
|
||||
|
||||
The first and second groups of bits are set by @c
|
||||
decide_logging_format() when it detects that a warning should be
|
||||
issued. The third group of bits is set from @c binlog_query()
|
||||
when a warning is issued. All bits are cleared at the end of the
|
||||
top-level statement.
|
||||
|
||||
This must be a member of THD and not of LEX, because warnings are
|
||||
detected and issued in different places (@c
|
||||
decide_logging_format() and @c binlog_query(), respectively).
|
||||
Between these calls, the THD->lex object may change; e.g., if a
|
||||
stored routine is invoked. Only THD persists between the calls.
|
||||
*/
|
||||
uint32 binlog_unsafe_warning_flags;
|
||||
|
||||
void issue_unsafe_warnings();
|
||||
|
||||
/*
|
||||
Number of outstanding table maps, i.e., table maps in the
|
||||
@ -2138,6 +2179,14 @@ public:
|
||||
inline void set_current_stmt_binlog_row_based_if_mixed()
|
||||
{
|
||||
DBUG_ENTER("set_current_stmt_binlog_row_based_if_mixed");
|
||||
/*
|
||||
This should only be called from decide_logging_format.
|
||||
|
||||
@todo Once we have ensured this, uncomment the following
|
||||
statement, remove the big comment below that, and remove the
|
||||
in_sub_stmt==0 condition from the following 'if'.
|
||||
*/
|
||||
/* DBUG_ASSERT(in_sub_stmt == 0); */
|
||||
/*
|
||||
If in a stored/function trigger, the caller should already have done the
|
||||
change. We test in_sub_stmt to prevent introducing bugs where people
|
||||
@ -2149,7 +2198,7 @@ public:
|
||||
*/
|
||||
if ((variables.binlog_format == BINLOG_FORMAT_MIXED) &&
|
||||
(in_sub_stmt == 0))
|
||||
current_stmt_binlog_format= BINLOG_FORMAT_ROW;
|
||||
set_current_stmt_binlog_row_based();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -2189,9 +2238,10 @@ public:
|
||||
show_system_thread(system_thread)));
|
||||
if ((temporary_tables == NULL) && (in_sub_stmt == 0))
|
||||
{
|
||||
current_stmt_binlog_format=
|
||||
(variables.binlog_format == BINLOG_FORMAT_ROW) ?
|
||||
BINLOG_FORMAT_ROW : BINLOG_FORMAT_STMT;
|
||||
if (variables.binlog_format == BINLOG_FORMAT_ROW)
|
||||
set_current_stmt_binlog_row_based();
|
||||
else
|
||||
clear_current_stmt_binlog_row_based();
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
Reference in New Issue
Block a user