Logo Search packages:      
Sourcecode: mysql-connector-java version File versions  Download package

XATest.java

/*
  Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.

  The MySQL Connector/J is licensed under the terms of the GPLv2
  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
  this software, see the FLOSS License Exception
  <http://www.mysql.com/about/legal/licensing/foss-exception.html>.

  This program is free software; you can redistribute it and/or modify it under the terms
  of the GNU General Public License as published by the Free Software Foundation; version 2
  of the License.

  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along with this
  program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
  Floor, Boston, MA 02110-1301  USA

*/

package testsuite.simple;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.rmi.server.UID;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Savepoint;

import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import testsuite.BaseTestCase;

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlXid;

/**
 * Unit tests for our XA implementation.
 * 
 * @version $Id: $
 */
00049 public class XATest extends BaseTestCase {
    MysqlXADataSource xaDs;
    
      public XATest(String name) {
            super(name);
            
            this.xaDs = new MysqlXADataSource();
            this.xaDs.setUrl(BaseTestCase.dbUrl);
            this.xaDs.setRollbackOnPooledClose(true);
      }

      /**
       * Tests that simple distributed transaction processing works as expected.
       * 
       * @throws Exception
       *             if the test fails.
       */
00066       public void testCoordination() throws Exception {
            if (!versionMeetsMinimum(5, 0)) {
                  return;
            }
            
            createTable("testCoordination", "(field1 int) ENGINE=InnoDB");
            
            Connection conn1 = null;
            Connection conn2 = null;
            XAConnection xaConn1 = null;
            XAConnection xaConn2 = null;
            
            try {
                  xaConn1 = getXAConnection();
                  XAResource xaRes1 = xaConn1.getXAResource();
                  conn1 = xaConn1.getConnection();
                  
                  xaConn2 = getXAConnection();
                  XAResource xaRes2 = xaConn2.getXAResource();
                  conn2 = xaConn2.getConnection();
                  
                  Xid xid1 = createXid();
                  Xid xid2 = createXid(xid1);
                  
                  xaRes1.start(xid1, XAResource.TMNOFLAGS);
                  xaRes2.start(xid2, XAResource.TMNOFLAGS);
                  conn1.createStatement().executeUpdate("INSERT INTO testCoordination VALUES (1)");
                  conn2.createStatement().executeUpdate("INSERT INTO testCoordination VALUES (2)");
                  xaRes1.end(xid1, XAResource.TMSUCCESS);
                  xaRes2.end(xid2, XAResource.TMSUCCESS);
                  
                  xaRes1.prepare(xid1);
                  xaRes2.prepare(xid2);
                  
                  xaRes1.commit(xid1, false);
                  xaRes2.commit(xid2, false);
                  
                  this.rs = this.stmt.executeQuery("SELECT field1 FROM testCoordination ORDER BY field1");
                  
                  assertTrue(this.rs.next());
                  assertEquals(1, this.rs.getInt(1));
                  
                  assertTrue(this.rs.next());
                  assertEquals(2, this.rs.getInt(1));
                  
                  this.stmt.executeUpdate("TRUNCATE TABLE testCoordination");
                  
                  //
                  // Now test rollback
                  //
                  
                  xid1 = createXid();
                  xid2 = createXid(xid1);
                  
                  xaRes1.start(xid1, XAResource.TMNOFLAGS);
                  xaRes2.start(xid2, XAResource.TMNOFLAGS);
                  conn1.createStatement().executeUpdate("INSERT INTO testCoordination VALUES (1)");
                  
                  // ensure visibility
                  assertEquals("1", getSingleIndexedValueWithQuery(conn1, 1, "SELECT field1 FROM testCoordination WHERE field1=1").toString());
                  
                  conn2.createStatement().executeUpdate("INSERT INTO testCoordination VALUES (2)");
                  
                  // ensure visibility
                  assertEquals("2", getSingleIndexedValueWithQuery(conn2, 1, "SELECT field1 FROM testCoordination WHERE field1=2").toString());
                  
                  xaRes1.end(xid1, XAResource.TMSUCCESS);
                  xaRes2.end(xid2, XAResource.TMSUCCESS);
                  
                  xaRes1.prepare(xid1);
                  xaRes2.prepare(xid2);
                  
                  xaRes1.rollback(xid1);
                  xaRes2.rollback(xid2);
                  
                  this.rs = this.stmt.executeQuery("SELECT field1 FROM testCoordination ORDER BY field1");
                  
                  assertTrue(!this.rs.next());
            } finally {
                  if (conn1 != null) {
                        conn1.close();
                  }
                  
                  if (conn2 != null) {
                        conn2.close();
                  }
                  
                  if (xaConn1 != null) {
                        xaConn1.close();
                  }
                  
                  if (xaConn2 != null) {
                        xaConn2.close();
                  }
            }
      }
      
      protected XAConnection getXAConnection() throws Exception {
            return this.xaDs.getXAConnection();
      }
      
      /**
       * Tests that XA RECOVER works as expected.
       * 
       * @throws Exception
       *             if test fails
       */
00173       public void testRecover() throws Exception {
            if (!versionMeetsMinimum(5, 0)) {
                  return;
            }

            XAConnection xaConn = null, recoverConn = null;
            
            try {             
                  xaConn = getXAConnection();
                  
                  Connection c = xaConn.getConnection();
                  Xid xid = createXid();
                  
                  XAResource xaRes = xaConn.getXAResource();
                  xaRes.start(xid, XAResource.TMNOFLAGS);
                  c.createStatement().executeQuery("SELECT 1");
                  xaRes.end(xid, XAResource.TMSUCCESS);
                  xaRes.prepare(xid);
                  
                  // Now try and recover
                  recoverConn = getXAConnection();
                  
                  XAResource recoverRes = recoverConn.getXAResource();
                  
                  Xid[] recoveredXids = recoverRes.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN);
                  
                  assertTrue(recoveredXids != null);
                  assertTrue(recoveredXids.length > 0);
                  
                  boolean xidFound = false;
                  
                  for (int i = 0; i < recoveredXids.length; i++) {
                        if (recoveredXids[i] != null &&
                              recoveredXids[i].equals(xid)) {
                              xidFound = true;
                              
                              break;
                        }
                  }
                  
                  assertTrue(xidFound);

                  recoverRes = recoverConn.getXAResource();

                  recoveredXids = recoverRes.recover(XAResource.TMSTARTRSCAN);

                  assertTrue(recoveredXids != null);
                  assertTrue(recoveredXids.length > 0);

                  xidFound = false;

                  for (int i = 0; i < recoveredXids.length; i++) {
                        if (recoveredXids[i] != null &&
                                    recoveredXids[i].equals(xid)) {
                              xidFound = true;

                              break;
                        }
                  }

                  assertTrue(xidFound);
                        
                  // Test flags
                  recoverRes.recover(XAResource.TMSTARTRSCAN);
                  recoverRes.recover(XAResource.TMENDRSCAN);
                  recoverRes.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN);
                  
                  // This should fail
                  try {
                        recoverRes.recover(XAResource.TMSUCCESS);
                        fail("XAException should have been thrown");
                  } catch (XAException xaEx) {
                        assertEquals(XAException.XAER_INVAL, xaEx.errorCode);
                  }
            } finally {
                  if (xaConn != null) {
                        xaConn.close();
                  }
                  
                  if (recoverConn != null) {
                        recoverConn.close();
                  }
            }
      }

      /**
       * Tests operation of local transactions on XAConnections when global
       * transactions are in or not in progress (follows from BUG#17401).
       * 
       * @throws Exception
       *             if the testcase fails
       */
