summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/xa.result4
-rw-r--r--mysql-test/t/xa.test4
-rw-r--r--sql/ha_innodb.cc2
-rw-r--r--sql/handler.cc63
-rw-r--r--sql/handler.h9
-rw-r--r--sql/mysqld.cc6
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_class.cc89
-rw-r--r--sql/sql_class.h43
-rw-r--r--sql/sql_parse.cc80
11 files changed, 211 insertions, 93 deletions
diff --git a/mysql-test/r/xa.result b/mysql-test/r/xa.result
index 1dde495d6ae..f3d7e151628 100644
--- a/mysql-test/r/xa.result
+++ b/mysql-test/r/xa.result
@@ -22,6 +22,8 @@ a
xa start 'testa','testb';
insert t1 values (30);
xa end 'testa','testb';
+xa start 'testa','testb';
+ERROR XAE08: XAER_DUPID: The XID already exists
xa start 0x7465737462, 0x2030405060, 0xb;
insert t1 values (40);
xa end 'testb',' 0@P`',11;
@@ -35,11 +37,11 @@ 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
xa rollback 'testa','testb';
xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
select * from t1;
a
20
-40
drop table t1;
diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test
index 321e5008035..aa921516110 100644
--- a/mysql-test/t/xa.test
+++ b/mysql-test/t/xa.test
@@ -31,6 +31,9 @@ xa end 'testa','testb';
connect (con1,localhost,,,);
connection con1;
+--error 1438
+xa start 'testa','testb';
+
# gtrid [ , bqual [ , formatID ] ]
xa start 0x7465737462, 0x2030405060, 0xb;
insert t1 values (40);
@@ -47,6 +50,7 @@ xa prepare 'testa','testb';
xa recover;
+--error 1397
xa commit 'testb',0x2030405060,11;
xa rollback 'testa','testb';
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 8dd45c03350..4aeeb954e17 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -7037,7 +7037,7 @@ innobase_xa_prepare(
return(0);
}
- trx->xid=thd->transaction.xid;
+ trx->xid=thd->transaction.xid_state.xid;
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex, we have to release the search system latch
diff --git a/sql/handler.cc b/sql/handler.cc
index 5a8762a615e..0b247f83af1 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -547,8 +547,8 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
trans->ht[trans->nht++]=ht_arg;
DBUG_ASSERT(*ht == ht_arg);
trans->no_2pc|=(ht_arg->prepare==0);
- if (thd->transaction.xid.is_null())
- thd->transaction.xid.set(thd->query_id);
+ if (thd->transaction.xid_state.xid.is_null())
+ thd->transaction.xid_state.xid.set(thd->query_id);
DBUG_VOID_RETURN;
}
@@ -595,7 +595,7 @@ int ha_commit_trans(THD *thd, bool all)
THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt;
bool is_real_trans= all || thd->transaction.all.nht == 0;
handlerton **ht= trans->ht;
- my_xid xid= thd->transaction.xid.get_my_xid();
+ my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
DBUG_ENTER("ha_commit_trans");
if (thd->in_sub_stmt)
@@ -695,7 +695,7 @@ int ha_commit_one_phase(THD *thd, bool all)
trans->nht=0;
trans->no_2pc=0;
if (is_real_trans)
- thd->transaction.xid.null();
+ thd->transaction.xid_state.xid.null();
if (all)
{
#ifdef HAVE_QUERY_CACHE
@@ -751,7 +751,7 @@ int ha_rollback_trans(THD *thd, bool all)
trans->nht=0;
trans->no_2pc=0;
if (is_real_trans)
- thd->transaction.xid.null();
+ thd->transaction.xid_state.xid.null();
if (all)
{
thd->variables.tx_isolation=thd->session_tx_isolation;
@@ -945,6 +945,7 @@ int ha_recover(HASH *commit_list)
char buf[XIDDATASIZE*4+6]; // see xid_to_str
sql_print_information("ignore xid %s", xid_to_str(buf, list+i));
#endif
+ xid_cache_insert(list+i, XA_PREPARED);
found_foreign_xids++;
continue;
}
@@ -1008,10 +1009,8 @@ bool mysql_xa_recover(THD *thd)
{
List<Item> field_list;
Protocol *protocol= thd->protocol;
- handlerton **ht= handlertons, **end_ht=ht+total_ha;
- bool error=TRUE;
- int len, got;
- XID *list=0;
+ int i=0;
+ XID_STATE *xs;
DBUG_ENTER("mysql_xa_recover");
field_list.push_back(new Item_int("formatID",0,11));
@@ -1021,48 +1020,30 @@ bool mysql_xa_recover(THD *thd)
if (protocol->send_fields(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
- DBUG_RETURN(TRUE);
-
- for (len= MAX_XID_LIST_SIZE ; list==0 && len > MIN_XID_LIST_SIZE; len/=2)
- {
- list=(XID *)my_malloc(len*sizeof(XID), MYF(0));
- }
- if (!list)
- {
- my_error(ER_OUTOFMEMORY, MYF(0), len);
DBUG_RETURN(1);
- }
- for ( ; ht < end_ht ; ht++)
+ pthread_mutex_lock(&LOCK_xid_cache);
+ while (xs=(XID_STATE*)hash_element(&xid_cache, i++))
{
- if (!(*ht)->recover)
- continue;
- while ((got=(*(*ht)->recover)(list, len)) > 0 )
+ if (xs->xa_state==XA_PREPARED)
{
- XID *xid, *end;
- for (xid=list, end=list+got; xid < end; xid++)
+ protocol->prepare_for_resend();
+ protocol->store_longlong((longlong)xs->xid.formatID, FALSE);
+ protocol->store_longlong((longlong)xs->xid.gtrid_length, FALSE);
+ protocol->store_longlong((longlong)xs->xid.bqual_length, FALSE);
+ protocol->store(xs->xid.data, xs->xid.gtrid_length+xs->xid.bqual_length,
+ &my_charset_bin);
+ if (protocol->write())
{
- if (xid->get_my_xid())
- continue; // skip "our" xids
- protocol->prepare_for_resend();
- protocol->store_longlong((longlong)xid->formatID, FALSE);
- protocol->store_longlong((longlong)xid->gtrid_length, FALSE);
- protocol->store_longlong((longlong)xid->bqual_length, FALSE);
- protocol->store(xid->data, xid->gtrid_length+xid->bqual_length,
- &my_charset_bin);
- if (protocol->write())
- goto err;
+ pthread_mutex_unlock(&LOCK_xid_cache);
+ DBUG_RETURN(1);
}
- if (got < len)
- break;
}
}
- error=FALSE;
+ pthread_mutex_unlock(&LOCK_xid_cache);
send_eof(thd);
-err:
- my_free((gptr)list, MYF(0));
- DBUG_RETURN(error);
+ DBUG_RETURN(0);
}
/*
diff --git a/sql/handler.h b/sql/handler.h
index 276f50bde63..ef45676207b 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -227,11 +227,11 @@ struct xid_t {
char data[XIDDATASIZE]; // not \0-terminated !
bool eq(struct xid_t *xid)
- { return !memcmp(this, xid, sizeof(long)*3+gtrid_length+bqual_length); }
+ { return !memcmp(this, xid, length()); }
bool eq(long g, long b, const char *d)
{ return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
void set(struct xid_t *xid)
- { memcpy(this, xid, sizeof(long)*3+xid->gtrid_length+xid->bqual_length); }
+ { memcpy(this, xid, xid->length()); }
void set(long f, const char *g, long gl, const char *b, long bl)
{
formatID= f;
@@ -270,6 +270,11 @@ struct xid_t {
!memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ?
quick_get_my_xid() : 0;
}
+ uint length()
+ {
+ return sizeof(formatID)+sizeof(gtrid_length)+sizeof(bqual_length)+
+ gtrid_length+bqual_length;
+ }
};
typedef struct xid_t XID;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index f8bfcb75be2..73080959c44 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1050,6 +1050,7 @@ void clean_up(bool print_message)
(void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */
if (tc_log)
tc_log->close();
+ xid_cache_free();
delete_elements(&key_caches, (void (*)(const char*, gptr)) free_key_cache);
multi_keycache_free();
end_thr_alarm(1); /* Free allocated memory */
@@ -2920,6 +2921,11 @@ server.");
using_update_log=1;
}
+ if (xid_cache_init())
+ {
+ sql_print_error("Out of memory");
+ unireg_abort(1);
+ }
if (ha_init())
{
sql_print_error("Can't init databases");
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 5dd5cd9c775..a987e0fd82d 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5388,3 +5388,5 @@ ER_STACK_OVERRUN_NEED_MORE
eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld -O thread_stack=#' to specify a bigger stack."
ER_TOO_LONG_BODY 42000 S1009
eng "Routine body for '%-.100s' is too long"
+ER_XAER_DUPID XAE08
+ eng "XAER_DUPID: The XID already exists"
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 5ff5e580f81..0836274b704 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -502,7 +502,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
*/
bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
if (!thd->active_transaction())
- thd->transaction.xid.null();
+ thd->transaction.xid_state.xid.null();
/* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */
if (!lock_in_use)
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 56d3194765b..fd972423bc6 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -323,7 +323,8 @@ void THD::init_for_queries()
variables.trans_alloc_block_size,
variables.trans_prealloc_size);
#endif
- transaction.xid.null();
+ transaction.xid_state.xid.null();
+ transaction.xid_state.in_thd=1;
}
@@ -358,9 +359,15 @@ void THD::cleanup(void)
{
DBUG_ENTER("THD::cleanup");
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
- if (transaction.xa_state != XA_PREPARED)
+ if (transaction.xid_state.xa_state == XA_PREPARED)
+ {
+#error xid_state in the cache should be replaced by the allocated value
+ }
#endif
+ {
ha_rollback(this);
+ xid_cache_delete(&transaction.xid_state);
+ }
if (locked_tables)
{
lock=locked_tables; locked_tables=0;
@@ -1841,3 +1848,81 @@ void THD::pop_open_tables_state()
set_open_tables_state(state);
DBUG_VOID_RETURN;
}
+
+pthread_mutex_t LOCK_xid_cache;
+HASH xid_cache;
+
+static byte *xid_get_hash_key(const byte *ptr,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=((XID_STATE*)ptr)->xid.length();
+ return (byte *)&((XID_STATE*)ptr)->xid;
+}
+
+static void xid_free_hash (void *ptr)
+{
+ if (!((XID_STATE*)ptr)->in_thd)
+ my_free((byte *)ptr, MYF(0));
+}
+
+bool xid_cache_init()
+{
+ pthread_mutex_init(&LOCK_xid_cache, MY_MUTEX_INIT_FAST);
+ hash_init(&xid_cache, &my_charset_bin, 100, 0, 0,
+ xid_get_hash_key, xid_free_hash, 0) != 0;
+}
+
+void xid_cache_free()
+{
+ if (hash_inited(&xid_cache))
+ {
+ hash_free(&xid_cache);
+ pthread_mutex_destroy(&LOCK_xid_cache);
+ }
+}
+
+XID_STATE *xid_cache_search(XID *xid)
+{
+ pthread_mutex_lock(&LOCK_xid_cache);
+ XID_STATE *res=(XID_STATE *)hash_search(&xid_cache, (byte *)xid, xid->length());
+ pthread_mutex_unlock(&LOCK_xid_cache);
+ return res;
+}
+
+bool xid_cache_insert(XID *xid, enum xa_states xa_state)
+{
+ XID_STATE *xs;
+ my_bool res;
+ pthread_mutex_lock(&LOCK_xid_cache);
+ if (hash_search(&xid_cache, (byte *)xid, xid->length()))
+ res=0;
+ else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME))))
+ res=1;
+ else
+ {
+ xs->xa_state=xa_state;
+ xs->xid.set(xid);
+ xs->in_thd=0;
+ res=my_hash_insert(&xid_cache, (byte*)xs);
+ }
+ pthread_mutex_unlock(&LOCK_xid_cache);
+ return res;
+}
+
+bool xid_cache_insert(XID_STATE *xid_state)
+{
+ pthread_mutex_lock(&LOCK_xid_cache);
+ DBUG_ASSERT(hash_search(&xid_cache, (byte *)&xid_state->xid,
+ xid_state->xid.length())==0);
+ my_bool res=my_hash_insert(&xid_cache, (byte*)xid_state);
+ pthread_mutex_unlock(&LOCK_xid_cache);
+ return res;
+}
+
+void xid_cache_delete(XID_STATE *xid_state)
+{
+ pthread_mutex_lock(&LOCK_xid_cache);
+ hash_delete(&xid_cache, (byte *)xid_state);
+ pthread_mutex_unlock(&LOCK_xid_cache);
+}
+
diff --git a/sql/sql_class.h b/sql/sql_class.h
index ad4f38946a3..c1ac2990331 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -351,8 +351,6 @@ public:
inline uint32 get_open_count() { return open_count; }
};
-/* character conversion tables */
-
typedef struct st_copy_info {
ha_rows records;
@@ -564,11 +562,11 @@ struct system_variables
my_bool ndb_use_transactions;
#endif /* HAVE_NDBCLUSTER_DB */
my_bool old_passwords;
-
+
/* Only charset part of these variables is sensible */
- CHARSET_INFO *character_set_client;
+ CHARSET_INFO *character_set_client;
CHARSET_INFO *character_set_results;
-
+
/* Both charset and collation parts of these variables are important */
CHARSET_INFO *collation_server;
CHARSET_INFO *collation_database;
@@ -631,7 +629,7 @@ typedef struct system_status_var
ulong filesort_range_count;
ulong filesort_rows;
ulong filesort_scan_count;
- /* Ppepared statements and binary protocol */
+ /* Prepared statements and binary protocol */
ulong com_stmt_prepare;
ulong com_stmt_execute;
ulong com_stmt_send_long_data;
@@ -656,8 +654,8 @@ void free_tmp_table(THD *thd, TABLE *entry);
/* The following macro is to make init of Query_arena simpler */
#ifndef DBUG_OFF
#define INIT_ARENA_DBUG_INFO is_backup_arena= 0
-#else
-#define INIT_ARENA_DBUG_INFO
+#else
+#define INIT_ARENA_DBUG_INFO
#endif
@@ -925,6 +923,22 @@ struct st_savepoint {
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED};
extern const char *xa_state_names[];
+typedef struct st_xid_state {
+ /* For now, this is only used to catch duplicated external xids */
+ XID xid; // transaction identifier
+ enum xa_states xa_state; // used by external XA only
+ bool in_thd;
+} XID_STATE;
+
+extern pthread_mutex_t LOCK_xid_cache;
+extern HASH xid_cache;
+bool xid_cache_init(void);
+void xid_cache_free(void);
+XID_STATE *xid_cache_search(XID *xid);
+bool xid_cache_insert(XID *xid, enum xa_states xa_state);
+bool xid_cache_insert(XID_STATE *xid_state);
+void xid_cache_delete(XID_STATE *xid_state);
+
/*
A registry for item tree transformations performed during
query optimization. We register only those changes which require
@@ -946,7 +960,7 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
/*
- Class that holds information about tables which were open and locked
+ Class that holds information about tables which were opened and locked
by the thread. It is also used to save/restore this information in
push_open_tables_state()/pop_open_tables_state().
*/
@@ -1062,7 +1076,7 @@ public:
// the lock_id of a cursor.
pthread_mutex_t LOCK_delete; // Locked before thd is deleted
/* all prepared statements and cursors of this connection */
- Statement_map stmt_map;
+ Statement_map stmt_map;
/*
A pointer to the stack frame of handle_one_connection(),
which is called first in the thread for handling a client
@@ -1132,10 +1146,10 @@ public:
thr_lock_type update_lock_default;
delayed_insert *di;
my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */
-
+
/* TRUE if we are inside of trigger or stored function. */
bool in_sub_stmt;
-
+
/* container for handler's private per-connection data */
void *ha_data[MAX_HA];
struct st_transactions {
@@ -1143,8 +1157,7 @@ public:
THD_TRANS all; // Trans since BEGIN WORK
THD_TRANS stmt; // Trans for current statement
bool on; // see ha_enable_transaction()
- XID xid; // transaction identifier
- enum xa_states xa_state; // used by external XA only
+ XID_STATE xid_state;
/*
Tables changed in transaction (that must be invalidated in query cache).
List contain only transactional tables, that not invalidated in query
@@ -1164,7 +1177,7 @@ public:
st_transactions()
{
bzero((char*)this, sizeof(*this));
- xid.null();
+ xid_state.xid.null();
init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
}
#endif
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 677b3a98174..1d7d1637ff7 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2017,7 +2017,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*/
bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
if (!thd->active_transaction())
- thd->transaction.xid.null();
+ thd->transaction.xid_state.xid.null();
/* report error issued during command execution */
if (thd->killed_errno() && !thd->net.report_error)
@@ -4502,14 +4502,15 @@ end_with_restore_list:
break;
}
case SQLCOM_XA_START:
- if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
+ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
+ thd->lex->xa_opt == XA_RESUME)
{
- if (! thd->transaction.xid.eq(thd->lex->xid))
+ if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
my_error(ER_XAER_NOTA, MYF(0));
break;
}
- thd->transaction.xa_state=XA_ACTIVE;
+ thd->transaction.xid_state.xa_state=XA_ACTIVE;
send_ok(thd);
break;
}
@@ -4518,10 +4519,10 @@ end_with_restore_list:
my_error(ER_XAER_INVAL, MYF(0));
break;
}
- if (thd->transaction.xa_state != XA_NOTR)
+ if (thd->transaction.xid_state.xa_state != XA_NOTR)
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
if (thd->active_transaction() || thd->locked_tables)
@@ -4529,9 +4530,15 @@ end_with_restore_list:
my_error(ER_XAER_OUTSIDE, MYF(0));
break;
}
- DBUG_ASSERT(thd->transaction.xid.is_null());
- thd->transaction.xa_state=XA_ACTIVE;
- thd->transaction.xid.set(thd->lex->xid);
+ if (xid_cache_search(thd->lex->xid))
+ {
+ my_error(ER_XAER_DUPID, MYF(0));
+ break;
+ }
+ DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
+ thd->transaction.xid_state.xa_state=XA_ACTIVE;
+ thd->transaction.xid_state.xid.set(thd->lex->xid);
+ xid_cache_insert(&thd->transaction.xid_state);
thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
@@ -4544,28 +4551,28 @@ end_with_restore_list:
my_error(ER_XAER_INVAL, MYF(0));
break;
}
- if (thd->transaction.xa_state != XA_ACTIVE)
+ if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
- if (!thd->transaction.xid.eq(thd->lex->xid))
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
my_error(ER_XAER_NOTA, MYF(0));
break;
}
- thd->transaction.xa_state=XA_IDLE;
+ thd->transaction.xid_state.xa_state=XA_IDLE;
send_ok(thd);
break;
case SQLCOM_XA_PREPARE:
- if (thd->transaction.xa_state != XA_IDLE)
+ if (thd->transaction.xid_state.xa_state != XA_IDLE)
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
- if (!thd->transaction.xid.eq(thd->lex->xid))
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
my_error(ER_XAER_NOTA, MYF(0));
break;
@@ -4573,22 +4580,28 @@ end_with_restore_list:
if (ha_prepare(thd))
{
my_error(ER_XA_RBROLLBACK, MYF(0));
- thd->transaction.xa_state=XA_NOTR;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state=XA_NOTR;
break;
}
- thd->transaction.xa_state=XA_PREPARED;
+ thd->transaction.xid_state.xa_state=XA_PREPARED;
send_ok(thd);
break;
case SQLCOM_XA_COMMIT:
- if (!thd->transaction.xid.eq(thd->lex->xid))
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
- if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 1)))
+ XID_STATE *xs=xid_cache_search(thd->lex->xid);
+ if (!xs || xs->in_thd)
my_error(ER_XAER_NOTA, MYF(0));
else
+ {
+ ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
+ xid_cache_delete(xs);
send_ok(thd);
+ }
break;
}
- if (thd->transaction.xa_state == XA_IDLE &&
+ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
thd->lex->xa_opt == XA_ONE_PHASE)
{
int r;
@@ -4597,7 +4610,7 @@ end_with_restore_list:
else
send_ok(thd);
}
- else if (thd->transaction.xa_state == XA_PREPARED &&
+ else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
thd->lex->xa_opt == XA_NONE)
{
if (wait_if_global_read_lock(thd, 0, 0))
@@ -4617,27 +4630,33 @@ end_with_restore_list:
else
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- thd->transaction.xa_state=XA_NOTR;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state=XA_NOTR;
break;
case SQLCOM_XA_ROLLBACK:
- if (!thd->transaction.xid.eq(thd->lex->xid))
+ if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
{
- if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 0)))
+ XID_STATE *xs=xid_cache_search(thd->lex->xid);
+ if (!xs || xs->in_thd)
my_error(ER_XAER_NOTA, MYF(0));
else
+ {
+ ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
+ xid_cache_delete(xs);
send_ok(thd);
+ }
break;
}
- if (thd->transaction.xa_state != XA_IDLE &&
- thd->transaction.xa_state != XA_PREPARED)
+ if (thd->transaction.xid_state.xa_state != XA_IDLE &&
+ thd->transaction.xid_state.xa_state != XA_PREPARED)
{
my_error(ER_XAER_RMFAIL, MYF(0),
- xa_state_names[thd->transaction.xa_state]);
+ xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
if (ha_rollback(thd))
@@ -4646,7 +4665,8 @@ end_with_restore_list:
send_ok(thd);
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- thd->transaction.xa_state=XA_NOTR;
+ xid_cache_delete(&thd->transaction.xid_state);
+ thd->transaction.xid_state.xa_state=XA_NOTR;
break;
case SQLCOM_XA_RECOVER:
res= mysql_xa_recover(thd);