mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
BUG#16290902 DROP TEMP TABLE IF EXISTS CAN CAUSE POINT
IN TIME RECOVERY FAILURE ON SLAVES Problem: DROP TEMP TABLE IF EXISTS commands can cause point in time recovery (re-applying binlog) failures. Analyses: In RBR, 'DROP TEMPORARY TABLE' commands are always binlogged by adding 'IF EXISTS' clauses. Also, the slave SQL thread will not check replicate.* filter rules for "DROP TEMPORARY TABLE IF EXISTS" queries. If log-slave-updates is enabled on slave, these queries will be binlogged in the format of "USE `db`; DROP TEMPORARY TABLE IF EXISTS `t1`;" irrespective of filtering rules and irrespective of the `db` existence. When users try to recover slave from it's own binlog, use `db` command might fail if `db` is not present on slave. Fix: At the time of writing the 'DROP TEMPORARY TABLE IF EXISTS' query into the binlog, 'use `db`' will not be present and the table name in the query will be a fully qualified table name. Eg: 'USE `db`; DROP TEMPORARY TABLE IF EXISTS `t1`;' will be logged as 'DROP TEMPORARY TABLE IF EXISTS `db`.`t1`;'.
This commit is contained in:
@ -2001,6 +2001,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
bool non_tmp_error= 0;
|
||||
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
|
||||
bool non_tmp_table_deleted= 0;
|
||||
bool is_drop_tmp_if_exists_added= 0;
|
||||
String built_query;
|
||||
String built_trans_tmp_query, built_non_trans_tmp_query;
|
||||
DBUG_ENTER("mysql_rm_table_no_locks");
|
||||
@ -2029,6 +2030,15 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
table stems from the fact that such drop does not commit an ongoing
|
||||
transaction and changes to non-transactional tables must be written
|
||||
ahead of the transaction in some circumstances.
|
||||
|
||||
6- Slave SQL thread ignores all replicate-* filter rules
|
||||
for temporary tables with 'IF EXISTS' clause. (See sql/sql_parse.cc:
|
||||
mysql_execute_command() for details). These commands will be binlogged
|
||||
as they are, even if the default database (from USE `db`) is not present
|
||||
on the Slave. This can cause point in time recovery failures later
|
||||
when user uses the slave's binlog to re-apply. Hence at the time of binary
|
||||
logging, these commands will be written with fully qualified table names
|
||||
and use `db` will be suppressed.
|
||||
*/
|
||||
if (!dont_log_query)
|
||||
{
|
||||
@ -2043,6 +2053,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
|
||||
if (thd->is_current_stmt_binlog_format_row() || if_exists)
|
||||
{
|
||||
is_drop_tmp_if_exists_added= true;
|
||||
built_trans_tmp_query.set_charset(system_charset_info);
|
||||
built_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
|
||||
built_non_trans_tmp_query.set_charset(system_charset_info);
|
||||
@ -2120,10 +2131,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
String *built_ptr_query=
|
||||
(is_trans ? &built_trans_tmp_query : &built_non_trans_tmp_query);
|
||||
/*
|
||||
Don't write the database name if it is the current one (or if
|
||||
thd->db is NULL).
|
||||
Write the database name if it is not the current one or if
|
||||
thd->db is NULL or 'IF EXISTS' clause is present in 'DROP TEMPORARY'
|
||||
query.
|
||||
*/
|
||||
if (thd->db == NULL || strcmp(db,thd->db) != 0)
|
||||
if (thd->db == NULL || strcmp(db,thd->db) != 0
|
||||
|| is_drop_tmp_if_exists_added )
|
||||
{
|
||||
append_identifier(thd, built_ptr_query, db, db_len);
|
||||
built_ptr_query->append(".");
|
||||
@ -2317,7 +2330,9 @@ err:
|
||||
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
||||
built_non_trans_tmp_query.ptr(),
|
||||
built_non_trans_tmp_query.length(),
|
||||
FALSE, FALSE, FALSE, 0);
|
||||
FALSE, FALSE,
|
||||
is_drop_tmp_if_exists_added,
|
||||
0);
|
||||
}
|
||||
if (trans_tmp_table_deleted)
|
||||
{
|
||||
@ -2327,7 +2342,9 @@ err:
|
||||
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
||||
built_trans_tmp_query.ptr(),
|
||||
built_trans_tmp_query.length(),
|
||||
TRUE, FALSE, FALSE, 0);
|
||||
TRUE, FALSE,
|
||||
is_drop_tmp_if_exists_added,
|
||||
0);
|
||||
}
|
||||
if (non_tmp_table_deleted)
|
||||
{
|
||||
|
Reference in New Issue
Block a user