00265       public void testLocalTransaction() throws Exception {

            if (!versionMeetsMinimum(5, 0) || isRunningOnJdk131()) {
                  return;
            }

            createTable("testLocalTransaction", "(field1 int) ENGINE=InnoDB");

            Connection conn1 = null;

            XAConnection xaConn1 = null;

            try {
                  xaConn1 = getXAConnection();
                  XAResource xaRes1 = xaConn1.getXAResource();
                  conn1 = xaConn1.getConnection();
                  assertEquals(true, conn1.getAutoCommit());
                  conn1.setAutoCommit(true);
                  conn1.createStatement().executeUpdate(
                              "INSERT INTO testLocalTransaction VALUES (1)");
                  assertEquals("1", getSingleIndexedValueWithQuery(conn1, 1,
                              "SELECT field1 FROM testLocalTransaction").toString());

                  conn1.createStatement().executeUpdate(
                              "TRUNCATE TABLE testLocalTransaction");
                  conn1.setAutoCommit(false);
                  conn1.createStatement().executeUpdate(
                              "INSERT INTO testLocalTransaction VALUES (2)");
                  assertEquals("2", getSingleIndexedValueWithQuery(conn1, 1,
                              "SELECT field1 FROM testLocalTransaction").toString());
                  conn1.rollback();
                  assertEquals(0, getRowCount("testLocalTransaction"));

                  conn1.createStatement().executeUpdate(
                              "INSERT INTO testLocalTransaction VALUES (3)");
                  assertEquals("3", getSingleIndexedValueWithQuery(conn1, 1,
                              "SELECT field1 FROM testLocalTransaction").toString());
                  conn1.commit();
                  assertEquals("3", getSingleIndexedValueWithQuery(conn1, 1,
                              "SELECT field1 FROM testLocalTransaction").toString());
                  conn1.commit();
                  
                  Savepoint sp = conn1.setSavepoint();
                  conn1.rollback(sp);
                  sp = conn1.setSavepoint("abcd");
                  conn1.rollback(sp);
                  Savepoint spSaved = sp;
                  
                  Xid xid = createXid();
                  xaRes1.start(xid, XAResource.TMNOFLAGS);

                  try {
                        try {
                              conn1.setAutoCommit(true);
                        } catch (SQLException sqlEx) {
                              // we expect an exception here
                              assertEquals("2D000", sqlEx.getSQLState());
                        }

                        try {
                              conn1.commit();
                        } catch (SQLException sqlEx) {
                              // we expect an exception here
                              assertEquals("2D000", sqlEx.getSQLState());
                        }

                        try {
                              conn1.rollback();
                        } catch (SQLException sqlEx) {
                              // we expect an exception here
                              assertEquals("2D000", sqlEx.getSQLState());
                        }
                        
                        try {
                              sp = conn1.setSavepoint();
                        } catch (SQLException sqlEx) {
                              // we expect an exception here
                              assertEquals("2D000", sqlEx.getSQLState());
                        }
                  
                        try {
                              conn1.rollback(spSaved);
                        } catch (SQLException sqlEx) {
                              // we expect an exception here
                              assertEquals("2D000", sqlEx.getSQLState());
                        }
                        
                        try {
                              sp = conn1.setSavepoint("abcd");
                        } catch (SQLException sqlEx) {
                              // we expect an exception here
                              assertEquals("2D000", sqlEx.getSQLState());
                        }
                        
                        try {
                              conn1.rollback(spSaved);
                        } catch (SQLException sqlEx) {
                              // we expect an exception here
                              assertEquals("2D000", sqlEx.getSQLState());
                        }
                  } finally {
                        xaRes1.forget(xid);
                  }
            } finally {
                  if (xaConn1 != null) {
                        try {
                              xaConn1.close();
                        } catch (SQLException sqlEx) {
                              // this is just busted in the server right now
                        }
                  }
            }
      }
      
      public void testSuspendableTx() throws Exception {
            if (!versionMeetsMinimum(5, 0) || isRunningOnJdk131()) {
                  return;
            }
            
            Connection conn1 = null;

            MysqlXADataSource suspXaDs = new MysqlXADataSource();
            suspXaDs.setUrl(BaseTestCase.dbUrl);
            suspXaDs.setPinGlobalTxToPhysicalConnection(true);
            suspXaDs.setRollbackOnPooledClose(true);
            
            XAConnection xaConn1 = null;
            
            Xid xid = createXid();
            
            try {
                  /*
                        -- works using RESUME
                        xa start 0x123,0x456;
                        select * from foo;
                        xa end 0x123,0x456;
                        xa start 0x123,0x456 resume;
                        select * from foo;
                        xa end 0x123,0x456;
                        xa commit 0x123,0x456 one phase;
                   */
                  
                  xaConn1 = suspXaDs.getXAConnection();
                  XAResource xaRes1 = xaConn1.getXAResource();
                  conn1 = xaConn1.getConnection();
                  xaRes1.start(xid, XAResource.TMNOFLAGS);
                  conn1.createStatement().executeQuery("SELECT 1");
                  xaRes1.end(xid, XAResource.TMSUCCESS);
                  xaRes1.start(xid, XAResource.TMRESUME);
                  conn1.createStatement().executeQuery("SELECT 1");
                  xaRes1.end(xid, XAResource.TMSUCCESS);
                  xaRes1.commit(xid, true);
                  
                  xaConn1.close();
                  
                  /*

                        -- fails using JOIN
                        xa start 0x123,0x456;
                        select * from foo;
                        xa end 0x123,0x456;
                        xa start 0x123,0x456 join;
                        select * from foo;
                        xa end 0x123,0x456;
                        xa commit 0x123,0x456 one phase;
                        */
            
                  xaConn1 = suspXaDs.getXAConnection();
                  xaRes1 = xaConn1.getXAResource();
                  conn1 = xaConn1.getConnection();
                  xaRes1.start(xid, XAResource.TMNOFLAGS);
                  conn1.createStatement().executeQuery("SELECT 1");
                  xaRes1.end(xid, XAResource.TMSUCCESS);
                  xaRes1.start(xid, XAResource.TMJOIN);
                  conn1.createStatement().executeQuery("SELECT 1");
                  xaRes1.end(xid, XAResource.TMSUCCESS);
                  xaRes1.commit(xid, true);
            } finally {
                  if (xaConn1 != null) {
                        xaConn1.close();
                  }
            }
      }

      private Xid createXid() throws IOException {
            ByteArrayOutputStream gtridOut = new ByteArrayOutputStream();
            DataOutputStream dataOut = new DataOutputStream(gtridOut);
            new UID().write(dataOut);
            
            final byte[] gtrid = gtridOut.toByteArray();
            
            ByteArrayOutputStream bqualOut = new ByteArrayOutputStream();
            dataOut = new DataOutputStream(bqualOut);
            
            new UID().write(dataOut);
            
            final byte[] bqual = bqualOut.toByteArray();
            
            Xid xid = new MysqlXid(gtrid, bqual, 3306);
            return xid;
      }

      private Xid createXid(Xid xidToBranch) throws IOException {
            ByteArrayOutputStream bqualOut = new ByteArrayOutputStream();
            DataOutputStream dataOut = new DataOutputStream(bqualOut);
            
            new UID().write(dataOut);
            
            final byte[] bqual = bqualOut.toByteArray();
            
            Xid xid = new MysqlXid(xidToBranch.getGlobalTransactionId(), bqual, 3306);
            
            return xid;
      }
}

Generated by  Doxygen 1.6.0   Back to index