List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:October 22 2008 6:39pm
Subject:bzr push into mysql-6.0 branch (davi:2876 to 2877) Bug#28323
View as plain text  
 2877 Davi Arnaut	2008-10-22 [merge]
      Bug#28323: Server crashed in xid cache operations
      
      The problem was that the server did not robustly handle a
      unilateral roll back issued by the Resource Manager (RM)
      due to a resource deadlock within the transaction branch.
      By not acknowledging the roll back, the server (TM) would
      eventually corrupt the XA transaction state and crash.
      
      The solution is to mark the transaction as rollback-only
      if the RM indicates that it rolled back its branch of the
modified:
  mysql-test/r/backup_backupdir.result
  mysql-test/r/debug_sync.result
  mysql-test/r/locktrans_innodb.result
  mysql-test/r/locktrans_myisam.result
  mysql-test/r/xa.result
  mysql-test/t/xa.test
  sql/handler.cc
  sql/share/errmsg.txt
  sql/sql_class.h
  sql/sql_parse.cc
  sql/transaction.cc

 2876 Sven Sandberg	2008-10-22 [merge]
      Merged test case for BUG#39812 from 5.1-5.1.29-rc to 6.0-5.1.29-rc, and
      changed the expected default binlog format in the result file to MIXED.
modified:
  mysql-test/r/binlog_format_basic.result
  mysql-test/t/binlog_format_basic.test

=== modified file 'mysql-test/r/backup_backupdir.result'
--- a/mysql-test/r/backup_backupdir.result	2008-09-02 09:04:39 +0000
+++ b/mysql-test/r/backup_backupdir.result	2008-10-22 16:33:23 +0000
@@ -53,8 +53,8 @@ ERROR HY000: Can't write to backup locat
 Attempt to set the backupdir to something invalid.
 SET @@global.backupdir = 'This_is_really_stupid/not/there/at/all';
 Warnings:
-Warning	1725	The path specified for the system variable backupdir cannot be accessed or is invalid. ref: This_is_really_stupid/not/there/at/all
-Warning	1725	The path specified for the system variable backupdir cannot be accessed or is invalid. ref: This_is_really_stupid/not/there/at/all
+Warning	1727	The path specified for the system variable backupdir cannot be accessed or is invalid. ref: This_is_really_stupid/not/there/at/all
+Warning	1727	The path specified for the system variable backupdir cannot be accessed or is invalid. ref: This_is_really_stupid/not/there/at/all
 Cleanup
 Reset backupdir 
 SET @@global.backupdir = @@global.datadir;

=== modified file 'mysql-test/r/debug_sync.result'
--- a/mysql-test/r/debug_sync.result	2008-07-09 14:27:18 +0000
+++ b/mysql-test/r/debug_sync.result	2008-10-22 16:33:23 +0000
@@ -137,7 +137,7 @@ Variable_name	Value
 debug_sync	ON - current signal: 'something'
 SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0';
 Warnings:
-Warning	1720	debug sync point wait timed out
+Warning	1722	debug sync point wait timed out
 SET DEBUG_SYNC= 'now SIGNAL nothing';
 SHOW VARIABLES LIKE 'DEBUG_SYNC';
 Variable_name	Value

=== modified file 'mysql-test/r/locktrans_innodb.result'
--- a/mysql-test/r/locktrans_innodb.result	2008-06-26 18:56:36 +0000
+++ b/mysql-test/r/locktrans_innodb.result	2008-10-22 16:33:23 +0000
@@ -95,12 +95,12 @@ ERROR 42000: You have an error in your S
 # Implicit lock method conversion due to mix in statement.
 LOCK TABLE t1 READ, t2 IN EXCLUSIVE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't2'
+Warning	1617	Converted to non-transactional lock on 't2'
 UNLOCK TABLES;
 # Lock t1 share (converted to read), t2 write.
 LOCK TABLE t1 IN SHARE MODE, t2 WRITE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't1'
+Warning	1617	Converted to non-transactional lock on 't1'
 # Show t1 is read locked, t2 write locked.
 INSERT INTO t1 SELECT * FROM t2;
 ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
@@ -111,8 +111,8 @@ INSERT INTO t2 SELECT * FROM t1;
 # Lock t1 exclusive (converted to write), t2 share (converted to read).
 LOCK TABLE t1 IN EXCLUSIVE MODE, t2 IN SHARE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't1'
-Warning	1615	Converted to non-transactional lock on 't2'
+Warning	1617	Converted to non-transactional lock on 't1'
+Warning	1617	Converted to non-transactional lock on 't2'
 # Show t1 is write locked, t2 read locked.
 INSERT INTO t1 SELECT * FROM t2;
 INSERT INTO t2 SELECT * FROM t1;
