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/11/23 16:03:21 UTC

svn commit: r1205426 - in /db/derby/code/trunk/java: client/org/apache/derby/client/net/ drda/org/apache/derby/impl/drda/ engine/org/apache/derby/iapi/jdbc/ engine/org/apache/derby/iapi/sql/ engine/org/apache/derby/impl/jdbc/ engine/org/apache/derby/im...

Author: dag
Date: Wed Nov 23 15:03:19 2011
New Revision: 1205426

URL: http://svn.apache.org/viewvc?rev=1205426&view=rev
Log:
DERBY-5459 Result set metadata are out of sync on client after underlying table is altered

Patch derby-5459-3. We now resend the result set metadata to the
client when the cursor is opened if the prepared statement gets
recompiled due to it being out of date when the server tries to
execute it (DRDAConnThread line 871). To detect this we introduce a
version counter which is incremented each time a statement is
(re)compiled and make a note which version's metadata gets sent to the
client as part of the explicit prepare. That version is compared with
the current version when we execute to make the decision whether to
resend metadata or not.

This also fixes DERBY-2402, a duplicate.

Modified:
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
    db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/BrokeredPreparedStatement.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/EnginePreparedStatement.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedPreparedStatement.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/PrepStmtMetaDataTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetStatementReply.java Wed Nov 23 15:03:19 2011
@@ -489,6 +489,12 @@ public class NetStatementReply extends N
                 //
                 // this will override the same call made from parsePrepareDescribe
                 //  this will not work, this is not the DA for the stored proc params
