From 7768ccbb54114e8ca35287fbcb14615f81a88783 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 4 Mar 2010 10:18:06 +0000 Subject: [PATCH] BUG#51055: Replication failure on duplicate key + traditional SQL mode When the master was executing in sql_mode='traditional' (which implies that really_abort_on_warning returns TRUE - because of MODE_STRICT_ALL_TABLES), the error code (ER_DUP_ENTRY in the reported case) was not being set in the Query_log_event. Therefore, even if a failure was to be expected when replaying the statement on the slave, a failure would occur, because the Query_log_event was not transporting the expected error code, but 0 instead. This was because when the master was getting the error code to set it in the Query_log_event, the executing thread would be assumed to have been killed: THD::killed==THD::KILL_BAD_DATA. This would make the error code fetch routine not to check thd->main_da.sql_errno(), but instead the thd->killed value. What's more, is that the server would thd->killed value if thd->killed == THD::KILL_BAD_DATA and return 0 instead. So this is a double inconsistency, as the we should not even check thd->killed but rather thd->main_da.sql_errno(). We fix this by extending the condition used to choose whether to check the thd->main_da.sql_errno() or thd->killed, so that it takes into consideration the case when: thd->killed==THD::KILL_BAD_DATA. --- .../suite/rpl/r/rpl_stm_sql_mode.result | 18 ++++++++++++++ mysql-test/suite/rpl/t/rpl_stm_sql_mode.test | 24 +++++++++++++++++++ sql/log.cc | 2 +- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/rpl/r/rpl_stm_sql_mode.result create mode 100644 mysql-test/suite/rpl/t/rpl_stm_sql_mode.test diff --git a/mysql-test/suite/rpl/r/rpl_stm_sql_mode.result b/mysql-test/suite/rpl/r/rpl_stm_sql_mode.result new file mode 100644 index 00000000000..fd143fc8a50 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_stm_sql_mode.result @@ -0,0 +1,18 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t1 (pk integer auto_increment , primary key (pk)); +SET SESSION SQL_MODE='traditional'; +# **** [MASTER] ***** +# action: raise DUP KEY error (error code should be set in the +# query log event) +INSERT INTO t1 (`pk`) VALUES (1), (1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +DROP TABLE t1; +# **** [ sync slave with master ] **** +# assertion: sync slave with master makes slave not to stop with +# duplicate key error (because it has received event +# with expected error code). diff --git a/mysql-test/suite/rpl/t/rpl_stm_sql_mode.test b/mysql-test/suite/rpl/t/rpl_stm_sql_mode.test new file mode 100644 index 00000000000..d5aac4a43e2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_sql_mode.test @@ -0,0 +1,24 @@ +-- source include/master-slave.inc +-- source include/have_binlog_format_statement.inc + +# +# Bug #51055 Replication failure on duplicate key + traditional SQL mode +# + +CREATE TABLE t1 (pk integer auto_increment , primary key (pk)); + +SET SESSION SQL_MODE='traditional'; + +-- echo # **** [MASTER] ***** +-- echo # action: raise DUP KEY error (error code should be set in the +-- echo # query log event) +-- error ER_DUP_ENTRY +INSERT INTO t1 (`pk`) VALUES (1), (1); + +DROP TABLE t1; + +-- echo # **** [ sync slave with master ] **** +-- echo # assertion: sync slave with master makes slave not to stop with +-- echo # duplicate key error (because it has received event +-- echo # with expected error code). +-- sync_slave_with_master diff --git a/sql/log.cc b/sql/log.cc index b7313a988c4..b75650cfec7 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4679,7 +4679,7 @@ int query_error_code(THD *thd, bool not_killed) { int error; - if (not_killed) + if (not_killed || (thd->killed == THD::KILL_BAD_DATA)) { error= thd->is_error() ? thd->main_da.sql_errno() : 0;