@@ -136,8 +136,8 @@ ERROR HY000: Cannot convert to non-trans
 ## Error is reported on first table only. Show both errors:
 SHOW WARNINGS;
 Level	Code	Message
-Error	1616	Cannot convert to non-transactional lock in strict mode on 't1'
-Error	1616	Cannot convert to non-transactional lock in strict mode on 't2'
+Error	1618	Cannot convert to non-transactional lock in strict mode on 't1'
+Error	1618	Cannot convert to non-transactional lock in strict mode on 't2'
 UNLOCK TABLES;
 SET @@SQL_MODE= @wl3561_save_sql_mode;
 #
@@ -157,7 +157,7 @@ CREATE TABLE t4 (c4 INT) ENGINE= MyISAM;
 # Request a transactional lock, which is converted to non-transactional.
 LOCK TABLE t4 IN SHARE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't4'
+Warning	1617	Converted to non-transactional lock on 't4'
 # Try a conflict with the existing non-transactional lock.
 INSERT INTO t4 VALUES(444);
 ERROR HY000: Table 't4' was locked with a READ lock and can't be updated
@@ -174,8 +174,8 @@ CREATE VIEW v1 AS SELECT * FROM t3, t4 W
 # Request a share lock on the view, which is converted to read locks.
 LOCK TABLE v1 IN SHARE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't3'
-Warning	1615	Converted to non-transactional lock on 't4'
+Warning	1617	Converted to non-transactional lock on 't3'
+Warning	1617	Converted to non-transactional lock on 't4'
 # Show that read locks on the base tables prohibit writing ...
 INSERT INTO t3 SELECT * FROM t4;
 ERROR HY000: Table 't3' was locked with a READ lock and can't be updated
@@ -191,7 +191,7 @@ COUNT(*)
 ## Report conversion on view due to existing non-transactional locks.
 LOCK TABLE v1 IN EXCLUSIVE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 'v1'
+Warning	1617	Converted to non-transactional lock on 'v1'
 INSERT INTO t3 VALUES(333);
 INSERT INTO t4 VALUES(444);
 INSERT INTO t1 VALUES(111);
@@ -200,8 +200,8 @@ UNLOCK TABLES;
 ## Now report conversion on base table again.
 LOCK TABLE v1 IN EXCLUSIVE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't3'
-Warning	1615	Converted to non-transactional lock on 't4'
+Warning	1617	Converted to non-transactional lock on 't3'
+Warning	1617	Converted to non-transactional lock on 't4'
 INSERT INTO t3 VALUES(333);
 INSERT INTO t4 VALUES(444);
 INSERT INTO t1 VALUES(111);

=== modified file 'mysql-test/r/locktrans_myisam.result'
--- a/mysql-test/r/locktrans_myisam.result	2008-06-26 18:56:36 +0000
+++ b/mysql-test/r/locktrans_myisam.result	2008-10-22 16:33:23 +0000
@@ -21,8 +21,8 @@ UNLOCK TABLES;
 # Valid syntax for transactional locks.
 LOCK TABLE t1 IN SHARE MODE, t2 IN EXCLUSIVE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't1'
-Warning	1615	Converted to non-transactional lock on 't2'
+Warning	1617	Converted to non-transactional lock on 't1'
+Warning	1617	Converted to non-transactional lock on 't2'
 UNLOCK TABLES;
 #
 # Valid syntax for aliases with and without 'AS'.
@@ -30,19 +30,19 @@ LOCK TABLE t1 AS a1 READ, t2 a2 WRITE;
 UNLOCK TABLES;
 LOCK TABLE t1 AS a1 IN SHARE MODE, t2 a2 IN EXCLUSIVE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 'a1'
-Warning	1615	Converted to non-transactional lock on 'a2'
+Warning	1617	Converted to non-transactional lock on 'a1'
+Warning	1617	Converted to non-transactional lock on 'a2'
 UNLOCK TABLES;
 #
 # Transactional locks taken on a view.
 CREATE VIEW v1 AS SELECT * FROM t1, t2 WHERE t1.c1 = t2.c2;
 LOCK TABLE v1 IN SHARE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't1'
-Warning	1615	Converted to non-transactional lock on 't2'
+Warning	1617	Converted to non-transactional lock on 't1'
+Warning	1617	Converted to non-transactional lock on 't2'
 LOCK TABLE v1 IN EXCLUSIVE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 'v1'
+Warning	1617	Converted to non-transactional lock on 'v1'
 UNLOCK TABLES;
 DROP VIEW v1;
 #
@@ -95,12 +95,12 @@ ERROR 42000: You have an error in your S
 # Implicit lock method conversion due to mix in statement.
 LOCK TABLE t1 READ, t2 IN EXCLUSIVE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't2'
+Warning	1617	Converted to non-transactional lock on 't2'
 UNLOCK TABLES;
 # Lock t1 share (converted to read), t2 write.
 LOCK TABLE t1 IN SHARE MODE, t2 WRITE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't1'
+Warning	1617	Converted to non-transactional lock on 't1'
 # Show t1 is read locked, t2 write locked.
 INSERT INTO t1 SELECT * FROM t2;
 ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
@@ -111,8 +111,8 @@ INSERT INTO t2 SELECT * FROM t1;
 # Lock t1 exclusive (converted to write), t2 share (converted to read).
 LOCK TABLE t1 IN EXCLUSIVE MODE, t2 IN SHARE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't1'
-Warning	1615	Converted to non-transactional lock on 't2'
+Warning	1617	Converted to non-transactional lock on 't1'
+Warning	1617	Converted to non-transactional lock on 't2'
 # Show t1 is write locked, t2 read locked.
 INSERT INTO t1 SELECT * FROM t2;
 INSERT INTO t2 SELECT * FROM t1;
@@ -136,8 +136,8 @@ ERROR HY000: Cannot convert to non-trans
 ## Error is reported on first table only. Show both errors:
 SHOW WARNINGS;
 Level	Code	Message
-Error	1616	Cannot convert to non-transactional lock in strict mode on 't1'
-Error	1616	Cannot convert to non-transactional lock in strict mode on 't2'
+Error	1618	Cannot convert to non-transactional lock in strict mode on 't1'
+Error	1618	Cannot convert to non-transactional lock in strict mode on 't2'
 UNLOCK TABLES;
 SET @@SQL_MODE= @wl3561_save_sql_mode;
 #
@@ -157,7 +157,7 @@ CREATE TABLE t4 (c4 INT) ENGINE= MyISAM;
 # Request a transactional lock, which is converted to non-transactional.
 LOCK TABLE t4 IN SHARE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't4'
+Warning	1617	Converted to non-transactional lock on 't4'
 # Try a conflict with the existing non-transactional lock.
 INSERT INTO t4 VALUES(444);
 ERROR HY000: Table 't4' was locked with a READ lock and can't be updated
@@ -174,8 +174,8 @@ CREATE VIEW v1 AS SELECT * FROM t3, t4 W
 # Request a share lock on the view, which is converted to read locks.
 LOCK TABLE v1 IN SHARE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't3'
-Warning	1615	Converted to non-transactional lock on 't4'
+Warning	1617	Converted to non-transactional lock on 't3'
+Warning	1617	Converted to non-transactional lock on 't4'
 # Show that read locks on the base tables prohibit writing ...
 INSERT INTO t3 SELECT * FROM t4;
 ERROR HY000: Table 't3' was locked with a READ lock and can't be updated
@@ -191,7 +191,7 @@ COUNT(*)
 ## Report conversion on view due to existing non-transactional locks.
 LOCK TABLE v1 IN EXCLUSIVE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 'v1'
+Warning	1617	Converted to non-transactional lock on 'v1'
 INSERT INTO t3 VALUES(333);
 INSERT INTO t4 VALUES(444);
 INSERT INTO t1 VALUES(111);
@@ -200,8 +200,8 @@ UNLOCK TABLES;
 ## Now report conversion on base table again.
 LOCK TABLE v1 IN EXCLUSIVE MODE;
 Warnings:
-Warning	1615	Converted to non-transactional lock on 't3'
-Warning	1615	Converted to non-transactional lock on 't4'
+Warning	1617	Converted to non-transactional lock on 't3'
+Warning	1617	Converted to non-transactional lock on 't4'
 INSERT INTO t3 VALUES(333);
 INSERT INTO t4 VALUES(444);
 INSERT INTO t1 VALUES(111);

=== modified file 'mysql-test/r/xa.result'
--- a/mysql-test/r/xa.result	2005-10-05 17:58:16 +0000
+++ b/mysql-test/r/xa.result	2008-10-21 21:02:26 +0000
@@ -55,3 +55,23 @@ select * from t1;
 a
 20
 drop table t1;
+drop table if exists t1;
+create table t1(a int, b int, c varchar(20), primary key(a)) engine = innodb;
+insert into t1 values(1, 1, 'a');
+insert into t1 values(2, 2, 'b');
+xa start 'a','b';
+update t1 set c = 'aa' where a = 1;
+xa start 'a','c';
+update t1 set c = 'bb' where a = 2;
+update t1 set c = 'bb' where a = 2;
+update t1 set c = 'aa' where a = 1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+select count(*) from t1;
+count(*)
+2
+xa end 'a','c';
+ERROR XA102: XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected
+xa rollback 'a','c';
+xa start 'a','c';
+drop table t1;
+End of 5.0 tests

=== modified file 'mysql-test/t/xa.test'
--- a/mysql-test/t/xa.test	2007-02-26 10:49:24 +0000
+++ b/mysql-test/t/xa.test	2008-10-21 21:02:26 +0000
@@ -74,3 +74,48 @@ xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
 select * from t1;
 drop table t1;
 
+disconnect con1;
+
+#
+# Bug#28323: Server crashed in xid cache operations
+#
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1(a int, b int, c varchar(20), primary key(a)) engine = innodb;
+insert into t1 values(1, 1, 'a');
+insert into t1 values(2, 2, 'b');
+
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+
+--connection con1
+xa start 'a','b';
+update t1 set c = 'aa' where a = 1;
+--connection con2
+xa start 'a','c';
+update t1 set c = 'bb' where a = 2;
+--connection con1
+--send update t1 set c = 'bb' where a = 2
+--connection con2
+--sleep 1
+--error ER_LOCK_DEADLOCK
+update t1 set c = 'aa' where a = 1;
+select count(*) from t1;
+--error ER_XA_RBDEADLOCK
+xa end 'a','c';
+xa rollback 'a','c';
+--disconnect con2
+
+connect (con3,localhost,root,,);
+--connection con3
+xa start 'a','c';
+
+--disconnect con1
+--disconnect con3
+--connection default
+drop table t1;
+
+--echo End of 5.0 tests

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2008-10-08 13:55:20 +0000
+++ b/sql/handler.cc	2008-10-22 16:33:23 +0000
@@ -1288,7 +1288,12 @@ int ha_rollback_trans(THD *thd, bool all
     trans->ha_list= 0;
     trans->no_2pc=0;
     if (is_real_trans)
-      thd->transaction.xid_state.xid.null();
+    {
+      if (thd->transaction_rollback_request)
+        thd->transaction.xid_state.rm_error= thd->main_da.sql_errno();
+      else
+        thd->transaction.xid_state.xid.null();
+    }
     if (all)
     {
       thd->variables.tx_isolation=thd->session_tx_isolation;

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2008-09-03 12:39:48 +0000
+++ b/sql/share/errmsg.txt	2008-10-22 16:33:23 +0000
@@ -6128,6 +6128,12 @@ ER_LOAD_DATA_INVALID_COLUMN
 ER_LOG_PURGE_NO_FILE  
 	eng "Being purged log %s was not found"
 
+ER_XA_RBTIMEOUT XA106
+	eng "XA_RBTIMEOUT: Transaction branch was rolled back: took too long"
+
+ER_XA_RBDEADLOCK XA102
+	eng "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected"
+
 ER_NEED_REPREPARE
   eng "Prepared statement needs to be re-prepared"
 

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2008-10-09 12:48:49 +0000
+++ b/sql/sql_class.h	2008-10-22 16:33:23 +0000
@@ -794,7 +794,7 @@ struct st_savepoint {
   Ha_trx_info         *ha_list;
 };
 
-enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED};
+enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY};
 extern const char *xa_state_names[];
 
 typedef struct st_xid_state {
@@ -802,6 +802,8 @@ typedef struct st_xid_state {
   XID  xid;                           // transaction identifier
   enum xa_states xa_state;            // used by external XA only
   bool in_thd;
+  /* Error reported by the Resource Manager (RM) to the Transaction Manager. */
+  uint rm_error;
 } XID_STATE;
 
 extern pthread_mutex_t LOCK_xid_cache;

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2008-10-08 11:46:49 +0000
+++ b/sql/sql_parse.cc	2008-10-22 16:33:23 +0000
@@ -94,7 +94,7 @@ const LEX_STRING command_name[]={
 };
 
 const char *xa_state_names[]={
-  "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
+  "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY"
 };
 
 extern DDL_blocker_class *DDL_blocker;

=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc	2008-09-23 14:33:18 +0000
+++ b/sql/transaction.cc	2008-10-22 16:33:23 +0000
@@ -44,6 +44,38 @@ static bool trans_check(THD *thd)
 
 
 /**
+  Mark a XA transaction as rollback-only if the RM unilaterally
+  rolled back the transaction branch.
+
+  @note If a rollback was requested by the RM, this function sets
+        the appropriate rollback error code and transits the state
+        to XA_ROLLBACK_ONLY.
+
+  @return TRUE if transaction was rolled back or if the transaction
+          state is XA_ROLLBACK_ONLY. FALSE otherwise.
+*/
+static bool xa_trans_rolled_back(XID_STATE *xid_state)
+{
+  if (xid_state->rm_error)
+  {
+    switch (xid_state->rm_error) {
+    case ER_LOCK_WAIT_TIMEOUT:
+      my_error(ER_XA_RBTIMEOUT, MYF(0));
+      break;
+    case ER_LOCK_DEADLOCK:
+      my_error(ER_XA_RBDEADLOCK, MYF(0));
+      break;
+    default:
+      my_error(ER_XA_RBROLLBACK, MYF(0));
+    }
+    xid_state->xa_state= XA_ROLLBACK_ONLY;
+  }
+
+  return (xid_state->xa_state == XA_ROLLBACK_ONLY);
+}
+
+
+/**
   Begin a new transaction.
 
   @note Beginning a transaction implicitly commits any current
@@ -229,7 +261,6 @@ bool trans_rollback_stmt(THD *thd)
 
   if (thd->transaction.stmt.ha_list)
   {
-    thd->transaction_rollback_request= FALSE;
     ha_rollback_trans(thd, FALSE);
     if (thd->transaction_rollback_request && !thd->in_sub_stmt)
       ha_rollback_trans(thd, TRUE);
@@ -426,6 +457,7 @@ bool trans_xa_start(THD *thd)
   {
     DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
     thd->transaction.xid_state.xa_state= XA_ACTIVE;
+    thd->transaction.xid_state.rm_error= 0;
     thd->transaction.xid_state.xid.set(thd->lex->xid);
     xid_cache_insert(&thd->transaction.xid_state);
     DBUG_RETURN(FALSE);
@@ -456,7 +488,7 @@ bool trans_xa_end(THD *thd)
              xa_state_names[thd->transaction.xid_state.xa_state]);
   else if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
     my_error(ER_XAER_NOTA, MYF(0));
-  else
+  else if (!xa_trans_rolled_back(&thd->transaction.xid_state))
     thd->transaction.xid_state.xa_state= XA_IDLE;
 
   DBUG_RETURN(thd->transaction.xid_state.xa_state != XA_IDLE);
@@ -512,18 +544,24 @@ bool trans_xa_commit(THD *thd)
   if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
   {
     XID_STATE *xs= xid_cache_search(thd->lex->xid);
-    bool not_found= !xs || xs->in_thd;
-    if (not_found)
+    res= !xs || xs->in_thd;
+    if (res)
       my_error(ER_XAER_NOTA, MYF(0));
     else
     {
-      ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
+      res= xa_trans_rolled_back(xs);
+      ha_commit_or_rollback_by_xid(thd->lex->xid, !res);
       xid_cache_delete(xs);
     }
-    DBUG_RETURN(not_found);
+    DBUG_RETURN(res);
   }
 
-  if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
+  if (xa_trans_rolled_back(&thd->transaction.xid_state))
+  {
+    if ((res= test(ha_rollback_trans(thd, TRUE))))
+      my_error(ER_XAER_RMERR, MYF(0));
+  }
+  else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
   {
     int r= ha_commit_trans(thd, TRUE);
     if ((res= test(r)))
@@ -545,7 +583,10 @@ bool trans_xa_commit(THD *thd)
     }
   }
   else
+  {
     my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+    DBUG_RETURN(TRUE);
+  }
 
   thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
   thd->transaction.all.modified_non_trans_table= FALSE;
@@ -575,18 +616,18 @@ bool trans_xa_rollback(THD *thd)
   if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
   {
     XID_STATE *xs= xid_cache_search(thd->lex->xid);
-    bool not_found= !xs || xs->in_thd;
-    if (not_found)
+    if (!xs || xs->in_thd)
       my_error(ER_XAER_NOTA, MYF(0));
     else
     {
+      xa_trans_rolled_back(xs);
       ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
       xid_cache_delete(xs);
     }
-    DBUG_RETURN(not_found);
+    DBUG_RETURN(thd->main_da.is_error());
   }
 
-  if (xa_state != XA_IDLE && xa_state != XA_PREPARED)
+  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]);
     DBUG_RETURN(TRUE);

Thread
bzr push into mysql-6.0 branch (davi:2876 to 2877) Bug#28323Davi Arnaut22 Oct