Commit 78585a25 authored by Alfranio Correia's avatar Alfranio Correia

BUG#46130 Slave does not correctly handle "expected errors"

In STATEMENT based replication, a statement that failed on the master but that
updated non-transactional tables is written to binary log with the error code
appended to it. On the slave, the statement is executed and the same error is
expected. However, when an "expected error" did not happen on the slave and was
either ignored or was related to a concurrency issue on the master, the slave
did not rollback the effects of the statement and as such inconsistencies might
happen.

To fix the problem, we automatically rollback a statement that should have
failed on a slave but succeded and whose expected failure is either ignored or
stems from a concurrency issue on the master.
parent ad2b5063
...@@ -101,6 +101,8 @@ master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'dark blue 1' WHERE f ...@@ -101,6 +101,8 @@ master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'dark blue 1' WHERE f
master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (6 + (1 * 10),"brown") master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (6 + (1 * 10),"brown")
master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown") master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
source include/diff_master_slave.inc;
source include/diff_master_slave.inc;
######################################################################## ########################################################################
# Cleanup # Cleanup
######################################################################## ########################################################################
......
...@@ -125,14 +125,13 @@ while ($type) ...@@ -125,14 +125,13 @@ while ($type)
connection master; connection master;
sync_slave_with_master; sync_slave_with_master;
# Re-enable this after fixing BUG#46130 connection master;
#connection master; let $diff_statement= SELECT * FROM t order by i;
#let $diff_statement= SELECT * FROM t order by i; source include/diff_master_slave.inc;
#source include/diff_master_slave.inc;
connection master;
#connection master; let $diff_statement= SELECT * FROM n order by d, f;
#let $diff_statement= SELECT * FROM n order by d, f; source include/diff_master_slave.inc;
#source include/diff_master_slave.inc;
--echo ######################################################################## --echo ########################################################################
--echo # Cleanup --echo # Cleanup
......
...@@ -3160,7 +3160,7 @@ compare_errors: ...@@ -3160,7 +3160,7 @@ compare_errors:
/* /*
If we expected a non-zero error code, and we don't get the same error If we expected a non-zero error code, and we don't get the same error
code, and none of them should be ignored. code, and it should be ignored or is related to a concurrency issue.
*/ */
actual_error= thd->is_error() ? thd->main_da.sql_errno() : 0; actual_error= thd->is_error() ? thd->main_da.sql_errno() : 0;
DBUG_PRINT("info",("expected_error: %d sql_errno: %d", DBUG_PRINT("info",("expected_error: %d sql_errno: %d",
...@@ -3183,7 +3183,8 @@ Default database: '%s'. Query: '%s'", ...@@ -3183,7 +3183,8 @@ Default database: '%s'. Query: '%s'",
thd->is_slave_error= 1; thd->is_slave_error= 1;
} }
/* /*
If we get the same error code as expected, or they should be ignored. If we get the same error code as expected and it is not a concurrency
issue, or should be ignored.
*/ */
else if ((expected_error == actual_error && else if ((expected_error == actual_error &&
!concurrency_error_code(expected_error)) || !concurrency_error_code(expected_error)) ||
...@@ -3193,6 +3194,14 @@ Default database: '%s'. Query: '%s'", ...@@ -3193,6 +3194,14 @@ Default database: '%s'. Query: '%s'",
clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
thd->killed= THD::NOT_KILLED; thd->killed= THD::NOT_KILLED;
} }
/*
If we expected a non-zero error code and get nothing and, it is a concurrency
issue or should be ignored.
*/
else if (expected_error && !actual_error &&
(concurrency_error_code(expected_error) ||
ignored_error_code(expected_error)))
ha_autocommit_or_rollback(thd, TRUE);
/* /*
Other cases: mostly we expected no error and get one. Other cases: mostly we expected no error and get one.
*/ */
......
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