Commit 88a9b233 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-14609 XA Transction unable to ROLLBACK TO SAVEPOINT

The function trans_rollback_to_savepoint(), unlike trans_savepoint(),
did not allow xa_state=XA_ACTIVE, so an attempt to do ROLLBCK TO SAVEPOINT
inside an XA transaction incorrectly returned an error
"...command cannot be executed ... in the ACTIVE state...".

Partially merging a MySQL patch:
  7fb5c47390311d9b1b5367f97cb8fedd4102dd05
  This is WL#7193 (Decouple THD and st_transactions)...

The currently merged part includes these changes:
- Introducing st_xid_state::check_has_uncommitted_xa()
- Reusing it in both trans_rollback_to_savepoint() and trans_savepoint(),
  so now both allow XA_ACTIVE.
parent 5fe1d7d0
...@@ -200,6 +200,17 @@ a ...@@ -200,6 +200,17 @@ a
1 1
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-14609 XA Transction unable to ROLLBACK TO SAVEPOINT
#
CREATE TABLE t1 (c1 INT) ENGINE=INNODB;
XA START 'xa1';
SAVEPOINT savepoint1;
INSERT INTO t1 (c1) VALUES (1),(2),(3),(4);
ROLLBACK TO SAVEPOINT savepoint1;
XA END 'xa1';
XA ROLLBACK 'xa1';
DROP TABLE t1;
#
# Bug#12352846 - TRANS_XA_START(THD*): # Bug#12352846 - TRANS_XA_START(THD*):
# ASSERTION THD->TRANSACTION.XID_STATE.XID.IS_NULL() # ASSERTION THD->TRANSACTION.XID_STATE.XID.IS_NULL()
# FAILED # FAILED
......
...@@ -327,6 +327,20 @@ SELECT * FROM t1; ...@@ -327,6 +327,20 @@ SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-14609 XA Transction unable to ROLLBACK TO SAVEPOINT
--echo #
CREATE TABLE t1 (c1 INT) ENGINE=INNODB;
XA START 'xa1';
SAVEPOINT savepoint1;
INSERT INTO t1 (c1) VALUES (1),(2),(3),(4);
ROLLBACK TO SAVEPOINT savepoint1;
XA END 'xa1';
XA ROLLBACK 'xa1';
DROP TABLE t1;
--echo # --echo #
--echo # Bug#12352846 - TRANS_XA_START(THD*): --echo # Bug#12352846 - TRANS_XA_START(THD*):
--echo # ASSERTION THD->TRANSACTION.XID_STATE.XID.IS_NULL() --echo # ASSERTION THD->TRANSACTION.XID_STATE.XID.IS_NULL()
......
...@@ -991,6 +991,30 @@ typedef struct st_xid_state { ...@@ -991,6 +991,30 @@ typedef struct st_xid_state {
bool in_thd; bool in_thd;
/* Error reported by the Resource Manager (RM) to the Transaction Manager. */ /* Error reported by the Resource Manager (RM) to the Transaction Manager. */
uint rm_error; uint rm_error;
/**
Check that XA transaction has an uncommitted work. Report an error
to the user in case when there is an uncommitted work for XA transaction.
@return result of check
@retval false XA transaction is NOT in state IDLE, PREPARED
or ROLLBACK_ONLY.
@retval true XA transaction is in state IDLE or PREPARED
or ROLLBACK_ONLY.
*/
bool check_has_uncommitted_xa() const
{
if (xa_state == XA_IDLE ||
xa_state == XA_PREPARED ||
xa_state == XA_ROLLBACK_ONLY)
{
my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
return true;
}
return false;
}
} XID_STATE; } XID_STATE;
extern mysql_mutex_t LOCK_xid_cache; extern mysql_mutex_t LOCK_xid_cache;
......
...@@ -433,12 +433,8 @@ bool trans_savepoint(THD *thd, LEX_STRING name) ...@@ -433,12 +433,8 @@ bool trans_savepoint(THD *thd, LEX_STRING name)
!opt_using_transactions) !opt_using_transactions)
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
enum xa_states xa_state= thd->transaction.xid_state.xa_state; if (thd->transaction.xid_state.check_has_uncommitted_xa())
if (xa_state != XA_NOTR && xa_state != XA_ACTIVE)
{
my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
}
sv= find_savepoint(thd, name); sv= find_savepoint(thd, name);
...@@ -513,12 +509,8 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name) ...@@ -513,12 +509,8 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
enum xa_states xa_state= thd->transaction.xid_state.xa_state; if (thd->transaction.xid_state.check_has_uncommitted_xa())
if (xa_state != XA_NOTR)
{
my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
}
if (ha_rollback_to_savepoint(thd, sv)) if (ha_rollback_to_savepoint(thd, sv))
res= TRUE; res= TRUE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment