Return-Path: Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: (qmail 49119 invoked from network); 26 Jan 2010 13:39:39 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 26 Jan 2010 13:39:39 -0000 Received: (qmail 46526 invoked by uid 500); 26 Jan 2010 13:39:39 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 46468 invoked by uid 500); 26 Jan 2010 13:39:39 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" List-Id: Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 46459 invoked by uid 99); 26 Jan 2010 13:39:39 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 26 Jan 2010 13:39:39 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 26 Jan 2010 13:39:38 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id BC8EE23888EC; Tue, 26 Jan 2010 13:39:17 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit 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 -0000 To: derby-commits@db.apache.org From: kristwaa@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100126133917.BC8EE23888EC@eris.apache.org> 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. + *

+ * 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.