Commit 1feee134 authored by Alfranio Correia's avatar Alfranio Correia

BUG#55625 RBR breaks on failing 'CREATE TABLE'

A CREATE...SELECT that fails is written to the binary log if a non-transactional
statement is updated. If the logging format is ROW, the CREATE statement and the
changes are written to the binary log as distinct events and by consequence the
created table is not rolled back in the slave.

In this patch, we opted to let the slave goes out of sync by not writting to the
binary log the CREATE statement. We do this by simply reseting the binary log's
cache.
parent 2aee4d8d
......@@ -8,3 +8,27 @@ drop table if exists t1, t2;
create table t1 (a int);
drop table t1, t2;
ERROR 42S02: Unknown table 't2'
include/stop_slave.inc
SET @old_binlog_format= @@global.binlog_format;
SET GLOBAL binlog_format = ROW;
include/start_slave.inc
SET @old_binlog_format= @@global.binlog_format;
SET binlog_format = ROW;
CREATE TABLE t2(a INT) ENGINE=MYISAM;
CREATE TABLE t3(a INT) ENGINE=INNODB;
CREATE FUNCTION f1() RETURNS INT
BEGIN
insert into t2 values(1);
insert into t3 values(1);
return 1;
END|
CREATE TABLE t1(UNIQUE(a)) ENGINE=MYISAM SELECT 1 AS a UNION ALL SELECT f1();
ERROR 23000: Duplicate entry '1' for key 'a'
CREATE TABLE t1(UNIQUE(a)) ENGINE=INNODB SELECT 1 AS a UNION ALL SELECT f1();
ERROR 23000: Duplicate entry '1' for key 'a'
show binlog events in 'master-bin.000001' from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
DROP FUNCTION f1;
DROP TABLE t2, t3;
SET @@global.binlog_format= @old_binlog_format;
SET @@global.binlog_format= @old_binlog_format;
# Testcase for BUG#4552 (DROP on two tables, one of which does not
# exist, must be binlogged with a non-zero error code)
source include/master-slave.inc;
source include/have_innodb.inc;
--disable_warnings
drop table if exists t1, t2;
--enable_warnings
......@@ -10,7 +11,57 @@ drop table t1, t2;
save_master_pos;
connection slave;
sync_with_master;
# End of 4.1 tests
# BUG#55625 RBR breaks on failing 'CREATE TABLE'
# A CREATE...SELECT that fails is written to the binary log if a non-transactional
# statement is updated. If the logging format is ROW, the CREATE statement and the
# changes are written to the binary log as distinct events and by consequence the
# created table is not rolled back in the slave.
# To fix the problem, we do not write a CREATE...SELECT that fails to the binary
# log. Howerver, the changes to non-transactional tables are not replicated and
# thus the slave goes out of sync. This should be fixed after BUG#47899.
#
# In the test case, we verify if the binary log contains no information for a
# CREATE...SELECT that fails.
connection slave;
--source include/stop_slave.inc
SET @old_binlog_format= @@global.binlog_format;
SET GLOBAL binlog_format = ROW;
--source include/start_slave.inc
connection master;
SET @old_binlog_format= @@global.binlog_format;
SET binlog_format = ROW;
CREATE TABLE t2(a INT) ENGINE=MYISAM;
CREATE TABLE t3(a INT) ENGINE=INNODB;
delimiter |;
CREATE FUNCTION f1() RETURNS INT
BEGIN
insert into t2 values(1);
insert into t3 values(1);
return 1;
END|
delimiter ;|
let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1);
let $binlog_file= query_get_value("SHOW MASTER STATUS", File, 1);
--error 1062
CREATE TABLE t1(UNIQUE(a)) ENGINE=MYISAM SELECT 1 AS a UNION ALL SELECT f1();
--error 1062
CREATE TABLE t1(UNIQUE(a)) ENGINE=INNODB SELECT 1 AS a UNION ALL SELECT f1();
--source include/show_binlog_events.inc
DROP FUNCTION f1;
DROP TABLE t2, t3;
SET @@global.binlog_format= @old_binlog_format;
--sync_slave_with_master
SET @@global.binlog_format= @old_binlog_format;
# End of 5.1 tests
......@@ -1628,6 +1628,19 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
DBUG_RETURN(error);
}
/**
Cleanup the cache.
@param thd The client thread that wants to clean up the cache.
*/
void MYSQL_BIN_LOG::reset_gathered_updates(THD *thd)
{
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
trx_data->reset();
}
void MYSQL_BIN_LOG::set_write_error(THD *thd)
{
DBUG_ENTER("MYSQL_BIN_LOG::set_write_error");
......
......@@ -356,10 +356,11 @@ public:
/* Use this to start writing a new log file */
void new_file();
void reset_gathered_updates(THD *thd);
bool write(Log_event* event_info); // binary log write
bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
bool write_incident(THD *thd, bool lock);
bool write_incident(THD *thd, bool lock);
int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
void set_write_error(THD *thd);
bool check_write_error(THD *thd);
......
......@@ -3873,6 +3873,17 @@ void select_create::abort()
if (table)
{
if (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
thd->current_stmt_binlog_row_based &&
!(thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
mysql_bin_log.is_open())
{
/*
This should be removed after BUG#47899.
*/
mysql_bin_log.reset_gathered_updates(thd);
}
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
if (!create_info->table_existed)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment