#At file:///export/home/x/mysql-trunk-bug59936/ based on revid:vinay.fisrekar@stripped
3717 Jon Olav Hauglid 2011-03-02
Bug #11766752 (former 59936)
Multiple XA assertions - transactional statement fuzzer
The problem was that the server for several statements did not check
the state of the current XA transaction (if any) before trying to
execute the statement. Specifically, you are not supposed to do
anything other than XA PREPARE / XA COMMIT ONE PHASE when in IDLE state,
or anything other than XA COMMIT / XA ROLLBACK in PREPARED state.
The assertions triggered by the testcase posted in the bug report,
was triggered by trying to access a table or rollback to a savepoint
when the current XA transaction was in PREPARED state.
This patch fixes the problem by reporting ER_XAER_RMFAIL error if
1) A statement tries to start a statement transaction when XA state
is IDLE or PREPARED.
2) SAVEPOINT or ROLLBACK TO SAVEPOINT is executed with an active
XA transaction. (Similar to what is already done for COMMIT/ROLLBACK)
Test case added to xa.test.
Also verified with the C testcase posted on the bug report.
modified:
mysql-test/r/xa.result
mysql-test/t/xa.test
sql/handler.cc
sql/transaction.cc
=== modified file 'mysql-test/r/xa.result'
--- a/mysql-test/r/xa.result 2011-02-14 13:16:31 +0000
+++ b/mysql-test/r/xa.result 2011-03-02 11:49:45 +0000
@@ -166,3 +166,27 @@ ERROR XA102: XA_RBDEADLOCK: Transaction
XA END 'b';
XA ROLLBACK 'b';
DROP TABLE t1;
+#
+# Bug#11766752 59936: multiple xa assertions - transactional
+# statement fuzzer
+#
+CREATE TABLE t1 (a INT) engine=InnoDB;
+XA START 'a';
+INSERT INTO t1 VALUES (1);
+SAVEPOINT savep;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state
+XA END 'a';
+INSERT INTO t1 VALUES (2);
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state
+SAVEPOINT savep;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state
+XA PREPARE 'a';
+INSERT INTO t1 VALUES (2);
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state
+SAVEPOINT savep;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state
+XA COMMIT 'a';
+SELECT * FROM t1;
+a
+1
+DROP TABLE t1;
=== modified file 'mysql-test/t/xa.test'
--- a/mysql-test/t/xa.test 2011-02-14 13:16:31 +0000
+++ b/mysql-test/t/xa.test 2011-03-02 11:49:45 +0000
@@ -287,6 +287,35 @@ DROP TABLE t1;
disconnect con1;
+--echo #
+--echo # Bug#11766752 59936: multiple xa assertions - transactional
+--echo # statement fuzzer
+--echo #
+
+CREATE TABLE t1 (a INT) engine=InnoDB;
+XA START 'a';
+INSERT INTO t1 VALUES (1);
+
+--error ER_XAER_RMFAIL
+SAVEPOINT savep;
+
+XA END 'a';
+--error ER_XAER_RMFAIL
+INSERT INTO t1 VALUES (2);
+--error ER_XAER_RMFAIL
+SAVEPOINT savep;
+
+XA PREPARE 'a';
+--error ER_XAER_RMFAIL
+INSERT INTO t1 VALUES (2);
+--error ER_XAER_RMFAIL
+SAVEPOINT savep;
+
+XA COMMIT 'a';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
# Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc 2011-03-01 14:47:01 +0000
+++ b/sql/handler.cc 2011-03-02 11:49:45 +0000
@@ -975,6 +975,13 @@ void trans_register_ha(THD *thd, bool al
DBUG_ENTER("trans_register_ha");
DBUG_PRINT("enter",("%s", all ? "all" : "stmt"));
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ if (xa_state == XA_IDLE || xa_state == XA_PREPARED)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ DBUG_VOID_RETURN;
+ }
+
if (all)
{
trans= &thd->transaction.all;
=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc 2011-02-14 14:15:28 +0000
+++ b/sql/transaction.cc 2011-03-02 11:49:45 +0000
@@ -362,6 +362,13 @@ bool trans_savepoint(THD *thd, LEX_STRIN
!opt_using_transactions)
DBUG_RETURN(FALSE);
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ if (xa_state != XA_NOTR)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ DBUG_RETURN(TRUE);
+ }
+
sv= find_savepoint(thd, name);
if (*sv) /* old savepoint of the same name exists */
@@ -435,6 +442,13 @@ bool trans_rollback_to_savepoint(THD *th
DBUG_RETURN(TRUE);
}
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ if (xa_state != XA_NOTR)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ DBUG_RETURN(TRUE);
+ }
+
if (ha_rollback_to_savepoint(thd, sv))
res= TRUE;
else if (((thd->variables.option_bits & OPTION_KEEP_LOG) ||
Attachment: [text/bzr-bundle] bzr/jon.hauglid@oracle.com-20110302114945-1pwxk2c0o0y8kd04.bundle