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 16:59:59 UTC

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

Author: mikem
Date: Mon Jul 19 14:59:58 2010
New Revision: 965518

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

backport change #965351 from 10.6 to 10.5 branch.

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.
Files Changed
MODIFY /db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
MODIFY /db/derby/code/branches/10.6/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java 


Modified:
    db/derby/code/branches/10.5/   (props changed)
    db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
    db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java

Propchange: db/derby/code/branches/10.5/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Jul 19 14:59:58 2010
@@ -1,2 +1,2 @@
-/db/derby/code/branches/10.6:942027,957000,962738
+/db/derby/code/branches/10.6:942027,957000,962738,965351
 /db/derby/code/trunk:757811,769596,769602,769606,769962,772090,772337,772449,772534,774281,777105,779681,782991,785131,785139,785163,785570,785662,788369,788670,788674,788968,789264,790218,791027,792434,793089,793588,794106,794303,794955,795166,795459,796020,796027,796316,796372,797147,798347,798742,800523,803548,803948,805696,808494,808850,809643,810860,812669,816531,816536,819006,822289,823659,824694,827505,829022,829410,830545,831304,831319,832379,833430,835286,881074,881444,882732,884163,885421,885659,887246,888311,892912,897161,898635,901165,901648,901760,902857,903108,905224,908418,908586,909176,910481,910511,911315,911793,915733,916075,916897,918152,918359,921028,927430,928065,934474,936215,938959,940462,940469,942286,942476,942480,942587,946794,948045,948069,951346,951366,952138,952581,954748,955001,955634,956075,956445,956659,958163,959550,962716

Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java?rev=965518&r1=965517&r2=965518&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java Mon Jul 19 14:59:58 2010
@@ -636,50 +636,69 @@ public class GenericLanguageConnectionCo
         TransactionController tran_for_drop = 
             (in_xa_transaction ? null : getTransactionExecute());
 
-        try
+        // in XA use nested user updatable transaction.  Delay creating
+        // the transaction until loop below finds one it needs to 
+        // process.
+        
+        for (int i=0; i<allDeclaredGlobalTempTables.size(); i++)
         {
-            for (int i=0; i<allDeclaredGlobalTempTables.size(); i++)
+            TableDescriptor td = 
+                ((TempTableInfo) (allDeclaredGlobalTempTables.
+                                      get(i))).getTableDescriptor();
+            if (td.isOnCommitDeleteRows() == false) 
             {
-                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;
-                        }
-                    }
+                // 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
+    }
+
+    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++)
         {
-            // if we created a nested user transaction for XA get rid of it.
-            if (xa_tran != null)
-            {
-                xa_tran.destroy();
-            }
+            // 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();
     }
 
 	/**
@@ -796,8 +815,8 @@ 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 with the old table descriptor which has the old conglomerate information
 				tempTableInfo.setTableDescriptor(td);
@@ -811,8 +830,7 @@ public class GenericLanguageConnectionCo
 				tempTableInfo.setModifiedInSavepointLevel(-1);
 				TableDescriptor td = tempTableInfo.getTableDescriptor();
 				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 unit/transaction and not modified
 		}
     
@@ -1298,40 +1316,48 @@ public class GenericLanguageConnectionCo
             }
         }
 
-		// now commit the Store transaction
-		TransactionController tc = getTransactionExecute();
-		if ( tc != null && commitStore ) 
-		{ 
-			if (sync)
-			{
-				if (commitflag == NON_XA)
-				{
-					// regular commit
-					tc.commit();
-				}
-				else
-				{
-					// This may be a xa_commit, check overloaded commitflag.
+        // now commit the Store transaction
+        TransactionController tc = getTransactionExecute();
+        if ( tc != null && commitStore ) 
+        { 
+            if (sync)
+            {
+                if (commitflag == NON_XA)
+                {
+                    // regular commit
+                    tc.commit();
+                }
+                else
+                {
+                    // This may be a xa_commit, check overloaded commitflag.
 
-					if (SanityManager.DEBUG)
-						SanityManager.ASSERT(commitflag == XA_ONE_PHASE ||
-											 commitflag == XA_TWO_PHASE,
-											   "invalid commit flag");
+                    if (SanityManager.DEBUG)
+                        SanityManager.ASSERT(commitflag == XA_ONE_PHASE ||
+                                             commitflag == XA_TWO_PHASE,
+                                               "invalid commit flag");
 
-					((XATransactionController)tc).xa_commit(commitflag == XA_ONE_PHASE);
+                    ((XATransactionController)tc).xa_commit(
+                            commitflag == XA_ONE_PHASE);
 
-				}
-			}
-			else
-			{
-				tc.commitNoSync(commitflag);
-			}
+                }
+            }
+            else
+            {
+                tc.commitNoSync(commitflag);
+            }
 
-			// reset the savepoints to the new
-			// location, since any outer nesting
-			// levels expect there to be a savepoint
-			resetSavepoints();
-		}
+            // reset the savepoints to the new
+            // 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();
+            }
+        }
 	}
 
 	/**
@@ -1346,11 +1372,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 = 

Modified: db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java?rev=965518&r1=965517&r2=965518&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java (original)
+++ db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java Mon Jul 19 14:59:58 2010
@@ -1093,12 +1093,12 @@ public class XATest extends BaseJDBCTest
      */
     public void testXATempTableD4731_RawStore() 
         throws SQLException, XAException {
-        doXATempTableD4731Work(true, XATestUtil.getXid(997, 9, 49));
+        doXATempTableD4731Work(true, false, XATestUtil.getXid(997, 9, 49));
     }
     
 
     /**
-     * DERBY-XXXX Temp tables with XA transactions
+     * DERBY-4735 Temp tables with XA transactions
      * an Assert will occur on prepare if only
      * temp table work is done in the xact.
      *
@@ -1106,10 +1106,27 @@ public class XATest extends BaseJDBCTest
      * @throws SQLException 
      * 
      */
-    public void xtestXATempTableDXXXX_Assert() 
+    public void xtestXATempTableD4735_Assert() 
         throws SQLException, XAException {
 
-          doXATempTableD4731Work(false, XATestUtil.getXid(998, 10, 50));
+          doXATempTableD4731Work(false, false, XATestUtil.getXid(999,  11, 51));
+          doXATempTableD4731Work(false, true,  XATestUtil.getXid(1000, 12, 52));
+    }
+
+    /**
+     * DERBY-4743 Temp tables with XA transactions
+     *
+     * Will throw an error in network server when attempt is made to 
+     * access the global temporary table after the end and commit.
+     *
+     * @throws XAException 
+     * @throws SQLException 
+     * 
+     */
+    public void xtestXATempTableD4743() 
+        throws SQLException, XAException {
+
+          doXATempTableD4731Work(true, true, XATestUtil.getXid(998, 10, 50));
     }
  
     
@@ -1124,6 +1141,7 @@ public class XATest extends BaseJDBCTest
      */
     private void doXATempTableD4731Work(
     boolean doLoggedWorkInXact,
+    boolean access_temp_table_after_xaendandcommit,
     Xid     xid)
         throws SQLException, XAException{
 
@@ -1154,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);
@@ -1163,11 +1182,23 @@ public class XATest extends BaseJDBCTest
             xar.prepare(xid));
 
         xar.commit(xid,false); 
+
+        if (access_temp_table_after_xaendandcommit)
+        {
+            // 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();
     }
 
+
     private void makeARealTable(Statement s) throws SQLException {
         try {
             s.executeUpdate("DROP TABLE REALTABLE1");