db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kahat...@apache.org
Subject svn commit: r997722 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/compile/ engine/org/apache/derby/iapi/sql/execute/ engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/impl/sql/execute/ testing/org/apache/derbyTesting/...
Date Thu, 16 Sep 2010 12:35:03 GMT
Author: kahatlen
Date: Thu Sep 16 12:35:02 2010
New Revision: 997722

URL: http://svn.apache.org/viewvc?rev=997722&view=rev
Log:
DERBY-1511: SELECT clause without a WHERE, causes an Exception when
extracting a Blob from a database

Disable bulk fetching for table scans that fetch BLOB or CLOB columns,
if the cursor is holdable, as the large objects in the internal buffer
will not survive across transaction boundaries.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BaseJoinStrategy.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NestedLoopJoinStrategy.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BulkTableScanResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java Thu
Sep 16 12:35:02 2010
@@ -324,6 +324,9 @@ public interface Optimizable {
 	/** Tell whether this Optimizable can be instantiated multiple times */
 	boolean supportsMultipleInstantiations();
 
+    /** Tell whether this Optimizable has any large object (LOB) columns. */
+    boolean hasLargeObjectColumns();
+
 	/** Get this Optimizable's result set number */
 	int getResultSetNumber();
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
Thu Sep 16 12:35:02 2010
@@ -969,6 +969,8 @@ public interface ResultSetFactory {
 								(in sys.systables)
 		@param isolationLevel	Isolation level (specified or not) to use on scans
 		@param rowsPerRead		The number of rows to read per fetch.
+        @param disableForHoldable Whether or not bulk fetch should be disabled
+                                  at runtime if the cursor is holdable.
 		@param oneRowScan		Whether or not this is a 1 row scan.
 		@param optimizerEstimatedRowCount	Estimated total # of rows by
 											optimizer
@@ -1001,6 +1003,7 @@ public interface ResultSetFactory {
 								boolean tableLocked,
 								int isolationLevel,
 								int rowsPerRead,
+                                boolean disableForHoldable,
 								boolean oneRowScan,
 								double optimizerEstimatedRowCount,
 								double optimizerEstimatedCost)

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BaseJoinStrategy.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BaseJoinStrategy.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BaseJoinStrategy.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BaseJoinStrategy.java
Thu Sep 16 12:35:02 2010
@@ -176,6 +176,10 @@ abstract class BaseJoinStrategy implemen
 
 		if (bulkFetch > 0) {
 			mb.push(bulkFetch);
+            // If the table references LOBs, we want to disable bulk fetching
+            // when the cursor is holdable. Otherwise, a commit could close
+            // LOBs before they have been returned to the user.
+            mb.push(innerTable.hasLargeObjectColumns());
 		}
 
 		/* 1 row scans (avoiding 2nd next()) are

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java Thu Sep
16 12:35:02 2010
@@ -742,6 +742,26 @@ abstract class FromTable extends ResultS
 		return false;
 	}
 
+    /**
+     * Check if any columns containing large objects (BLOBs or CLOBs) are
+     * referenced in this table.
+     *
+     * @return {@code true} if at least one large object column is referenced,
+     * {@code false} otherwise
+     */
+    public boolean hasLargeObjectColumns() {
+        for (int i = 0; i < resultColumns.size(); i++) {
+            ResultColumn rc = (ResultColumn) resultColumns.elementAt(i);
+            if (rc.isReferenced()) {
+                DataTypeDescriptor type = rc.getType();
+                if (type != null && type.getTypeId().isLOBTypeId()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
 	/** @see Optimizable#isMaterializable 
 	 *
 	 * @exception StandardException		Thrown on error

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NestedLoopJoinStrategy.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NestedLoopJoinStrategy.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NestedLoopJoinStrategy.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NestedLoopJoinStrategy.java
Thu Sep 16 12:35:02 2010
@@ -238,7 +238,11 @@ public class NestedLoopJoinStrategy exte
 		}
 		else if (bulkFetch > 1)
 		{
-			numArgs = 25;
+            // Bulk-fetch uses TableScanResultSet arguments plus two
+            // additional arguments: 1) bulk fetch size, and 2) whether the
+            // table contains LOB columns (used at runtime to decide if
+            // bulk fetch is safe DERBY-1511).
+            numArgs = 26;
 		}
 		else
 		{

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BulkTableScanResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BulkTableScanResultSet.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BulkTableScanResultSet.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BulkTableScanResultSet.java
Thu Sep 16 12:35:02 2010
@@ -102,6 +102,7 @@ class BulkTableScanResultSet extends Tab
 		boolean tableLocked,
 		int isolationLevel,
 		int rowsPerRead,
+        boolean disableForHoldable,
 		boolean oneRowScan,
 		double optimizerEstimatedRowCount,
 		double optimizerEstimatedCost)
@@ -128,7 +129,7 @@ class BulkTableScanResultSet extends Tab
 			lockMode,
 			tableLocked,
 			isolationLevel,
-			rowsPerRead,
+            adjustBulkFetchSize(activation, rowsPerRead, disableForHoldable),
 			oneRowScan,
 			optimizerEstimatedRowCount,
 			optimizerEstimatedCost);
@@ -156,6 +157,31 @@ class BulkTableScanResultSet extends Tab
     }
 
     /**
+     * Adjust the bulk fetch size according to the parameters. Bulk fetch may
+     * be disabled by returning 1 from this method. Disabling of bulk fetch
+     * may happen if the cursor is holdable and it contains LOB columns
+     * (DERBY-1511) because
+     *
+     * @param activation the activation for the executing statement
+     * @param rowsPerRead how many rows to read in each chunk if a bulk fetch
+     * is OK to use
+     * @param disableForHoldable whether or not bulk fetch should be disabled
+     * for holdable cursors
+     * @return the bulk fetch size to use
+     */
+    private static int adjustBulkFetchSize(
+            Activation activation, int rowsPerRead, boolean disableForHoldable)
+    {
+        if (disableForHoldable && activation.getResultSetHoldability()) {
+            // We have a holdable cursor, and we've been requested to disable
+            // bulk fetch if the cursor is holdable, so change bulk size to 1.
+            return 1;
+        } else {
+            return rowsPerRead;
+        }
+    }
+
+    /**
  	 * Open the scan controller
 	 *
 	 * @param tc transaction controller will open one if null

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
Thu Sep 16 12:35:02 2010
@@ -679,6 +679,7 @@ public class GenericResultSetFactory imp
 									boolean tableLocked,
 									int isolationLevel,
 									int rowsPerRead,
+                                    boolean disableForHoldable,
 									boolean oneRowScan,
 									double optimizerEstimatedRowCount,
 									double optimizerEstimatedCost)
@@ -716,6 +717,7 @@ public class GenericResultSetFactory imp
 								tableLocked,
 								isolationLevel,
 								rowsPerRead,
+                                disableForHoldable,
 								oneRowScan,
 								optimizerEstimatedRowCount,
 								optimizerEstimatedCost);

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
Thu Sep 16 12:35:02 2010
@@ -2426,6 +2426,7 @@ class InsertResultSet extends DMLWriteRe
                     true,					// table locked
                     tc.ISOLATION_READ_COMMITTED,
                     LanguageProperties.BULK_FETCH_DEFAULT_INT,	// rows per read
+                    false,                  // never disable bulk fetch
                     false,					// not a 1 row per scan
                     0d,						// estimated rows
                     0d 					// estimated cost

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
Thu Sep 16 12:35:02 2010
@@ -680,6 +680,45 @@ final public class BLOBTest extends Base
         s2.close();
     }
 
+    /**
+     * Regression test case for DERBY-1511. Scans of tables with large objects
+     * used to fail if commits were issued during the scans.
+     */
+    public void testDerby1511() throws Exception {
+        setAutoCommit(false);
+
+        Statement s = createStatement();
+        s.executeUpdate("create table derby1511(b blob)");
+
+        PreparedStatement insert = prepareStatement(
+                "insert into derby1511(b) values (?)");
+
+        int rows = 20;
+        int length = 40000; // LOB size should be > 32 KB to expose the bug
+                            // (otherwise, materialization happens and a
+                            // different code path is taken)
+
+        for (int i = 0; i < rows; i++) {
+            insert.setBinaryStream(
+                    1, new LoopingAlphabetStream(length), length);
+            insert.executeUpdate();
+        }
+
+        commit();
+
+        ResultSet rs = s.executeQuery("select b from derby1511");
+        for (int i = 0; i < rows; i++) {
+            assertTrue("Too few rows", rs.next());
+            // Second time this was called we used to get an error saying
+            // container has been closed.
+            assertEquals(new LoopingAlphabetStream(length),
+                         rs.getBinaryStream(1));
+            commit();
+        }
+
+        assertFalse("Too many rows", rs.next());
+        rs.close();
+    }
 
     /**
      * Verifies that the table has row with column val=newVal

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java?rev=997722&r1=997721&r2=997722&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java
Thu Sep 16 12:35:02 2010
@@ -2933,6 +2933,10 @@ public class BlobClob4BlobTest extends B
      * is thrown instead of an NPE.
      * Basically per the spec, getBlob is valid only for the duration of
      * the transaction it was created in
+     * Updated for DERBY-1511: The test case wasn't supposed to fail in the
+     * first place (neither with NPE nor with "proper user error") since none
+     * of the BLOBs are accessed after the transaction that created them was
+     * completed.
      * @throws Exception
      * @throws FileNotFoundException
      * @throws IOException
@@ -2967,18 +2971,14 @@ public class BlobClob4BlobTest extends B
         rs1.next();
         Blob b1 = rs1.getBlob(2);
         rs1.close();
-        try {
-            rs2.next();
-            rs2.getBlob(2);
-            fail("FAIL - can not access blob after implicit commit");
-        } catch (SQLException sqle) {
-            checkException(BLOB_ACCESSED_AFTER_COMMIT, sqle);
-        } finally {
-            rs2.close();
-            s2.close();
-            s.close();
-            ps.close();
-        }
+
+        // DERBY-1511: Fetching the next BLOB here used to fail because it
+        // had been pre-fetched before the commit and was closed in the commit.
+        // Now, we don't pre-fetch BLOBs anymore, so expect to get a working
+        // object here.
+        assertTrue(rs2.next());
+        assertNotNull(rs2.getBlob(2));
+        rs2.close();
     }
 
     /**
@@ -2988,6 +2988,10 @@ public class BlobClob4BlobTest extends B
      * is thrown instead of an NPE.
      * Basically per the spec, getClob is valid only for the duration of
      * the transaction in it was created in
+     * Updated for DERBY-1511: The test case wasn't supposed to fail in the
+     * first place (neither with NPE nor with "proper user error") since none
+     * of the CLOBs are accessed after the transaction that created them was
+     * completed.
      * @throws Exception
      */
     public void testNegativeTestDerby265Clob() throws Exception {
@@ -3021,18 +3025,14 @@ public class BlobClob4BlobTest extends B
         rs1.next();
         Clob b1 = rs1.getClob(2);
         rs1.close();
-        try {
-            rs2.next();
-            rs2.getClob(2);
-            fail("FAIL - can not access blob after implicit commit");
-        } catch (SQLException sqle) {
-            checkException(BLOB_ACCESSED_AFTER_COMMIT, sqle);
-        } finally {
-            rs2.close();
-            s2.close();
-            s.close();
-            ps.close();
-        }
+
+        // DERBY-1511: Fetching the next CLOB here used to fail because it
+        // had been pre-fetched before the commit and was closed in the commit.
+        // Now, we don't pre-fetch CLOBs anymore, so expect to get a working
+        // object here.
+        assertTrue(rs2.next());
+        assertNotNull(rs2.getClob(2));
+        rs2.close();
     }
 
     public static Test suite() {
@@ -3518,9 +3518,7 @@ public class BlobClob4BlobTest extends B
     private static final String LANG_DATA_TYPE_GET_MISMATCH = "22005";
     private static final String BLOB_NULL_PATTERN_OR_SEARCH_STR = "XJ072";
     private static final String LOCK_TIMEOUT = "40XL1";
-    private static final String BLOB_ACCESSED_AFTER_COMMIT = "XJ073";
     private static final String NO_CURRENT_CONNECTION = "08003";
     private static final String INVALID_LOB = "XJ215";
-    private static final String INVALID_LOCATOR = "XJ217";
 
 }



Mime
View raw message