db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From krist...@apache.org
Subject svn commit: r903222 - in /db/derby/code/branches/10.5: ./ java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
Date Tue, 26 Jan 2010 13:39:17 GMT
Author: kristwaa
Date: Tue Jan 26 13:39:17 2010
New Revision: 903222

URL: http://svn.apache.org/viewvc?rev=903222&view=rev
Log:
DERBY-4102: Assert failure or ClassCastException in EmbedBlob when retrieving BLOB >= 32K
Merged fix from trunk (r835286, derby-4102-1a.diff).

Modified:
    db/derby/code/branches/10.5/   (props changed)
    db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
    db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java

Propchange: db/derby/code/branches/10.5/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Jan 26 13:39:17 2010
@@ -1 +1 @@
-/db/derby/code/trunk:769596,769602,769606,769962,772090,772337,772449,772534,774281,777105,779681,782991,785131,785139,785163,785570,785662,788369,788670,788674,788968,789264,790218,792434,793089,793588,794106,794303,794955,795166,796020,796027,796316,796372,797147,798347,798742,800523,803548,803948,805696,808494,808850,809643,810860,812669,816531,816536,819006,822289,823659,824694,829022,832379,833430,882732,884163,887246,892912,897161,901165,901648,901760
+/db/derby/code/trunk:769596,769602,769606,769962,772090,772337,772449,772534,774281,777105,779681,782991,785131,785139,785163,785570,785662,788369,788670,788674,788968,789264,790218,792434,793089,793588,794106,794303,794955,795166,796020,796027,796316,796372,797147,798347,798742,800523,803548,803948,805696,808494,808850,809643,810860,812669,816531,816536,819006,822289,823659,824694,829022,832379,833430,835286,882732,884163,887246,892912,897161,901165,901648,901760

Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java?rev=903222&r1=903221&r2=903222&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java Tue
Jan 26 13:39:17 2010
@@ -27,6 +27,7 @@
 import org.apache.derby.iapi.jdbc.EngineLOB;
 import org.apache.derby.iapi.services.sanity.SanityManager;
 import org.apache.derby.iapi.types.DataValueDescriptor;
+import org.apache.derby.iapi.types.RawToBinaryFormatStream;
 import org.apache.derby.iapi.types.Resetable;
 import org.apache.derby.iapi.services.io.InputStreamUtil;
 
@@ -159,9 +160,20 @@
         if (SanityManager.DEBUG)
             SanityManager.ASSERT(!dvd.isNull(), "blob is created on top of a null column");
 
+        /*
+           We support three scenarios at this point:
+            a) The Blob value is already represented as bytes in memory.
+               This is the case for small Blobs (less than 32 KB).
+            b) The Blob value is represented as a resetable stream.
+               This is the case for Blobs coming from the store
+               (note the comment about SQLBit below).
+            c) The Blob value is represented as a wrapped user stream.
+               This stream cannot be reset, which means we have to drain the
+               stream and store it temporarily until it is either discarded or
+               inserted into the database.
+         */
         InputStream dvdStream = dvd.getStream();
-        if (dvdStream == null)
-        {
+        if (dvdStream == null) { // a) Blob already materialized in memory
             materialized = true;
             streamPositionOffset = Integer.MIN_VALUE;
             // copy bytes into memory so that blob can live after result set
@@ -177,9 +189,7 @@
                 throw StandardException.newException (
                                         SQLState.SET_STREAM_FAILURE, e);
             }
-        }
-        else
-        {
+        } else if (dvdStream instanceof Resetable) { // b) Resetable stream
             materialized = false;
 
             /*
@@ -215,6 +225,39 @@
                 throw StandardException.newException(
                      SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION, ioe, "BLOB");
             }
+        } else { // c) Non-resetable stream
+            // The code below will only work for RawToBinaryFormatStream.
+            if (SanityManager.DEBUG) {
+                SanityManager.ASSERT(
+                        dvdStream instanceof RawToBinaryFormatStream,
+                        "Invalid stream type: " + dvdStream.getClass());
+            }
+            // The source stream isn't resetable, so we have to write it to a
+            // temporary location to be able to support the Blob operations.
+            materialized = true;
+            streamPositionOffset = Integer.MIN_VALUE;
+            try {
+                control = new LOBStreamControl(getEmbedConnection());
+                BinaryToRawStream tmpStream =
+                        new BinaryToRawStream(dvdStream, con);
+                // Transfer the data.
+                byte[] bytes = new byte[4096]; // 4 KB buffer
+                long pos = 0;
+                while (true) {
+                    int read = tmpStream.read(bytes, 0, bytes.length);
+                    if (read < 1) {
+                        // Reached EOF, or stream is behaving badly.
+                        break;
+                    }
+                    // If the stream is larger than the maximum allowed by
+                    // Derby, the call below will thrown an exception.
+                    pos = control.write(bytes, 0, read, pos);
+                }
+                tmpStream.close();
+            } catch (IOException ioe) {
+                throw StandardException.newException (
+                                        SQLState.SET_STREAM_FAILURE, ioe);
+            }
         }
         //add entry in connection so it can be cleared 
         //when transaction is not valid

Modified: db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java?rev=903222&r1=903221&r2=903222&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
(original)
+++ db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BLOBTest.java
Tue Jan 26 13:39:17 2010
@@ -31,6 +31,7 @@
 import java.sql.SQLException;
 import java.io.IOException;
 import java.io.InputStream;
+import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetStream;
 
 /**
  * Tests reading and updating binary large objects (BLOBs).
@@ -349,7 +350,35 @@
         verifyNewValueInTable(newVal, newSize);
     }
     
-    
+    /**
+     * Tests that a stream value in a values clause can be cast to a BLOB.
+     * <p>
+     * See DERBY-4102 (test case resulted in a ClassCastException earlier).
+     *
+     * @throws IOException if something goes wrong
+     * @throws SQLException if something goes wrong
+     */
+    public void testBlobCastInValuesClause()
+            throws IOException, SQLException {
+        // The length must be at least 32 KB.
+        final int length = 38*1024;
+        PreparedStatement ps = prepareStatement("values cast(? as blob)");
+        ps.setBinaryStream(1, new LoopingAlphabetStream(length), length);
+        ResultSet rs = ps.executeQuery();
+        assertTrue(rs.next());
+        Blob b = rs.getBlob(1);
+        assertEquals(length, b.length());
+        // Select some parts of the Blob, moving backwards.
+        assertEquals(100, b.getBytes(32*1024-27, 100).length);
+        assertEquals(1029, b.getBytes(19*1024, 1029).length);
+        // Compare a fresh stream with the one from the Blob.
+        assertEquals(new LoopingAlphabetStream(length), b.getBinaryStream());
+        assertEquals(-1, b.position(new byte[] {(byte)'a', (byte)'A'}, 1));
+        assertEquals(length, b.length());
+        assertFalse(rs.next());
+        rs.close();
+    }
+
     /**
      * Verifies that the table has row with column val=newVal
      * and that it its data and size columns are consistent.



Mime
View raw message