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 da...@apache.org on 2011/10/14 03:34:41 UTC

svn commit: r1183192 - /db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java

Author: dag
Date: Fri Oct 14 01:34:40 2011
New Revision: 1183192

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

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/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java?rev=1183192&r1=1183191&r2=1183192&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java Fri Oct 14 01:34:40 2011
@@ -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;
 import org.apache.derby.iapi.util.InterruptStatus;
@@ -1077,43 +1078,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);
+                }
+
                 InterruptStatus.restoreIntrFlagIfSeen(lcc);
 			} catch (Throwable t) {
 				throw handleException(t);