You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by mi...@apache.org on 2010/07/19 01:20:09 UTC

svn commit: r965317 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java

Author: mikem
Date: Sun Jul 18 23:20:09 2010
New Revision: 965317

URL: http://svn.apache.org/viewvc?rev=965317&view=rev
Log:
DERBY-4731

Previous change did not completely solve the problem.  There is a problem with
the initial fix, not sure why it only showed an error in the 10.3 backport. 
The temporary tables are stored in the transaction context, so using a nested 
transaction creates a new context and the work there is not reflected in the 
parent context.  Thus the previous fix which used a nested transaction does
not work.

This patch delays the work on the XA global temporary tables until after the xa transaction has committed but before control returns to the client executing 
the commit.  The delay solves the issue of attempting to do work in a 
prepared transaction.

It drops all global temporary tables following an XA commit.  This gives us
consistent behavior between embedded and network server implementations.  At
the time of an xa end the system "Ends the work performed on behalf of a transaction branch. The resource manager disassociates the XA resource from the transaction branch specified and lets the transaction complete."  Given this 
description of the behavior of XAResource it seems reasonable to document
that global temporary tables are not supported across the XA commit boundary.
In the worst case one might be connecting to an resource in completely another
database and the temp table implementation is tied to the transaction 
context in a single connection to a existing server.



Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java?rev=965317&r1=965316&r2=965317&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java Sun Jul 18 23:20:09 2010
@@ -720,54 +720,66 @@ public class GenericLanguageConnectionCo
         // in XA use nested user updatable transaction.  Delay creating
         // the transaction until loop below finds one it needs to 
         // process.
