diff --git a/mysql-test/suite/galera/r/MW-388.result b/mysql-test/suite/galera/r/MW-388.result new file mode 100644 index 00000000000..f81f1e1a9fb --- /dev/null +++ b/mysql-test/suite/galera/r/MW-388.result @@ -0,0 +1,33 @@ +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) Engine=InnoDB; +CREATE PROCEDURE insert_proc () +BEGIN +DECLARE CONTINUE HANDLER FOR SQLEXCEPTION +BEGIN +GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO; +END; +INSERT INTO t1 VALUES (1, 'node 1'),(2, 'node 1'); +INSERT INTO t1 VALUES (3, 'node 1'); +END| +SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb"; +INSERT INTO t1 VALUES (1, 'node 2');; +SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; +SET SESSION wsrep_sync_wait = 0; +SET SESSION DEBUG_SYNC = 'wsrep_before_replication SIGNAL wsrep_before_replication_reached WAIT_FOR wsrep_before_replication_continue'; +CALL insert_proc ();; +SET SESSION DEBUG_SYNC = "now WAIT_FOR wsrep_before_replication_reached"; +SET GLOBAL DEBUG = ""; +SET DEBUG_SYNC = "now SIGNAL wsrep_before_replication_continue"; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; +SELECT @errno; +@errno +1213 +SELECT * FROM t1; +f1 f2 +1 node 2 +3 node 1 +SELECT * FROM t1; +f1 f2 +1 node 2 +3 node 1 +DROP TABLE t1; +DROP PROCEDURE insert_proc; diff --git a/mysql-test/suite/galera/t/MW-388.test b/mysql-test/suite/galera/t/MW-388.test new file mode 100644 index 00000000000..59b28dba236 --- /dev/null +++ b/mysql-test/suite/galera/t/MW-388.test @@ -0,0 +1,54 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--connection node_1 +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) Engine=InnoDB; + +DELIMITER |; +CREATE PROCEDURE insert_proc () +BEGIN + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION + BEGIN + GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO; + END; + INSERT INTO t1 VALUES (1, 'node 1'),(2, 'node 1'); + INSERT INTO t1 VALUES (3, 'node 1'); +END| +DELIMITER ;| + +SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb"; + +--connection node_2 +--send INSERT INTO t1 VALUES (1, 'node 2'); + +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--connection node_1a +SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; + +--connection node_1 +SET SESSION wsrep_sync_wait = 0; +SET SESSION DEBUG_SYNC = 'wsrep_before_replication SIGNAL wsrep_before_replication_reached WAIT_FOR wsrep_before_replication_continue'; +--send CALL insert_proc (); + +--connection node_1a +SET SESSION DEBUG_SYNC = "now WAIT_FOR wsrep_before_replication_reached"; + +--connection node_1a +SET GLOBAL DEBUG = ""; +SET DEBUG_SYNC = "now SIGNAL wsrep_before_replication_continue"; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; + +--connection node_2 +--reap + +--connection node_1 +# We expect no errors here, because the handler in insert_proc() caught the deadlock error +--reap +SELECT @errno; +SELECT * FROM t1; + +--connection node_2 +SELECT * FROM t1; + +DROP TABLE t1; +DROP PROCEDURE insert_proc; \ No newline at end of file diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 11d4630bc49..f28bf1044e0 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5620,6 +5620,26 @@ finish: } if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR)) trans_rollback_stmt(thd); +#ifdef WITH_WSREP + else if (thd->sp_runtime_ctx && + !thd->is_error() && + !thd->in_multi_stmt_transaction_mode() && + (thd->wsrep_conflict_state == MUST_ABORT || + thd->wsrep_conflict_state == CERT_FAILURE)) + { + /* + The error was cleared, but THD was aborted by wsrep and + wsrep_conflict_state is still set accordingly. This + situation is expected if we are running a stored procedure + that declares a handler that catches ER_LOCK_DEADLOCK error. + In which case the error may have been cleared in method + sp_rcontext::handle_sql_condition(). + */ + trans_rollback_stmt(thd); + thd->wsrep_conflict_state= NO_CONFLICT; + thd->killed= THD::NOT_KILLED; + } +#endif /* WITH_WSREP */ else { /* If commit fails, we should be able to reset the OK status. */