2
Copyright (C) 2005 MySQL AB
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of version 2 of the GNU General Public License as
6
published by the Free Software Foundation.
8
There are special exceptions to the terms and conditions of the GPL
9
as it is applied to this software. View the full text of the
10
exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
11
software distribution.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program; if not, write to the Free Software
20
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
package testsuite.simple;
26
import java.io.ByteArrayOutputStream;
27
import java.io.DataOutputStream;
28
import java.io.IOException;
29
import java.rmi.server.UID;
30
import java.sql.Connection;
31
import java.sql.SQLException;
32
import java.sql.Savepoint;
34
import javax.sql.XAConnection;
35
import javax.transaction.xa.XAException;
36
import javax.transaction.xa.XAResource;
37
import javax.transaction.xa.Xid;
39
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
40
import com.mysql.jdbc.jdbc2.optional.MysqlXid;
42
import testsuite.BaseTestCase;
45
* Unit tests for our XA implementation.
49
public class XATest extends BaseTestCase {
50
MysqlXADataSource xaDs;
52
public XATest(String name) {
55
this.xaDs = new MysqlXADataSource();
56
this.xaDs.setUrl(BaseTestCase.dbUrl);
57
this.xaDs.setRollbackOnPooledClose(true);
61
* Tests that simple distributed transaction processing works as expected.
66
public void testCoordination() throws Exception {
67
if (!versionMeetsMinimum(5, 0)) {
71
createTable("testCoordination", "(field1 int) ENGINE=InnoDB");
73
Connection conn1 = null;
74
Connection conn2 = null;
75
XAConnection xaConn1 = null;
76
XAConnection xaConn2 = null;
79
xaConn1 = getXAConnection();
80
XAResource xaRes1 = xaConn1.getXAResource();
81
conn1 = xaConn1.getConnection();
83
xaConn2 = getXAConnection();
84
XAResource xaRes2 = xaConn2.getXAResource();
85
conn2 = xaConn2.getConnection();
87
Xid xid1 = createXid();
88
Xid xid2 = createXid(xid1);
90
xaRes1.start(xid1, XAResource.TMNOFLAGS);
91
xaRes2.start(xid2, XAResource.TMNOFLAGS);
92
conn1.createStatement().executeUpdate("INSERT INTO testCoordination VALUES (1)");
93
conn2.createStatement().executeUpdate("INSERT INTO testCoordination VALUES (2)");
94
xaRes1.end(xid1, XAResource.TMSUCCESS);
95
xaRes2.end(xid2, XAResource.TMSUCCESS);
100
xaRes1.commit(xid1, false);
101
xaRes2.commit(xid2, false);
103
this.rs = this.stmt.executeQuery("SELECT field1 FROM testCoordination ORDER BY field1");
105
assertTrue(this.rs.next());
106
assertEquals(1, this.rs.getInt(1));
108
assertTrue(this.rs.next());
109
assertEquals(2, this.rs.getInt(1));
111
this.stmt.executeUpdate("TRUNCATE TABLE testCoordination");
118
xid2 = createXid(xid1);
120
xaRes1.start(xid1, XAResource.TMNOFLAGS);
121
xaRes2.start(xid2, XAResource.TMNOFLAGS);
122
conn1.createStatement().executeUpdate("INSERT INTO testCoordination VALUES (1)");
125
assertEquals("1", getSingleIndexedValueWithQuery(conn1, 1, "SELECT field1 FROM testCoordination WHERE field1=1").toString());
127
conn2.createStatement().executeUpdate("INSERT INTO testCoordination VALUES (2)");
130
assertEquals("2", getSingleIndexedValueWithQuery(conn2, 1, "SELECT field1 FROM testCoordination WHERE field1=2").toString());
132
xaRes1.end(xid1, XAResource.TMSUCCESS);
133
xaRes2.end(xid2, XAResource.TMSUCCESS);
135
xaRes1.prepare(xid1);
136
xaRes2.prepare(xid2);
138
xaRes1.rollback(xid1);
139
xaRes2.rollback(xid2);
141
this.rs = this.stmt.executeQuery("SELECT field1 FROM testCoordination ORDER BY field1");
143
assertTrue(!this.rs.next());
153
if (xaConn1 != null) {
157
if (xaConn2 != null) {
163
protected XAConnection getXAConnection() throws Exception {
164
return this.xaDs.getXAConnection();
168
* Tests that XA RECOVER works as expected.
173
public void testRecover() throws Exception {
174
if (!versionMeetsMinimum(5, 0)) {
178
XAConnection xaConn = null, recoverConn = null;
181
xaConn = getXAConnection();
183
Connection c = xaConn.getConnection();
184
Xid xid = createXid();
186
XAResource xaRes = xaConn.getXAResource();
187
xaRes.start(xid, XAResource.TMNOFLAGS);
188
c.createStatement().executeQuery("SELECT 1");
189
xaRes.end(xid, XAResource.TMSUCCESS);
192
// Now try and recover
193
recoverConn = getXAConnection();
195
XAResource recoverRes = recoverConn.getXAResource();
197
Xid[] recoveredXids = recoverRes.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN);
199
assertTrue(recoveredXids != null);
200
assertTrue(recoveredXids.length > 0);
202
boolean xidFound = false;
204
for (int i = 0; i < recoveredXids.length; i++) {
205
if (recoveredXids[i] != null &&
206
recoveredXids[i].equals(xid)) {
213
assertTrue(xidFound);
215
recoverRes = recoverConn.getXAResource();
217
recoveredXids = recoverRes.recover(XAResource.TMSTARTRSCAN);
219
assertTrue(recoveredXids != null);
220
assertTrue(recoveredXids.length > 0);
224
for (int i = 0; i < recoveredXids.length; i++) {
225
if (recoveredXids[i] != null &&
226
recoveredXids[i].equals(xid)) {
233
assertTrue(xidFound);
236
recoverRes.recover(XAResource.TMSTARTRSCAN);
237
recoverRes.recover(XAResource.TMENDRSCAN);
238
recoverRes.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN);
242
recoverRes.recover(XAResource.TMSUCCESS);
243
fail("XAException should have been thrown");
244
} catch (XAException xaEx) {
245
assertEquals(XAException.XAER_INVAL, xaEx.errorCode);
248
if (xaConn != null) {
252
if (recoverConn != null) {
259
* Tests operation of local transactions on XAConnections when global
260
* transactions are in or not in progress (follows from BUG#17401).
263
* if the testcase fails
265
public void testLocalTransaction() throws Exception {
267
if (!versionMeetsMinimum(5, 0) || isRunningOnJdk131()) {
271
createTable("testLocalTransaction", "(field1 int) ENGINE=InnoDB");
273
Connection conn1 = null;
275
XAConnection xaConn1 = null;
278
xaConn1 = getXAConnection();
279
XAResource xaRes1 = xaConn1.getXAResource();
280
conn1 = xaConn1.getConnection();
281
assertEquals(false, conn1.getAutoCommit());
282
conn1.setAutoCommit(true);
283
conn1.createStatement().executeUpdate(
284
"INSERT INTO testLocalTransaction VALUES (1)");
285
assertEquals("1", getSingleIndexedValueWithQuery(conn1, 1,
286
"SELECT field1 FROM testLocalTransaction").toString());
288
conn1.createStatement().executeUpdate(
289
"TRUNCATE TABLE testLocalTransaction");
290
conn1.setAutoCommit(false);
291
conn1.createStatement().executeUpdate(
292
"INSERT INTO testLocalTransaction VALUES (2)");
293
assertEquals("2", getSingleIndexedValueWithQuery(conn1, 1,
294
"SELECT field1 FROM testLocalTransaction").toString());
296
assertEquals(0, getRowCount("testLocalTransaction"));
298
conn1.createStatement().executeUpdate(
299
"INSERT INTO testLocalTransaction VALUES (3)");
300
assertEquals("3", getSingleIndexedValueWithQuery(conn1, 1,
301
"SELECT field1 FROM testLocalTransaction").toString());
303
assertEquals("3", getSingleIndexedValueWithQuery(conn1, 1,
304
"SELECT field1 FROM testLocalTransaction").toString());
307
Savepoint sp = conn1.setSavepoint();
309
sp = conn1.setSavepoint("abcd");
311
Savepoint spSaved = sp;
313
Xid xid = createXid();
314
xaRes1.start(xid, XAResource.TMNOFLAGS);
318
conn1.setAutoCommit(true);
319
} catch (SQLException sqlEx) {
320
// we expect an exception here
321
assertEquals("2D000", sqlEx.getSQLState());
326
} catch (SQLException sqlEx) {
327
// we expect an exception here
328
assertEquals("2D000", sqlEx.getSQLState());
333
} catch (SQLException sqlEx) {
334
// we expect an exception here
335
assertEquals("2D000", sqlEx.getSQLState());
339
sp = conn1.setSavepoint();
340
} catch (SQLException sqlEx) {
341
// we expect an exception here
342
assertEquals("2D000", sqlEx.getSQLState());
346
conn1.rollback(spSaved);
347
} catch (SQLException sqlEx) {
348
// we expect an exception here
349
assertEquals("2D000", sqlEx.getSQLState());
353
sp = conn1.setSavepoint("abcd");
354
} catch (SQLException sqlEx) {
355
// we expect an exception here
356
assertEquals("2D000", sqlEx.getSQLState());
360
conn1.rollback(spSaved);
361
} catch (SQLException sqlEx) {
362
// we expect an exception here
363
assertEquals("2D000", sqlEx.getSQLState());
369
if (xaConn1 != null) {
375
public void testSuspendableTx() throws Exception {
376
if (!versionMeetsMinimum(5, 0) || isRunningOnJdk131()) {
380
Connection conn1 = null;
382
MysqlXADataSource suspXaDs = new MysqlXADataSource();
383
suspXaDs.setUrl(BaseTestCase.dbUrl);
384
suspXaDs.setPinGlobalTxToPhysicalConnection(true);
385
suspXaDs.setRollbackOnPooledClose(true);
387
XAConnection xaConn1 = null;
389
Xid xid = createXid();
393
-- works using RESUME
394
xa start 0x123,0x456;
397
xa start 0x123,0x456 resume;
400
xa commit 0x123,0x456 one phase;
403
xaConn1 = suspXaDs.getXAConnection();
404
XAResource xaRes1 = xaConn1.getXAResource();
405
conn1 = xaConn1.getConnection();
406
xaRes1.start(xid, XAResource.TMNOFLAGS);
407
conn1.createStatement().executeQuery("SELECT 1");
408
xaRes1.end(xid, XAResource.TMSUCCESS);
409
xaRes1.start(xid, XAResource.TMRESUME);
410
conn1.createStatement().executeQuery("SELECT 1");
411
xaRes1.end(xid, XAResource.TMSUCCESS);
412
xaRes1.commit(xid, true);
419
xa start 0x123,0x456;
422
xa start 0x123,0x456 join;
425
xa commit 0x123,0x456 one phase;
428
xaConn1 = suspXaDs.getXAConnection();
429
xaRes1 = xaConn1.getXAResource();
430
conn1 = xaConn1.getConnection();
431
xaRes1.start(xid, XAResource.TMNOFLAGS);
432
conn1.createStatement().executeQuery("SELECT 1");
433
xaRes1.end(xid, XAResource.TMSUCCESS);
434
xaRes1.start(xid, XAResource.TMJOIN);
435
conn1.createStatement().executeQuery("SELECT 1");
436
xaRes1.end(xid, XAResource.TMSUCCESS);
437
xaRes1.commit(xid, true);
439
if (xaConn1 != null) {
445
private Xid createXid() throws IOException {
446
ByteArrayOutputStream gtridOut = new ByteArrayOutputStream();
447
DataOutputStream dataOut = new DataOutputStream(gtridOut);
448
new UID().write(dataOut);
450
final byte[] gtrid = gtridOut.toByteArray();
452
ByteArrayOutputStream bqualOut = new ByteArrayOutputStream();
453
dataOut = new DataOutputStream(bqualOut);
455
new UID().write(dataOut);
457
final byte[] bqual = bqualOut.toByteArray();
459
Xid xid = new MysqlXid(gtrid, bqual, 3306);
463
private Xid createXid(Xid xidToBranch) throws IOException {
464
ByteArrayOutputStream bqualOut = new ByteArrayOutputStream();
465
DataOutputStream dataOut = new DataOutputStream(bqualOut);
467
new UID().write(dataOut);
469
final byte[] bqual = bqualOut.toByteArray();
471
Xid xid = new MysqlXid(xidToBranch.getGlobalTransactionId(), bqual, 3306);