Skip to content

Commit dd3ffdb

Browse files
committed
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.
1 parent f4f6558 commit dd3ffdb

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

mysql-test/main/xa.result

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ formatID gtrid_length bqual_length data
5151
11 5 5 testb 0@P`
5252
1 5 5 testatestb
5353
xa commit 'testb',0x2030405060,11;
54-
ERROR XAE04: XAER_NOTA: Unknown XID
54+
ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
5555
xa rollback 'testa','testb';
5656
xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
5757
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_сеновала_тормозила_головой';
370370
SET NAMES default;
371371
DROP TABLE t1;
372372
#
373+
# MDEV-21659 XA rollback foreign_xid is allowed inside active XA
374+
# MDEV-21854 - xa commit one phase for already prepared transaction
375+
# must always error out
376+
#
377+
BEGIN;
378+
XA COMMIT 'unknown';
379+
ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
380+
XA COMMIT 'unknown' ONE PHASE;
381+
ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
382+
BEGIN;
383+
XA ROLLBACK 'unknown';
384+
ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
385+
ROLLBACK;
386+
XA START 'xid1';
387+
XA COMMIT 'unknown';
388+
ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
389+
XA COMMIT 'unknown' ONE PHASE;
390+
ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
391+
XA ROLLBACK 'unknown';
392+
ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction
393+
XA END 'xid1';
394+
XA PREPARE 'xid1';
395+
XA COMMIT 'xid1' ONE PHASE;
396+
ERROR XAE05: XAER_INVAL: Invalid arguments (or unsupported command)
397+
XA ROLLBACK 'xid1';
398+
#
373399
# MDEV-21856 - xid_t::formatID has to be constrained to 4 byte size
374400
#
375401
XA START 'gtrid', 'bqual', 0x80000000;

mysql-test/main/xa.test

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ xa prepare 'testa','testb';
7272

7373
xa recover;
7474

75-
--error ER_XAER_NOTA
75+
--error ER_XAER_OUTSIDE
7676
xa commit 'testb',0x2030405060,11;
7777
xa rollback 'testa','testb';
7878

@@ -505,6 +505,33 @@ XA ROLLBACK 'Я_упaлa_c_сеновала_тормозила_головой';
505505
SET NAMES default;
506506

507507
DROP TABLE t1;
508+
--echo #
509+
--echo # MDEV-21659 XA rollback foreign_xid is allowed inside active XA
510+
--echo # MDEV-21854 - xa commit one phase for already prepared transaction
511+
--echo # must always error out
512+
--echo #
513+
BEGIN;
514+
--error ER_XAER_OUTSIDE
515+
XA COMMIT 'unknown';
516+
--error ER_XAER_OUTSIDE
517+
XA COMMIT 'unknown' ONE PHASE;
518+
BEGIN;
519+
--error ER_XAER_OUTSIDE
520+
XA ROLLBACK 'unknown';
521+
ROLLBACK;
522+
523+
XA START 'xid1';
524+
--error ER_XAER_OUTSIDE
525+
XA COMMIT 'unknown';
526+
--error ER_XAER_OUTSIDE
527+
XA COMMIT 'unknown' ONE PHASE;
528+
--error ER_XAER_OUTSIDE
529+
XA ROLLBACK 'unknown';
530+
XA END 'xid1';
531+
XA PREPARE 'xid1';
532+
--error ER_XAER_INVAL
533+
XA COMMIT 'xid1' ONE PHASE;
534+
XA ROLLBACK 'xid1';
508535

509536

510537
--echo #

sql/xa.cc

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,24 @@ bool trans_xa_commit(THD *thd)
529529
if (!thd->transaction.xid_state.is_explicit_XA() ||
530530
!thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
531531
{
532+
if (thd->in_multi_stmt_transaction_mode())
533+
{
534+
/*
535+
Not allow to commit from inside an not-"native" to xid
536+
ongoing transaction: the commit effect can't be reversed.
537+
*/
538+
my_error(ER_XAER_OUTSIDE, MYF(0));
539+
DBUG_RETURN(TRUE);
540+
}
541+
if (thd->lex->xa_opt != XA_NONE)
542+
{
543+
/*
544+
Not allow to commit with one phase a prepared xa out of compatibility
545+
with the native commit branch's error out.
546+
*/
547+
my_error(ER_XAER_INVAL, MYF(0));
548+
DBUG_RETURN(TRUE);
549+
}
532550
if (thd->fix_xid_hash_pins())
533551
{
534552
my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -558,10 +576,14 @@ bool trans_xa_commit(THD *thd)
558576
if ((res= MY_TEST(r)))
559577
my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
560578
}
561-
else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED &&
562-
thd->lex->xa_opt == XA_NONE)
579+
else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED)
563580
{
564581
MDL_request mdl_request;
582+
if (thd->lex->xa_opt != XA_NONE)
583+
{
584+
my_error(ER_XAER_INVAL, MYF(0));
585+
DBUG_RETURN(TRUE);
586+
}
565587

566588
/*
567589
Acquire metadata lock which will ensure that COMMIT is blocked
@@ -623,6 +645,11 @@ bool trans_xa_rollback(THD *thd)
623645
if (!thd->transaction.xid_state.is_explicit_XA() ||
624646
!thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
625647
{
648+
if (thd->in_multi_stmt_transaction_mode())
649+
{
650+
my_error(ER_XAER_OUTSIDE, MYF(0));
651+
DBUG_RETURN(TRUE);
652+
}
626653
if (thd->fix_xid_hash_pins())
627654
{
628655
my_error(ER_OUT_OF_RESOURCES, MYF(0));

0 commit comments

Comments
 (0)