summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2017-12-09 11:21:23 +0200
committerJan Lindström <jan.lindstrom@mariadb.com>2017-12-09 11:21:23 +0200
commitfeb8296ee61cbd349a8bc13cac4e126306039fb5 (patch)
treea4e76a1eaa8b7c770a6046d755bf1a58201ede11
parente66bb5726716b7852c880e02b0acf0f5b9a1e8ee (diff)
downloadmariadb-git-feb8296ee61cbd349a8bc13cac4e126306039fb5.tar.gz
MDEV-14401: Stored procedure that declares a handler that catches ER_LOCK_DEADLOCK error causes thd->is_error() assertion
This was missing bug fix from MySQL wsrep i.e. Galera. Problem was that if stored procedure declares a handler that catches deadlock error, then the error may have been cleared in method sp_rcontext::handle_sql_condition(). Use wsrep_conflict_state correctly to determine is the error already sent to client. Add test case for both this bug and MDEV-12837: WSREP: BF lock wait long. Test requires both fixes to pass.
-rw-r--r--mysql-test/suite/galera/r/galera_bf_lock_wait.result18
-rw-r--r--mysql-test/suite/galera/t/galera_bf_lock_wait.test52
-rw-r--r--sql/sql_parse.cc33
3 files changed, 91 insertions, 12 deletions
diff --git a/mysql-test/suite/galera/r/galera_bf_lock_wait.result b/mysql-test/suite/galera/r/galera_bf_lock_wait.result
new file mode 100644
index 00000000000..4e6019ec8ad
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_bf_lock_wait.result
@@ -0,0 +1,18 @@
+CREATE TABLE t1 ENGINE=InnoDB select 1 as a, 1 as b union select 2, 2;
+ALTER TABLE t1 add primary key(a);
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION rollback;
+WHILE 1 DO
+start transaction;
+update t1 set b=connection_id() where a=1;
+commit;
+END WHILE;
+END|
+call p1;
+call p1;
+call p1;
+call p1;
+checking error log for 'BF lock wait long' message for 10 times every 10 seconds ...
+drop table t1;
+drop procedure p1;
diff --git a/mysql-test/suite/galera/t/galera_bf_lock_wait.test b/mysql-test/suite/galera/t/galera_bf_lock_wait.test
new file mode 100644
index 00000000000..e3a9077a888
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_lock_wait.test
@@ -0,0 +1,52 @@
+--source include/galera_cluster.inc
+--source include/big_test.inc
+
+CREATE TABLE t1 ENGINE=InnoDB select 1 as a, 1 as b union select 2, 2;
+ALTER TABLE t1 add primary key(a);
+
+DELIMITER |;
+
+CREATE PROCEDURE p1()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION rollback;
+ WHILE 1 DO
+ start transaction;
+ update t1 set b=connection_id() where a=1;
+ commit;
+ END WHILE;
+END|
+
+
+DELIMITER ;|
+
+--connect node_1_p1, 127.0.0.1, root, , test, $NODE_MYPORT_1
+send call p1;
+--connect node_1_p2, 127.0.0.1, root, , test, $NODE_MYPORT_1
+send call p1;
+--connect node_2_p1, 127.0.0.1, root, , test, $NODE_MYPORT_2
+send call p1;
+--connect node_2_p2, 127.0.0.1, root, , test, $NODE_MYPORT_2
+send call p1;
+
+connection default;
+let $counter=10;
+let $sleep_period=10;
+
+echo checking error log for 'BF lock wait long' message for $counter times every $sleep_period seconds ...;
+while($counter > 0)
+{
+--disable_query_log
+--disable_result_log
+ eval do sleep($sleep_period);
+--enable_query_log
+--enable_result_log
+
+# use error 0,1 instead if want test to continue
+ --error 1
+ exec grep 'BF lock wait long' $MYSQLTEST_VARDIR/log/mysqld.*.err;
+ dec $counter;
+}
+
+drop table t1;
+drop procedure p1;
+
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 7337a8aeb21..5cea264e4a8 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -5041,14 +5041,19 @@ end_with_restore_list:
thd->print_aborted_warning(3, "RELEASE");
}
#ifdef WITH_WSREP
- if (WSREP(thd) && (thd->wsrep_conflict_state != NO_CONFLICT &&
- thd->wsrep_conflict_state != REPLAYING))
- {
- DBUG_ASSERT(thd->is_error()); // the error is already issued
+ if (WSREP(thd)) {
+
+ if (thd->wsrep_conflict_state == NO_CONFLICT ||
+ thd->wsrep_conflict_state == REPLAYING)
+ {
+ my_ok(thd);
+ }
+ } else {
+#endif /* WITH_WSREP */
+ my_ok(thd);
+#ifdef WITH_WSREP
}
- else
#endif /* WITH_WSREP */
- my_ok(thd);
break;
}
case SQLCOM_ROLLBACK:
@@ -5085,13 +5090,16 @@ end_with_restore_list:
if (tx_release)
thd->set_killed(KILL_CONNECTION);
#ifdef WITH_WSREP
- if (WSREP(thd) && thd->wsrep_conflict_state != NO_CONFLICT)
- {
- DBUG_ASSERT(thd->is_error()); // the error is already issued
+ if (WSREP(thd)) {
+ if (thd->wsrep_conflict_state == NO_CONFLICT) {
+ my_ok(thd);
+ }
+ } else {
+#endif /* WITH_WSREP */
+ my_ok(thd);
+#ifdef WITH_WSREP
}
- else
#endif /* WITH_WSREP */
- my_ok(thd);
break;
}
case SQLCOM_RELEASE_SAVEPOINT:
@@ -5720,8 +5728,9 @@ finish:
if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR))
trans_rollback_stmt(thd);
#ifdef WITH_WSREP
- else if (thd->spcont &&
+ if (thd->spcont &&
(thd->wsrep_conflict_state == MUST_ABORT ||
+ thd->wsrep_conflict_state == ABORTED ||
thd->wsrep_conflict_state == CERT_FAILURE))
{
/*