summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Elkin <andrei.elkin@mariadb.com>2020-03-02 17:12:35 +0200
committerAndrei Elkin <andrei.elkin@mariadb.com>2020-03-09 20:40:52 +0200
commitdd3ffdbd92e9cc7224f8127c1fb6a7332110ff3e (patch)
treebe41634cbe85a954aa47b7f26f96259ec8d7f882
parentf4f65586667860295c5d5cd371a6f44ede60005f (diff)
downloadmariadb-git-dd3ffdbd92e9cc7224f8127c1fb6a7332110ff3e.tar.gz
MDEV-21659 XA rollback foreign_xid is allowed inside active XA
MDEV-21854 xa commit `xid` one phase for already prepared transaction must always error out Added state and one-phase option checks to XA "external" commit/rollback branches. While the XA standard does not prohibit it, Commit and Rollback of an XA external to the current ongoing transaction is not allowed; after all the current transaction may rollback to not being able to revert that decision.
-rw-r--r--mysql-test/main/xa.result28
-rw-r--r--mysql-test/main/xa.test29
-rw-r--r--sql/xa.cc31
3 files changed, 84 insertions, 4 deletions
diff --git a/mysql-test/main/xa.result b/mysql-test/main/xa.result
index f5d72930913..5e03c8f75dc 100644
--- a/mysql-test/main/xa.result
+++ b/mysql-test/main/xa.result
@@ -51,7 +51,7 @@ formatID gtrid_length bqual_length data
11 5 5 testb 0@P`
1 5 5 testatestb
xa commit 'testb',0x2030405060,11;
-ERROR XAE04: XAER_NOTA: Unknown XID
+ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
xa rollback 'testa','testb';
xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
@@ -370,6 +370,32 @@ XA ROLLBACK 'Я_упaлa_c_сеновала_тормозила_головой';
SET NAMES default;
DROP TABLE t1;
#
+# MDEV-21659 XA rollback foreign_xid is allowed inside active XA
+# MDEV-21854 - xa commit one phase for already prepared transaction
+# must always error out
+#
+BEGIN;
+XA COMMIT 'unknown';
+ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
+XA COMMIT 'unknown' ONE PHASE;
+ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
+BEGIN;
+XA ROLLBACK 'unknown';
+ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
+ROLLBACK;
+XA START 'xid1';
+XA COMMIT 'unknown';
+ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
+XA COMMIT 'unknown' ONE PHASE;
+ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
+XA ROLLBACK 'unknown';
+ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
+XA END 'xid1';
+XA PREPARE 'xid1';
+XA COMMIT 'xid1' ONE PHASE;
+ERROR XAE05: XAER_INVAL: Invalid arguments (or unsupported command)
+XA ROLLBACK 'xid1';
+#
# MDEV-21856 - xid_t::formatID has to be constrained to 4 byte size
#
XA START 'gtrid', 'bqual', 0x80000000;
diff --git a/mysql-test/main/xa.test b/mysql-test/main/xa.test
index 3305a54e690..e23e3c6a428 100644
--- a/mysql-test/main/xa.test
+++ b/mysql-test/main/xa.test
@@ -72,7 +72,7 @@ xa prepare 'testa','testb';
xa recover;
---error ER_XAER_NOTA
+--error ER_XAER_OUTSIDE
xa commit 'testb',0x2030405060,11;
xa rollback 'testa','testb';
@@ -505,6 +505,33 @@ XA ROLLBACK 'Я_упaлa_c_сеновала_тормозила_головой';
SET NAMES default;
DROP TABLE t1;
+--echo #
+--echo # MDEV-21659 XA rollback foreign_xid is allowed inside active XA
+--echo # MDEV-21854 - xa commit one phase for already prepared transaction
+--echo # must always error out
+--echo #
+BEGIN;
+--error ER_XAER_OUTSIDE
+XA COMMIT 'unknown';
+--error ER_XAER_OUTSIDE
+XA COMMIT 'unknown' ONE PHASE;
+BEGIN;
+--error ER_XAER_OUTSIDE
+XA ROLLBACK 'unknown';
+ROLLBACK;
+
+XA START 'xid1';
+--error ER_XAER_OUTSIDE
+XA COMMIT 'unknown';
+--error ER_XAER_OUTSIDE
+XA COMMIT 'unknown' ONE PHASE;
+--error ER_XAER_OUTSIDE
+XA ROLLBACK 'unknown';
+XA END 'xid1';
+XA PREPARE 'xid1';
+--error ER_XAER_INVAL
+XA COMMIT 'xid1' ONE PHASE;
+XA ROLLBACK 'xid1';
--echo #
diff --git a/sql/xa.cc b/sql/xa.cc
index 9b1545a6bd5..e0ae0caa1a2 100644
--- a/sql/xa.cc
+++ b/sql/xa.cc
@@ -529,6 +529,24 @@ bool trans_xa_commit(THD *thd)
if (!thd->transaction.xid_state.is_explicit_XA() ||
!thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
{
+ if (thd->in_multi_stmt_transaction_mode())
+ {
+ /*
+ Not allow to commit from inside an not-"native" to xid
+ ongoing transaction: the commit effect can't be reversed.
+ */
+ my_error(ER_XAER_OUTSIDE, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ if (thd->lex->xa_opt != XA_NONE)
+ {
+ /*
+ Not allow to commit with one phase a prepared xa out of compatibility
+ with the native commit branch's error out.
+ */
+ my_error(ER_XAER_INVAL, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
if (thd->fix_xid_hash_pins())
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -558,10 +576,14 @@ bool trans_xa_commit(THD *thd)
if ((res= MY_TEST(r)))
my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
}
- else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED &&
- thd->lex->xa_opt == XA_NONE)
+ else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED)
{
MDL_request mdl_request;
+ if (thd->lex->xa_opt != XA_NONE)
+ {
+ my_error(ER_XAER_INVAL, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
/*
Acquire metadata lock which will ensure that COMMIT is blocked
@@ -623,6 +645,11 @@ bool trans_xa_rollback(THD *thd)
if (!thd->transaction.xid_state.is_explicit_XA() ||
!thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
{
+ if (thd->in_multi_stmt_transaction_mode())
+ {
+ my_error(ER_XAER_OUTSIDE, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
if (thd->fix_xid_hash_pins())
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));