-        TransactionController xa_tran       = null; 
-        TransactionController tran_for_drop = 
-            (in_xa_transaction ? null : getTransactionExecute());
-
-        try
-        {
-            for (int i=0; i<allDeclaredGlobalTempTables.size(); i++)
-            {
-                TableDescriptor td = 
-                    ((TempTableInfo) (allDeclaredGlobalTempTables.
-                                          get(i))).getTableDescriptor();
-                if (td.isOnCommitDeleteRows() == false) 
-                {
-                    // do nothing for temp table with ON COMMIT PRESERVE ROWS
-                    continue;
-                }
-                else if (checkIfAnyActivationHasHoldCursor(td.getName()) == 
-                            false)
-                {
-                    // temp tables with ON COMMIT DELETE ROWS and 
-                    // no open held cursors
-                    getDataDictionary().getDependencyManager().invalidateFor(
-                        td, DependencyManager.DROP_TABLE, this);
-
-                    // handle delayed creation of nested xact for XA.
-                    if (in_xa_transaction)
-                    {
-                        if (xa_tran == null)
-                        {
-                            xa_tran = 
-                                getTransactionExecute().
-                                    startNestedUserTransaction(false);
-                            tran_for_drop = xa_tran;
-                        }
-                    }
+        
+        for (int i=0; i<allDeclaredGlobalTempTables.size(); i++)
+        {
+            TableDescriptor td = 
+                ((TempTableInfo) (allDeclaredGlobalTempTables.
+                                      get(i))).getTableDescriptor();
+            if (td.isOnCommitDeleteRows() == false) 
+            {
+                // do nothing for temp table with ON COMMIT PRESERVE ROWS
+                continue;
+            }
+            else if (checkIfAnyActivationHasHoldCursor(td.getName()) == 
+                        false)
+            {
+                // temp tables with ON COMMIT DELETE ROWS and 
+                // no open held cursors
+                getDataDictionary().getDependencyManager().invalidateFor(
+                    td, DependencyManager.DROP_TABLE, this);
 
-                    cleanupTempTableOnCommitOrRollback(tran_for_drop, td, true);
+                if (!in_xa_transaction)
+                {
+                    // delay physical cleanup to after the commit for XA
+                    // transactions.   In XA the transaction is likely in
+                    // prepare state at this point and physical changes to
+                    // store are not allowed until after the commit.
+                    // Do the work here for non-XA so that fast path does
+                    // have to do the 2 commits that the XA path will.
+                    cleanupTempTableOnCommitOrRollback(td, true);
                 }
             }
         }
-        finally
-        {
-            // if we created a nested user transaction for XA get rid of it.
-            if (xa_tran != null)
-            {
-                xa_tran.destroy();
-            }
+    }
+
+    private void tempTablesXApostCommit() 
+        throws StandardException
+    {
+        TransactionController tc = getTransactionExecute();
+
+        // at commit time for an XA transaction drop all temporary tables.
+        // A transaction context may not be maintained from one
+        // XAResource.xa_commit to the next in the case of XA with
+        // network server and thus there is no way to get at the temp
+        // tables again.  To provide consistent behavior in embedded vs
+        // network server, consistently remove temp tables at XA commit
+        // transaction boundary.
+        for (int i=0; i < allDeclaredGlobalTempTables.size(); i++)
+        {
+            // remove all temp tables from this context.
+            TableDescriptor td = 
+                ((TempTableInfo) 
+                 (allDeclaredGlobalTempTables.get(i))).getTableDescriptor();
+
+            //remove the conglomerate created for this temp table
+            tc.dropConglomerate(td.getHeapConglomerateId()); 
+
+            //remove it from the list of temp tables
+            allDeclaredGlobalTempTables.remove(i); 
         }
+
+        tc.commit();
     }
 
     /**
@@ -944,8 +956,7 @@ public class GenericLanguageConnectionCo
                 // restore the old definition of temp table because drop is 
                 // being rolledback
                 TableDescriptor td = tempTableInfo.getTableDescriptor();
-                td = cleanupTempTableOnCommitOrRollback(
-                        getTransactionExecute(), td, false);
+                td = cleanupTempTableOnCommitOrRollback(td, false);
 
                 // In order to store the old conglomerate information for the 
                 // temp table, we need to replace the existing table descriptor
@@ -976,8 +987,7 @@ public class GenericLanguageConnectionCo
                 getDataDictionary().getDependencyManager().invalidateFor(
                         td, DependencyManager.DROP_TABLE, this);
 
-                cleanupTempTableOnCommitOrRollback(
-                    getTransactionExecute(), td, true);
+                cleanupTempTableOnCommitOrRollback(td, true);
             } 
             // there is no else here because there is no special processing 
             // required for temp tables declares in earlier work of 
@@ -1530,6 +1540,13 @@ public class GenericLanguageConnectionCo
             // location, since any outer nesting
             // levels expect there to be a savepoint
             resetSavepoints();
+
+            // Do post commit XA temp table cleanup if necessary.
+            if ((allDeclaredGlobalTempTables != null) &&
+                (commitflag != NON_XA))
+            {
+                tempTablesXApostCommit();
+            }
         }
     }
 
@@ -1545,11 +1562,12 @@ public class GenericLanguageConnectionCo
      * temp table (because the drop on it is being rolled back).
      */
     private TableDescriptor cleanupTempTableOnCommitOrRollback(
-    TransactionController   tc,
     TableDescriptor         td, 
     boolean                 dropAndRedeclare)
          throws StandardException
     {
+        TransactionController tc = getTransactionExecute();
+
         //create new conglomerate with same properties as the old conglomerate 
         //and same row template as the old conglomerate
         long conglomId = 
@@ -1580,7 +1598,7 @@ public class GenericLanguageConnectionCo
         //will be refetched next time with the new value
         td.resetHeapConglomNumber();
 
-        if(dropAndRedeclare)
+        if (dropAndRedeclare)
         {
             //remove the old conglomerate from the system
             tc.dropConglomerate(cid); 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java?rev=965317&r1=965316&r2=965317&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java Sun Jul 18 23:20:09 2010
@@ -1172,6 +1172,7 @@ public class XATest extends BaseJDBCTest
         ps.executeUpdate();
         ResultSet rs = s.executeQuery("SELECT count(*) FROM SESSION.t1");
         JDBC.assertFullResultSet(rs, new String[][] {{"1"}});
+        rs.close();
         // You could work around the issue by dropping the TEMP table
         //s.executeUpdate("DROP TABLE SESSION.T1");
         xar.end(xid, XAResource.TMSUCCESS);
@@ -1187,8 +1188,11 @@ public class XATest extends BaseJDBCTest
             // is temp table empty after the commit?
             rs = s.executeQuery("SELECT count(*) FROM SESSION.t1");
             JDBC.assertFullResultSet(rs, new String[][] {{"0"}});
+            rs.close();
+            conn.commit();
         }
 
+
         s.close();
         conn.close();
         xaconn.close();