[ 
https://issues.apache.org/jira/browse/DERBY-4232?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Knut Anders Hatlen updated DERBY-4232:
--------------------------------------

    Attachment: d4232-1a.diff

The patch d4232-1a.diff appears to fix the issue. It simply skips sending the 
timeout property if something we have other flags than TMNOFLAGS. Currently, 
the client code will only reread the timeout value when start(xid,TMNOFLAGS) is 
called, but the last timeout value read is still sent to the server regardless 
of the flags. I think this is unintentional, and that the meaning was to 
suppress the sending of the value as well. If start(xid,TMNOFLAGS) hasn't been 
called on the XAResource before we call start() with TMJOIN, the timeout value 
will be ignored with the current code too, and we don't get the XAER_PROTO 
exception.

(This means that we will ignore changes in the timeout value when calling 
start() with flags!=TMNOFLAGS, which I wouldn't think is according to the XA 
specification. However, this is an existing problem in the cases where we don't 
get a protocol error, so a new bug should be filed if someone wants that 
addressed. My current understanding is that communicating the changed timeout 
value to the server in the non-TMNOFLAGS case would require an extension to the 
DRDA protocol.)

> Call XAResource.setTransactionTimeout() makes XAResource.start() fail with 
> the client dirver
> --------------------------------------------------------------------------------------------
>
>                 Key: DERBY-4232
>                 URL: https://issues.apache.org/jira/browse/DERBY-4232
>             Project: Derby
>          Issue Type: Bug
>          Components: JDBC
>    Affects Versions: 10.4.2.0
>            Reporter: Simon Meng
>         Attachments: d4232-1a.diff, test.diff
>
>
> Got below error message when running an XA prolgram with derby. 
> org.apache.derby.client.am.XaException: XAER_PROTO : Error executing a 
> XAResource.start(), server returned XAER_PROTO.
>       at org.apache.derby.client.net.NetXAResource.throwXAException(Unknown 
> Source)
>       at org.apache.derby.client.net.NetXAResource.start(Unknown Source)
>       at TestDerbyXA.process(TestDerbyXA.java:186)
>       at TestDerbyXA.main(TestDerbyXA.java:43)
> Caused by: org.apache.derby.client.am.SqlException: Error executing a 
> XAResource.start(), server returned XAER_PROTO.
>       at 
> org.apache.derby.client.net.NetXAResource.xaRetValErrorAccumSQL(Unknown 
> Source)
>       ... 3 more
> Below is the example program I used. Note: The program will succeed if 
> comment out line 147 - setTransactionTimeout. Does that means call 
> XAResource.setTransactionTimeout() caused the failure?
> I use Apache Derby Network Server - 10.4.2.0 - (689064). The same program 
> works fine with another version Apache Derby Network Server - 10.2.2.0 - 
> (485682). It looks like there is a regression between the two versions.
> import java.sql.Connection;
> import java.sql.PreparedStatement;
> import java.sql.SQLException;
> import java.sql.Statement;
> import javax.sql.XAConnection;
> import javax.transaction.xa.XAException;
> import javax.transaction.xa.XAResource;
> import javax.transaction.xa.Xid;
> import org.apache.derby.jdbc.ClientXADataSource;
> public class TestDerbyXA {
>       ClientXADataSource xaDSLocal = null;
>       ClientXADataSource xaDSRemote = null;
>       public TestDerbyXA() {
>               // Create two XA data sources.
>               xaDSLocal = new ClientXADataSource();
>               xaDSLocal.setServerName("localhost");
>               xaDSLocal.setPortNumber(1527);
>               xaDSLocal.setDatabaseName("testdb");
>               xaDSLocal.setUser("app");
>               xaDSLocal.setPassword("derby");
>               xaDSRemote = new ClientXADataSource();
>               xaDSRemote.setServerName("localhost");
>               xaDSRemote.setPortNumber(1527);
>               xaDSRemote.setDatabaseName("testdb");
>               xaDSRemote.setUser("app");
>               xaDSRemote.setPassword("derby");
>               // xaDSRemote = xaDSLocal;
>       }
>       public static void main(String[] args) throws Exception {
>               TestDerbyXA testObj = new TestDerbyXA();
>               testObj.dropTable("tablea");
>               testObj.createTable("CREATE TABLE tablea (col1 INT, col2 
> VARCHAR(32))");
>               testObj.dropTable("tableb");
>               testObj.createTable("CREATE TABLE tableb (col1 INT, col2 
> VARCHAR(32))");
>               testObj.process();
>       }
>       public void dropTable(String tableName) throws Exception {
>               Connection conn = null;
>               Statement stmt = null;
>               try {
>                       conn = xaDSLocal.getConnection();
>                       stmt = conn.createStatement();
>                       stmt.executeUpdate("DROP TABLE " + tableName);
>                       System.out.println("Drop table " + tableName + " 
> succeed.");
>               } catch (SQLException sqle) {
>                       System.out.println("Drop table " + tableName + " 
> failed.");
>                       sqle.printStackTrace();
>               } finally {
>                       // ============ Close JDBC objects, including the 
> connection =======
>                       if (stmt != null) {
>                               try {
>                                       stmt.close();
>                                       stmt = null;
>                               } catch (SQLException e) {
>                               }
>                       }
>                       if (conn != null) {
>                               try {
>                                       conn.close();
>                                       conn = null;
>                               } catch (SQLException e) {
>                               }
>                       }
>               }
>       }
>       public void createTable(String DDL) throws Exception {
>               Connection conn = null;
>               Statement stmt = null;
>               try {
>                       conn = xaDSLocal.getConnection();
>                       stmt = conn.createStatement();
>                       stmt.executeUpdate(DDL);
>                       System.out.println(DDL + " succeed.");
>               } catch (SQLException sqle) {
>                       System.out.println(DDL + " failed.");
>                       sqle.printStackTrace();
>               } finally {
>                       // ============ Close JDBC objects, including the 
> connection =======
>                       if (stmt != null) {
>                               try {
>                                       stmt.close();
>                                       stmt = null;
>                               } catch (SQLException e) {
>                               }
>                       }
>                       if (conn != null) {
>                               try {
>                                       conn.close();
>                                       conn = null;
>                               } catch (SQLException e) {
>                               }
>                       }
>               }
>       }
>       public void process() throws Exception {
>               Connection connLocal = null;
>               Connection connRemote = null;
>               int rows = 0;
>               PreparedStatement pstmtLocal = null;
>               PreparedStatement pstmtRemote = null;
>               XAConnection xaConnLocal = null;
>               XAConnection xaConnRemote = null;
>               XAResource xarLocal = null;
>               XAResource xarRemote = null;
>               Xid xidLocal = null;
>               Xid xidRemote = null;
>               try {
>                       xaConnLocal = xaDSLocal.getXAConnection();
>                       xaConnRemote = xaDSRemote.getXAConnection();
>                       connLocal = xaConnLocal.getConnection();
>                       connRemote = xaConnRemote.getConnection();
>                       xarLocal = xaConnLocal.getXAResource();
>                       xarRemote = xaConnRemote.getXAResource();
>                       // Create the Xids
>                       // Create the global ID
>                       byte[] globalTransactionId1 = new byte[64];
>                       globalTransactionId1[0] = (byte) 1;
>                       byte[] globalTransactionId2 = new byte[64];
>                       globalTransactionId2[0] = (byte) 2;
>                       // Create the local branch ID
>                       byte[] branchQualifierLocal = new byte[64];
>                       branchQualifierLocal[0] = (byte) 1;
>                       xidLocal = new XidImpl(globalTransactionId1, 
> branchQualifierLocal, 0x1234);
>                       // Create the remote branch ID
>                       byte[] branchQualifierRemote = new byte[64];
>                       branchQualifierRemote[0] = (byte) 2;
>                       xidRemote = new XidImpl(globalTransactionId2, 
> branchQualifierRemote, 0x1234);
>                       // Database operations on the local branch, suspend 
> local branch
>                       xarLocal.setTransactionTimeout(500);  //!!! The failure 
> will disappear if comment out this line.
>                       connLocal.setAutoCommit(false);
>                       xarLocal.start(xidLocal, XAResource.TMNOFLAGS);
>                       pstmtLocal = connLocal
>                                       .prepareStatement("INSERT INTO tablea 
> (col1, col2) VALUES (?, ?)");
>                       pstmtLocal.setInt(1, 1);
>                       pstmtLocal.setString(2, "insert first rec to tablea");
>                       rows = pstmtLocal.executeUpdate();
>                       System.out.println(rows + " rows inserted to tablea");
>                       pstmtLocal.close();
>                       pstmtLocal = null;
>                       xarLocal.end(xidLocal, XAResource.TMSUCCESS);
>                       connLocal.setAutoCommit(true);
>                       // Database operation on the remote branch, commit 
> remote branch
>                       xarRemote.setTransactionTimeout(500);
>                       connRemote.setAutoCommit(false);
>                       xarRemote.start(xidRemote, XAResource.TMNOFLAGS);
>                       pstmtRemote = connRemote
>                                       .prepareStatement("INSERT INTO tableb 
> (col1, col2) VALUES (?, ?)");
>                       pstmtRemote.setInt(1, 2);
>                       pstmtRemote.setString(2, "insert second rec to tableb");
>                       rows = pstmtRemote.executeUpdate();
>                       System.out.println(rows + " rows inserted to tableb");
>                       pstmtRemote.close();
>                       pstmtRemote = null;
>                       xarRemote.end(xidRemote, XAResource.TMSUCCESS);
>                       connRemote.setAutoCommit(true);
>                       System.out.println("commit remote branch");
>                       xarRemote.commit(xidRemote, true);
>                       // Resume the local branch and do some database 
> operation, commit local branch
>                       xarLocal.setTransactionTimeout(500);
>                       connLocal.setAutoCommit(false);
>                       xarLocal.start(xidLocal, XAResource.TMJOIN);
>                       pstmtLocal = connLocal
>                                       .prepareStatement("INSERT INTO tablea 
> (col1, col2) VALUES (?, ?)");
>                       pstmtLocal.setInt(1, 3);
>                       pstmtLocal.setString(2, "insert third rec to tablea");
>                       rows = pstmtLocal.executeUpdate();
>                       System.out.println(rows + " rows inserted to tablea");
>                       pstmtLocal.close();
>                       pstmtLocal = null;
>                       xarLocal.end(xidLocal, XAResource.TMSUCCESS);
>                       connLocal.setAutoCommit(true);
>                       System.out.println("commit local branch");
>                       xarLocal.commit(xidLocal, true);
>                       // Close the resources
>                       connLocal.close();
>                       connLocal = null;
>                       connRemote.close();
>                       connRemote = null;
>                       xaConnLocal.close();
>                       xaConnLocal = null;
>                       xaConnRemote.close();
>                       xaConnRemote = null;
>               } catch (SQLException e) {
>                       System.err.println("SQL Error: " + e.getMessage());
>                       e.printStackTrace();
>               } catch (XAException e) {
>                       System.err.println("XA Error: " + e.getMessage());
>                       e.printStackTrace();
>               } finally {
>                       if (pstmtLocal != null)
>                               try {
>                                       pstmtLocal.close();
>                                       pstmtLocal = null;
>                               } catch (SQLException ignore) {
>                               }
>                       if (pstmtRemote != null)
>                               try {
>                                       pstmtRemote.close();
>                                       pstmtRemote = null;
>                               } catch (SQLException ignore) {
>                               }
>                       if (connLocal != null)
>                               try {
>                                       connLocal.close();
>                                       connLocal = null;
>                               } catch (SQLException ignore) {
>                               }
>                       if (connRemote != null)
>                               try {
>                                       connRemote.close();
>                                       connRemote = null;
>                               } catch (SQLException ignore) {
>                               }
>                       if (xaConnLocal != null)
>                               try {
>                                       xaConnLocal.close();
>                                       xaConnLocal = null;
>                               } catch (SQLException ignore) {
>                               }
>                       if (xaConnRemote != null)
>                               try {
>                                       xaConnRemote.close();
>                                       xaConnRemote = null;
>                               } catch (SQLException ignore) {
>                               }
>               }
>       }
> }

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to