From 33ed16c7505dbe9f9e861b0ddebb038bb81659bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 2 Dec 2016 16:25:47 +0200 Subject: [PATCH] MDEV-11236 Failing assertion: state == TRX_STATE_NOT_STARTED trx_state_eq(): Add the parameter bool relaxed=false, to allow trx->state==TRX_STATE_NOT_STARTED where a different state is expected, if an error has been reported. trx_release_savepoint_for_mysql(): Pass relaxed=true to trx_state_eq(). That is, allow the transaction to be idle when ROLLBACK TO SAVEPOINT is attempted after an error has been reported to the client. --- mysql-test/suite/innodb/r/trigger.result | 28 ++++++++++++++ mysql-test/suite/innodb/t/trigger.test | 47 ++++++++++++++++++++++++ storage/innobase/include/trx0trx.h | 12 +++++- storage/innobase/include/trx0trx.ic | 14 ++++++- storage/innobase/trx/trx0roll.cc | 4 +- storage/xtradb/include/trx0trx.h | 9 ++++- storage/xtradb/include/trx0trx.ic | 11 +++++- storage/xtradb/trx/trx0roll.cc | 4 +- 8 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 mysql-test/suite/innodb/r/trigger.result create mode 100644 mysql-test/suite/innodb/t/trigger.test diff --git a/mysql-test/suite/innodb/r/trigger.result b/mysql-test/suite/innodb/r/trigger.result new file mode 100644 index 00000000000..8218e6e8e70 --- /dev/null +++ b/mysql-test/suite/innodb/r/trigger.result @@ -0,0 +1,28 @@ +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +CREATE TABLE t3 (c INT) ENGINE=InnoDB; +CREATE TRIGGER tr BEFORE INSERT ON t3 FOR EACH ROW BEGIN SAVEPOINT sv; INSERT INTO t2 VALUES (0); END $$ +START TRANSACTION; +DELETE FROM t1; +connect con1,localhost,root,,test; +START TRANSACTION; +INSERT INTO t2 VALUES (2); +UPDATE t2 SET b = b+1; +INSERT INTO t1 VALUES (1); +connection default; +COMMIT; +connection con1; +COMMIT; +disconnect con1; +connection default; +SELECT * FROM t1; +a +1 +SELECT * FROM t2; +b +3 +SELECT * FROM t3; +c +DROP TABLE t1, t2, t3; +DROP TRIGGER tr; +ERROR HY000: Trigger does not exist diff --git a/mysql-test/suite/innodb/t/trigger.test b/mysql-test/suite/innodb/t/trigger.test new file mode 100644 index 00000000000..fe0bab21497 --- /dev/null +++ b/mysql-test/suite/innodb/t/trigger.test @@ -0,0 +1,47 @@ +--source include/have_innodb.inc +--source include/count_sessions.inc + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +CREATE TABLE t3 (c INT) ENGINE=InnoDB; + +--delimiter $$ +CREATE TRIGGER tr BEFORE INSERT ON t3 FOR EACH ROW BEGIN SAVEPOINT sv; INSERT INTO t2 VALUES (0); END $$ +--delimiter ; + +START TRANSACTION; +DELETE FROM t1; + +connect (con1,localhost,root,,test); +START TRANSACTION; +INSERT INTO t2 VALUES (2); +UPDATE t2 SET b = b+1; + +--send +INSERT INTO t1 VALUES (1); + +connection default; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = 'update' and info = 'INSERT INTO t1 VALUES (1)' +--source include/wait_condition.inc + +--error ER_LOCK_DEADLOCK +INSERT INTO t3 VALUES (2); +COMMIT; + +connection con1; +reap; +COMMIT; +disconnect con1; + +connection default; +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +DROP TABLE t1, t2, t3; +--error ER_TRG_DOES_NOT_EXIST +DROP TRIGGER tr; + +--source include/wait_until_count_sessions.inc diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 91d85255fb2..19b0747c6a3 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -432,8 +433,15 @@ bool trx_state_eq( /*=========*/ const trx_t* trx, /*!< in: transaction */ - trx_state_t state) /*!< in: state */ - MY_ATTRIBUTE((warn_unused_result)); + trx_state_t state, /*!< in: state; + if state != TRX_STATE_NOT_STARTED + asserts that + trx->state != TRX_STATE_NOT_STARTED */ + bool relaxed = false) + /*!< in: whether to allow + trx->state == TRX_STATE_NOT_STARTED + after an error has been reported */ + MY_ATTRIBUTE((nonnull, warn_unused_result)); # ifdef UNIV_DEBUG /**********************************************************************//** Asserts that a transaction has been started. diff --git a/storage/innobase/include/trx0trx.ic b/storage/innobase/include/trx0trx.ic index 7120a7aaced..f0ed9b61c5a 100644 --- a/storage/innobase/include/trx0trx.ic +++ b/storage/innobase/include/trx0trx.ic @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -36,7 +37,14 @@ bool trx_state_eq( /*=========*/ const trx_t* trx, /*!< in: transaction */ - trx_state_t state) /*!< in: state */ + trx_state_t state, /*!< in: state; + if state != TRX_STATE_NOT_STARTED + asserts that + trx->state != TRX_STATE_NOT_STARTED */ + bool relaxed) + /*!< in: whether to allow + trx->state == TRX_STATE_NOT_STARTED + after an error has been reported */ { #ifdef UNIV_DEBUG switch (trx->state) { @@ -60,7 +68,9 @@ trx_state_eq( /* These states are not allowed for running transactions. */ ut_a(state == TRX_STATE_NOT_STARTED - || state == TRX_STATE_FORCED_ROLLBACK); + || state == TRX_STATE_FORCED_ROLLBACK + || (relaxed + && thd_get_error_number(trx->mysql_thd))); ut_ad(!trx->in_rw_trx_list); diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index a22b903df7a..dc779fefc58 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -581,7 +582,8 @@ trx_release_savepoint_for_mysql( { trx_named_savept_t* savep; - ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) || trx_state_eq(trx, TRX_STATE_PREPARED)); + ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE, true) + || trx_state_eq(trx, TRX_STATE_PREPARED, true)); ut_ad(trx->in_mysql_trx_list); savep = trx_savepoint_find(trx, savepoint_name); diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index 44ff8f3ec98..0733d830a9a 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -1,7 +1,8 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, MariaDB Corporation +Copyright (c) 2015, 2016, MariaDB Corporation. All Rights Reserved. + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -393,10 +394,14 @@ ibool trx_state_eq( /*=========*/ const trx_t* trx, /*!< in: transaction */ - trx_state_t state) /*!< in: state; + trx_state_t state, /*!< in: state; if state != TRX_STATE_NOT_STARTED asserts that trx->state != TRX_STATE_NOT_STARTED */ + bool relaxed = false) + /*!< in: whether to allow + trx->state == TRX_STATE_NOT_STARTED + after an error has been reported */ MY_ATTRIBUTE((nonnull, warn_unused_result)); # ifdef UNIV_DEBUG /**********************************************************************//** diff --git a/storage/xtradb/include/trx0trx.ic b/storage/xtradb/include/trx0trx.ic index 8582b63f806..eb7d62d9cad 100644 --- a/storage/xtradb/include/trx0trx.ic +++ b/storage/xtradb/include/trx0trx.ic @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -36,10 +37,14 @@ ibool trx_state_eq( /*=========*/ const trx_t* trx, /*!< in: transaction */ - trx_state_t state) /*!< in: state; + trx_state_t state, /*!< in: state; if state != TRX_STATE_NOT_STARTED asserts that trx->state != TRX_STATE_NOT_STARTED */ + bool relaxed) + /*!< in: whether to allow + trx->state == TRX_STATE_NOT_STARTED + after an error has been reported */ { #ifdef UNIV_DEBUG switch (trx->state) { @@ -57,7 +62,9 @@ trx_state_eq( case TRX_STATE_NOT_STARTED: /* This state is not allowed for running transactions. */ - ut_a(state == TRX_STATE_NOT_STARTED); + ut_a(state == TRX_STATE_NOT_STARTED + || (relaxed + && thd_get_error_number(trx->mysql_thd))); ut_ad(!trx->in_rw_trx_list); ut_ad(!trx->in_ro_trx_list); return(state == trx->state); diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc index 4618cf653f0..ee1497b209f 100644 --- a/storage/xtradb/trx/trx0roll.cc +++ b/storage/xtradb/trx/trx0roll.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -507,7 +508,8 @@ trx_release_savepoint_for_mysql( { trx_named_savept_t* savep; - ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) || trx_state_eq(trx, TRX_STATE_PREPARED)); + ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE, true) + || trx_state_eq(trx, TRX_STATE_PREPARED, true)); ut_ad(trx->in_mysql_trx_list); savep = trx_savepoint_find(trx, savepoint_name);