db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mi...@apache.org
Subject svn commit: r1302229 - in /db/derby/code/branches/10.5/java: engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java
Date Sun, 18 Mar 2012 21:35:07 GMT
Author: mikem
Date: Sun Mar 18 21:35:07 2012
New Revision: 1302229

URL: http://svn.apache.org/viewvc?rev=1302229&view=rev
Log:
DERBY-3823 NullPointerException in stress.multi test

backported change #1242007 from 10.8 branch to 10.5 branch

This patch fixes a race condition in
EmbedPreparedStatement#getMetaData: if we are trying to retrieve the
metadata for a prepared statement while it is being recompiled there
is a time window during which the activation class is null. The
existing code could therefore cause an NPE. The new code plugs the
race condition. This NPE led to intermittent errors in
stressTestMulti.


Modified:
    db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
    db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java

Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java?rev=1302229&r1=1302228&r2=1302229&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
(original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
Sun Mar 18 21:35:07 2012
@@ -64,6 +64,7 @@ import java.sql.Types;
 import org.apache.derby.iapi.jdbc.BrokeredConnectionControl;
 import org.apache.derby.iapi.jdbc.EngineParameterMetaData;
 import org.apache.derby.iapi.jdbc.EnginePreparedStatement;
+import org.apache.derby.iapi.services.loader.GeneratedClass;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
 import org.apache.derby.iapi.types.StringDataValue;
 
@@ -1072,43 +1073,48 @@ public abstract class EmbedPreparedState
 			setupContextStack(); // make sure there's context
 
 			try {
-				//bug 4579 - if the statement is invalid, regenerate the metadata info
-				if (preparedStatement.isValid() == false)
-				{
-					//need to revalidate the statement here, otherwise getResultDescription would
-					//still have info from previous valid statement
-					preparedStatement.rePrepare(lcc);
-					rMetaData = null;
-				}
 				//bug 4579 - gcDuringGetMetaData will be null if this is the first time
 				//getMetaData call is made.
 				//Second check - if the statement was revalidated since last getMetaData call,
 				//then gcDuringGetMetaData wouldn't match with current generated class name
-				if (gcDuringGetMetaData == null || gcDuringGetMetaData.equals(execp.getActivationClass().getName())
== false)
-				{
-					rMetaData = null;
-					gcDuringGetMetaData = execp.getActivationClass().getName();
-				}
-				if (rMetaData == null)
-				{
-					ResultDescription resd = preparedStatement.getResultDescription();
-					if (resd != null)
-					{
-						// Internally, the result description has information
-						// which is used for insert, update and delete statements
-						// Externally, we decided that statements which don't
-						// produce result sets such as insert, update and delete
-						// should not return ResultSetMetaData.  This is enforced
-						// here
-						String statementType = resd.getStatementType();
-						if (statementType.equals("INSERT") ||
-								statementType.equals("UPDATE") ||
-								statementType.equals("DELETE"))
-							rMetaData = null;
-						else
-				    		rMetaData = newEmbedResultSetMetaData(resd);
-					}
-				}
+
+                GeneratedClass currAc = null;
+                ResultDescription resd = null;
+
+                synchronized(execp) {
+                    // DERBY-3823 Some other thread may be repreparing
+                    do {
+                        while (!execp.upToDate()) {
+                            execp.rePrepare(lcc);
+                        }
+
+                        currAc = execp.getActivationClass();
+                        resd = execp.getResultDescription();
+                    } while (currAc == null);
+                }
+
+                if (gcDuringGetMetaData == null ||
+                        !gcDuringGetMetaData.equals(currAc.getName())) {
+                    rMetaData = null;
+                    gcDuringGetMetaData = currAc.getName();
+                }
+
+                if (rMetaData == null && resd != null) {
+                    // Internally, the result description has information
+                    // which is used for insert, update and delete statements
+                    // Externally, we decided that statements which don't
+                    // produce result sets such as insert, update and delete
+                    // should not return ResultSetMetaData.  This is enforced
+                    // here
+                    String statementType = resd.getStatementType();
+                    if (statementType.equals("INSERT") ||
+                            statementType.equals("UPDATE") ||
+                            statementType.equals("DELETE"))
+                        rMetaData = null;
+                    else
+                        rMetaData = newEmbedResultSetMetaData(resd);
+                }
+
 			} catch (Throwable t) {
 				throw handleException(t);
 			}	finally {

Modified: db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java?rev=1302229&r1=1302228&r2=1302229&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java
(original)
+++ db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java
Sun Mar 18 21:35:07 2012
@@ -1710,6 +1710,65 @@ public final class AlterTableTest extend
 
         st.executeUpdate(
                 "rename column renc_schema_2.renc_8.b to b2");
+        
+        //DERBY-3823 While a resulset is still open, network server allows
+        // ALTER TABLE to change the length of the column in the resultset,
+        // but that length is not reflected in resultset's metadata. This
+        // most likely is happening because of the pre-fetching by the 
+        // server. Related jiras are DERBY-3839 and DERBY-4373.
+        //Once DERBY-3823 is fixed, we should see the change in metadata
+        // reflected in resultset's metadata. A fix for DERBY-3823 will
+        // cause the following test to fail. Right now, the following
+        // test accepts the incorrect metadata length obtained through
+        // the resultset's metadata after ALTER TABLE has been performed.
+        conn.setAutoCommit(false);
+        //Create table and load data
+        st.executeUpdate(
+                "create table derby_3823_t1 (c11 int, c12 varchar(5))");
+        PreparedStatement ps = prepareStatement(
+        		"insert into derby_3823_t1 values(?,'aaaaa')");
+        for (int i = 0; i < 1000; i++) { 
+        	ps.setInt(1, i); 
+        	ps.executeUpdate(); 
+    	} 
+        conn.commit();
+        //Open a resultset on the table which will be altered because
+        // the resultset has been exhausted. The alter table will fail
+        // in embedded mode because of the open resulset but will succeed
+        // in network server because of the pre-fetching.
+        rs = st.executeQuery("select * from derby_3823_t1");
+        //Just get first 100 rows rather than going through all the rows
+        //Next, we will attempt to change the column length of one of the
+        // columns in the resultset and see what happens
+        for (int i = 0; i < 100; i++) { 
+        	rs.next(); 
+    	}
+        rsmd = rs.getMetaData();
+        //The column c12's length at this point is 2
+        assertEquals(5, rsmd.getColumnDisplaySize(2));
+        Statement st1 = createStatement();
+        // This should fail, as c12's column length at this point is 2 and
+        //  data being inserted is 8 characters in length
+        assertStatementError("22001", st1, "insert into derby_3823_t1 values(99,'12345678')");
+        if (usingEmbedded()) 
+        {
+        	//ALTER TABLE will fail in embedded because of the open resulset
+            assertStatementError("X0X95", st1,
+                    "alter table derby_3823_t1 alter column c12 set data type varchar(8)");
+        } else {
+        	//ALTER TABLE does not fail in network server because of pre-fetching
+            st1.execute("alter table derby_3823_t1 alter column c12 set data type varchar(8)");

+            //BUG - but the following metadata of the resultset does not show
+            //  the new column length for C12 which is 8 rather than 2
+            rsmd = rs.getMetaData(); 
+            //Following is incorrect. The column length should have been 8
+            // rather than 5
+            assertEquals(5, rsmd.getColumnDisplaySize(2));
+            //Following shows that we are able to enter 8character string after
+            // alter table alter column. It is the resulset metadata which does
+            // not reflect the change in length
+            st1.executeUpdate("insert into derby_3823_t1 values(99,'12345678')"); 
+        }
     }
 
     // alter table tests for ALTER TABLE DROP COLUMN. The 



Mime
View raw message