db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mi...@apache.org
Subject svn commit: r965586 - in /db/derby/code/branches/10.3/java: engine/org/apache/derby/impl/sql/conn/ engine/org/apache/derby/jdbc/ testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/
Date Mon, 19 Jul 2010 19:04:43 GMT
Author: mikem
Date: Mon Jul 19 19:04:43 2010
New Revision: 965586

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

backport change #965351 from 10.6 to 10.3 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.


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

Modified: db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java?rev=965586&r1=965585&r2=965586&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
(original)
+++ db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
Mon Jul 19 19:04:43 2010
@@ -538,25 +538,121 @@ public class GenericLanguageConnectionCo
 		}
 	}
 
-	/**
-	 * do the necessary work at commit time for temporary tables
-	 * 1)If a temporary table was marked as dropped in this transaction, then remove it from
the list of temp tables for this connection
-	 * 2)If a temporary table was not dropped in this transaction, then mark it's declared savepoint
level and modified savepoint level as -1
-	 */
-	private void tempTablesAndCommit() {
-		for (int i = allDeclaredGlobalTempTables.size()-1; i >= 0; i--) {
-			TempTableInfo tempTableInfo = (TempTableInfo)allDeclaredGlobalTempTables.get(i);
-			if (tempTableInfo.getDroppedInSavepointLevel() != -1)
-			{
-				//this means table was dropped in this unit of work and hence should be removed from
valid list of temp tables
-				allDeclaredGlobalTempTables.remove(i);
-			} else //this table was not dropped in this unit of work, hence set its declaredInSavepointLevel
as -1 and also mark it as not modified 
-			{
-				tempTableInfo.setDeclaredInSavepointLevel(-1);
-				tempTableInfo.setModifiedInSavepointLevel(-1);
-			}
-		}
-	}
+    /**
+     * Do the necessary work at commit time for temporary tables
+     * <p>
+     * 1)If a temporary table was marked as dropped in this transaction, then 
+     *   remove it from the list of temp tables for this connection
+     * 2)If a temporary table was not dropped in this transaction, then mark 
+     *   it's declared savepoint level and modified savepoint level as -1
+     * 3)After savepoint fix up, then handle all ON COMMIT DELETE ROWS with
+     *   no open held cursor temp tables.
+     * <p>
+     *
+     * @param in_xa_transaction if true, then transaction is an XA transaction,
+     *                          and special nested transaction may be necessary
+     *                          to cleanup internal containers supporting the
+     *                          temp tables at commit time.
+     *
+     * @exception  StandardException  Standard exception policy.
+     **/
+    private void tempTablesAndCommit(boolean in_xa_transaction) 
+        throws StandardException
+    {
+        // loop through all declared global temporary tables and determine
+        // what to do at commit time based on if they were dropped during
+        // the current savepoint level.
+        for (int i = allDeclaredGlobalTempTables.size()-1; i >= 0; i--) 
+        {
+            TempTableInfo tempTableInfo = 
+                (TempTableInfo)allDeclaredGlobalTempTables.get(i);
+
+            if (tempTableInfo.getDroppedInSavepointLevel() != -1)
+            {
+                // this means table was dropped in this unit of work and hence 
+                // should be removed from valid list of temp tables
+
+                allDeclaredGlobalTempTables.remove(i);
+            } 
+            else 
+            {
+                //this table was not dropped in this unit of work, hence set 
+                //its declaredInSavepointLevel as -1 and also mark it as not 
+                //modified 
+
+                tempTableInfo.setDeclaredInSavepointLevel(-1);
+                tempTableInfo.setModifiedInSavepointLevel(-1);
+            }
+        }
+
+        // at commit time, for all the temp tables declared with 
+        // ON COMMIT DELETE ROWS, make sure there are no held cursor open
+        // on them.
+        // If there are no held cursors open on ON COMMIT DELETE ROWS, 
+        // drop those temp tables and redeclare them to get rid of all the 
+        // data in them
+
+        
+        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);
+
+                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);
+                }
+            }
+        }
+    }
+
+    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();
+    }
 
 	/**
 		Reset the connection before it is returned (indirectly) by
@@ -663,6 +759,7 @@ public class GenericLanguageConnectionCo
 				//restore the old definition of temp table because drop is being rolledback
 				TableDescriptor td = tempTableInfo.getTableDescriptor();
 				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);
@@ -1102,31 +1199,11 @@ public class GenericLanguageConnectionCo
 
 		endTransactionActivationHandling(false);
 
-		//do the clean up work required for temporary tables at the commit time. This cleanup work
-		//can possibly remove entries from allDeclaredGlobalTempTables and that's why we need to
check
-		//again later to see if we there are still any entries in allDeclaredGlobalTempTables
-		if (allDeclaredGlobalTempTables != null)
-		{
-			tempTablesAndCommit();
-			//at commit time, for all the temp tables declared with ON COMMIT DELETE ROWS, make sure
there are no held cursor open on them.
-			//If there are no held cursors open on ON COMMIT DELETE ROWS, drop those temp tables and
redeclare them to get rid of all the data in them
-			if (allDeclaredGlobalTempTables != null) {
-				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;
-					}
-					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(td, true);
-					}
-				}
-			}
-		}
-
+        // Do clean up work required for temporary tables at commit time.  
+        if (allDeclaredGlobalTempTables != null)
+        {
+            tempTablesAndCommit(commitflag != NON_XA);
+        }
 
 		currentSavepointLevel = 0; //reset the current savepoint level for the connection to 0
at the end of commit work for temp tables
 
@@ -1149,40 +1226,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();
+            }
+        }
 	}
 
 	/**
@@ -1197,14 +1282,16 @@ public class GenericLanguageConnectionCo
      * temp table (because the drop on it is being rolled back).
 	 */
 	private TableDescriptor cleanupTempTableOnCommitOrRollback(
-    TableDescriptor td, 
-    boolean         dropAndRedeclare)
+    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 = 
-            tran.createConglomerate(
+            tc.createConglomerate(
                 "heap", // we're requesting a heap conglomerate
                 td.getEmptyExecRow().getRowArray(), // row template
                 null, //column sort order - not required for heap
@@ -1229,7 +1316,7 @@ public class GenericLanguageConnectionCo
 
 		if(dropAndRedeclare)
 		{
-			tran.dropConglomerate(cid); //remove the old conglomerate from the system
+			tc.dropConglomerate(cid); //remove the old conglomerate from the system
 			replaceDeclaredGlobalTempTable(td.getName(), td);
 		}
 

Modified: db/derby/code/branches/10.3/java/engine/org/apache/derby/jdbc/EmbedXAResource.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/engine/org/apache/derby/jdbc/EmbedXAResource.java?rev=965586&r1=965585&r2=965586&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/engine/org/apache/derby/jdbc/EmbedXAResource.java (original)
+++ db/derby/code/branches/10.3/java/engine/org/apache/derby/jdbc/EmbedXAResource.java Mon
Jul 19 19:04:43 2010
@@ -290,10 +290,16 @@ class EmbedXAResource implements XAResou
                 } else {
                     
                     returnConnectionToResource(tranState, xid_im);
+
 					if (SanityManager.DEBUG) {
-						if (con.realConnection != null)
-							SanityManager.ASSERT(con.realConnection.transactionIsIdle(),
-									"real connection should have been idle at this point"); 			
+						if (con.realConnection != null) {
+							SanityManager.ASSERT(
+                                con.realConnection.transactionIsIdle(),
+                                "real connection should have been idle." +
+                                "tranState = " + tranState +
+                                "ret = " + ret +
+                                "con.realConnection = " + con.realConnection);
+                        }
 					}
                     return XAResource.XA_RDONLY;
                 }

Modified: db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java?rev=965586&r1=965585&r2=965586&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java
(original)
+++ db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/XATest.java
Mon Jul 19 19:04:43 2010
@@ -1091,14 +1091,14 @@ public class XATest extends BaseJDBCTest
      * @throws SQLException 
      * 
      */
-    public void xtestXATempTableD4731_RawStore() 
+    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");



Mime
View raw message