+                //
+                // DERBY-5459. We may now receive a new SQLDARD (unrequested, a
+                // DRDA protocol extension) when a query is opened iff the
+                // underlying server's prepared statement has been recompiled
+                // since the client first received metadata when preparing the
+                // statement.
                 statementI.completePrepareDescribeOutput(columnMetaData, netSqlca);
                 peekCP = parseTypdefsOrMgrlvlovrs();
             }

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Wed Nov 23 15:03:19 2011
@@ -828,6 +828,7 @@ class DRDAConnThread extends Thread {
 					try {
 						database.getConnection().clearWarnings();
 						sqldaType = parsePRPSQLSTT();
+                        database.getCurrentStatement().sqldaType = sqldaType;
 						if (sqldaType > 0)		// do write SQLDARD
 							writeSQLDARD(database.getCurrentStatement(),
 										 (sqldaType ==  CodePoint.TYPSQLDA_LIGHT_OUTPUT),
@@ -871,6 +872,27 @@ class DRDAConnThread extends Thread {
 							writeOPNQRYRM(false, stmt);
 							checkWarning(null, ps, null, 0, false, true);
 
+                            long sentVersion = stmt.versionCounter;
+                            long currentVersion =
+                                    ((EnginePreparedStatement)stmt.ps).
+                                    getVersionCounter();
+
+                            if (stmt.sqldaType ==
+                                    CodePoint.TYPSQLDA_LIGHT_OUTPUT &&
+                                    currentVersion != sentVersion) {
+                                // DERBY-5459. The prepared statement has a
+                                // result set and has changed on the server
+                                // since we last informed the client about its
+                                // shape, so re-send metadata.
+                                //
+                                // NOTE: This is an extension of the standard
+                                // DRDA protocol since we send the SQLDARD
+                                // even if it isn't requested in this case.
+                                // This is OK because there is already code on the
+                                // client to handle an unrequested SQLDARD at
+                                // this point in the protocol.
+                                writeSQLDARD(stmt, true, null);
+                            }
 							writeQRYDSC(stmt, false);
 
 							stmt.rsSuspend();

Modified: db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java (original)
+++ db/derby/code/trunk/java/drda/org/apache/derby/impl/drda/DRDAStatement.java Wed Nov 23 15:03:19 2011
@@ -284,6 +284,19 @@ class DRDAStatement
 	boolean needsToSendParamData = false;
 	boolean explicitlyPrepared = false;    //Prepared with PRPSQLSTT (reusable) 
 
+    /**
+     * If this changes, we need to re-send result set metadata to client, since
+     * a change indicates the engine has recompiled the prepared statement.
+     */
+    long versionCounter;
+
+    /**
+     * Saved value returned from {@link DRDAConnThread#from
+     * parsePRPSQLSTT}. Used to determine if the statment is such that we may
+     * need to re-send metadata at execute time, see {@link #versionCounter}.
+     */
+    int sqldaType;
+
 	// constructor
 	/**
 	 * DRDAStatement constructor
@@ -678,7 +691,10 @@ class DRDAStatement
 			ps.setCursorName(cursorName);
 		if (isolationSet)
 			database.setPrepareIsolation(saveIsolationLevel);
-				return ps;
+
+        versionCounter = ((EnginePreparedStatement)ps).getVersionCounter();
+
+        return ps;
 	}
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/BrokeredPreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/BrokeredPreparedStatement.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/BrokeredPreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/BrokeredPreparedStatement.java Wed Nov 23 15:03:19 2011
@@ -549,4 +549,9 @@ public abstract class BrokeredPreparedSt
 
 		return newStatement;
 	}
+
+    public final long getVersionCounter() throws SQLException {
+        return ((EnginePreparedStatement)getPreparedStatement()).
+                getVersionCounter();
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/EnginePreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/EnginePreparedStatement.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/EnginePreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/jdbc/EnginePreparedStatement.java Wed Nov 23 15:03:19 2011
@@ -39,4 +39,12 @@ public interface EnginePreparedStatement
     
     public void setCharacterStream(int parameterIndex, Reader reader)
         throws SQLException;
+
+    /**
+     * Get the version of the prepared statement. If this has not been changed,
+     * the caller may assume that a recompilation has not taken place, i.e.
+     * meta-data are (also) unchanged.
+     * @return version counter
+     */
+    public long getVersionCounter() throws SQLException;
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java Wed Nov 23 15:03:19 2011
@@ -270,4 +270,10 @@ public interface PreparedStatement
 	*/
 	public SQLWarning getCompileTimeWarnings();
 
+    /**
+     * Get the version counter. A change in the value indicates a recompile
+     * has happened.
+     * @return version counter
+     */
+    public long getVersionCounter();
 }

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=1205426&r1=1205425&r2=1205426&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 Wed Nov 23 15:03:19 2011
@@ -1971,4 +1971,8 @@ public abstract class EmbedPreparedState
             throw dataTypeConversion(parameterIndex, "java.sql.Blob");
         }
     }
+
+    public final long getVersionCounter() throws SQLException {
+        return preparedStatement.getVersionCounter();
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java Wed Nov 23 15:03:19 2011
@@ -173,6 +173,11 @@ public class GenericPreparedStatement
 	*/
 	private Cacheable cacheHolder;
 
+    /**
+     * Incremented for each (re)compile.
+     */
+    private long versionCounter;
+
 	//
 	// constructors
 	//
@@ -1241,4 +1246,12 @@ recompileOutOfDatePlan:
 	{
 		return requiredPermissionsList;
 	}
+
+    public final long getVersionCounter() {
+        return versionCounter;
+    }
+
+    public final void incrementVersionCounter() {
+        ++versionCounter;
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java Wed Nov 23 15:03:19 2011
@@ -545,6 +545,7 @@ public class GenericStatement
 					preparedStmt.setConstantAction( qt.makeConstantAction() );
 					preparedStmt.setSavedObjects( cc.getSavedObjects() );
 					preparedStmt.setRequiredPermissionsList(cc.getRequiredPermissionsList());
+                    preparedStmt.incrementVersionCounter();
 					preparedStmt.setActivationClass(ac);
 					preparedStmt.setNeedsSavepoint(qt.needsSavepoint());
 					preparedStmt.setCursorInfo((CursorInfo)cc.getCursorInfo());

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/PrepStmtMetaDataTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/PrepStmtMetaDataTest.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/PrepStmtMetaDataTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/PrepStmtMetaDataTest.java Wed Nov 23 15:03:19 2011
@@ -115,23 +115,35 @@ public class PrepStmtMetaDataTest extend
         assertEquals(java.sql.Types.INTEGER, rsmd.getColumnType(1));
         assertEquals("C11", rsmd.getColumnName(1));
 
-        // DERBY-2402 Client does not report added columns.
-        // Take out check when DERBY-2402 is fixed
-        if (usingDerbyNetClient())
-            return;
-
         s.executeUpdate("alter table bug4579 add column c12 int");
+
+        if (usingDerbyNetClient()) {
+            // DERBY-2402 Client does not report added columns.
+            // Take out check when DERBY-2402 is fixed
+            //
+        } else {
+            rsmd = ps.getMetaData();
+            assertEquals(2, rsmd.getColumnCount());
+            assertEquals(java.sql.Types.INTEGER, rsmd.getColumnType(1));
+            assertEquals("C11", rsmd.getColumnName(1));
+            assertEquals(java.sql.Types.INTEGER, rsmd.getColumnType(2));
+            assertEquals("C12", rsmd.getColumnName(2));
+        }
+
+        // ResultSetMetaData for select * after alter table and
+        // executeQuery.
+        s.executeUpdate("alter table bug4579 add column c13 int");
+        ResultSet rs = ps.executeQuery();
         rsmd = ps.getMetaData();
-        assertEquals(2, rsmd.getColumnCount());
+        assertEquals(3, rsmd.getColumnCount());
         assertEquals(java.sql.Types.INTEGER, rsmd.getColumnType(1));
         assertEquals("C11", rsmd.getColumnName(1));
         assertEquals(java.sql.Types.INTEGER, rsmd.getColumnType(2));
         assertEquals("C12", rsmd.getColumnName(2));
+        assertEquals(java.sql.Types.INTEGER, rsmd.getColumnType(3));
+        assertEquals("C13", rsmd.getColumnName(3));
 
-        // ResultSetMetaData for select * after alter table and
-        // executeQuery.
-        s.executeUpdate("alter table bug4579 add column c13 int");
-        ResultSet rs = ps.executeQuery();
+        // Check ps metadata again
         rsmd = ps.getMetaData();
         assertEquals(3, rsmd.getColumnCount());
         assertEquals(java.sql.Types.INTEGER, rsmd.getColumnType(1));
@@ -140,6 +152,7 @@ public class PrepStmtMetaDataTest extend
         assertEquals("C12", rsmd.getColumnName(2));
         assertEquals(java.sql.Types.INTEGER, rsmd.getColumnType(3));
         assertEquals("C13", rsmd.getColumnName(3));
+
         rs.close();
         ps.close();
         s.executeUpdate("drop table bug4579");

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java?rev=1205426&r1=1205425&r2=1205426&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java Wed Nov 23 15:03:19 2011
@@ -200,19 +200,12 @@ public final class AlterTableTest extend
         // select * prepared statements do see added columns after 
         // alter table
 
-        if (usingEmbedded()) // client/server doesn't keep cursor open.
-        {
-            rs = pSt.executeQuery();
-            JDBC.assertColumnNames(rs, new String[]{"C1", "C2"});
-            JDBC.assertFullResultSet(rs, new String[][]{
-                        {"1", null},
-                        {"2", null}
-                    });
-        } else {
-            rs = pSt.executeQuery();
-            JDBC.assertColumnNames(rs, new String[]{"C1"});
-            JDBC.assertFullResultSet(rs, new String[][]{{"1"}, {"2"}});
-        }
+        rs = pSt.executeQuery();
+        JDBC.assertColumnNames(rs, new String[]{"C1", "C2"});
+        JDBC.assertFullResultSet(rs, new String[][]{
+                {"1", null},
+                {"2", null}
+            });
 
         // add non-nullable column to 0 row table and verify
         st.executeUpdate("alter table t0 add column c2 int not null default 0");