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 kr...@apache.org on 2008/10/31 14:39:44 UTC

svn commit: r709408 - in /db/derby/code/branches/10.4/java: engine/org/apache/derby/impl/jdbc/EmbedBlob.java engine/org/apache/derby/impl/jdbc/LOBStreamControl.java testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java

Author: kristwaa
Date: Fri Oct 31 06:39:43 2008
New Revision: 709408

URL: http://svn.apache.org/viewvc?rev=709408&view=rev
Log:
DERBY-3871: EmbedBlob.setBytes returns incorrect insertion count.
Backported revisions 701372 (1a) and 701979 (2a) to 10.4.

Modified:
    db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
    db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java
    db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java

Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java?rev=709408&r1=709407&r2=709408&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java Fri Oct 31 06:39:43 2008
@@ -793,39 +793,40 @@
 	/////////////////////////////////////////////////////////////////////////
 
 	/**
-    * JDBC 3.0
-    *
-    * Writes the given array of bytes to the BLOB value that this Blob object
-    * represents, starting at position pos, and returns the number of bytes written.
-    *
-    * @param pos - the position in the BLOB object at which to start writing
-    * @param bytes - the array of bytes to be written to the BLOB value that this
-    * Blob object represents
-    * @return the number of bytes written
-    * @exception SQLException Feature not implemented for now.
-	*/
+     * Writes the given array of bytes to the BLOB value that this Blob object
+     * represents, starting at position pos, and returns the number of bytes
+     * written.
+     *
+     * @param pos the position in the BLOB object at which to start writing
+     * @param bytes the array of bytes to be written to the BLOB value that this
+     *       Blob object represents
+     * @return The number of bytes written to the BLOB.
+     * @throws SQLException if writing the bytes to the BLOB fails
+     * @since 1.4
+	 */
 	public int setBytes(long pos, byte[] bytes) throws SQLException {
             return setBytes(pos, bytes, 0, bytes.length);
 	}
 
-   /**
-    * JDBC 3.0
-    *
-    * Writes all or part of the given array of byte array to the BLOB value that
-    * this Blob object represents and returns the number of bytes written.
-    * Writing starts at position pos in the BLOB value; len bytes from the given
-    * byte array are written.
-    *
-    * @param pos - the position in the BLOB object at which to start writing
-    * @param bytes - the array of bytes to be written to the BLOB value that this
-    * Blob object represents
-    * @param offset - the offset into the array bytes at which to start reading
-    * the bytes to be set
-    * @param len - the number of bytes to be written to the BLOB value from the
-    * array of bytes bytes
-    * @return the number of bytes written
-    * @exception SQLException Feature not implemented for now.
-	*/
+    /**
+     * Writes all or part of the given array of byte array to the BLOB value
+     * that this Blob object represents and returns the number of bytes written.
+     * Writing starts at position pos in the BLOB value; len bytes from the
+     * given byte array are written.
+     *
+     * @param pos the position in the BLOB object at which to start writing
+     * @param bytes the array of bytes to be written to the BLOB value that this
+     *       Blob object represents
+     * @param offset the offset into the byte array at which to start reading
+     *       the bytes to be written
+     * @param len the number of bytes to be written to the BLOB value from the
+     *       array of bytes bytes
+     * @return The number of bytes written to the BLOB.
+     * @throws SQLException if writing the bytes to the BLOB fails
+     * @throws IndexOutOfBoundsException if {@code len} is larger than
+     *       {@code bytes.length - offset}
+     * @since 1.4
+	 */
     public int setBytes(long pos,
             byte[] bytes,
             int offset,
@@ -839,12 +840,12 @@
                 if (pos < 1)
                     throw Util.generateCsSQLException(
                         SQLState.BLOB_BAD_POSITION, new Long(pos));
-                len = (int) control.write (bytes, offset, len, pos - 1);
+                control.write (bytes, offset, len, pos - 1);
             }
             else {
                 control = new LOBStreamControl (getEmbedConnection());
                 control.copyData (myStream, length());
-                len = (int) control.write(bytes, offset, len, pos - 1);
+                control.write(bytes, offset, len, pos - 1);
                 myStream.close();
                 streamLength = -1;
                 materialized = true;

Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java?rev=709408&r1=709407&r2=709408&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java Fri Oct 31 06:39:43 2008
@@ -214,13 +214,17 @@
     }
 
     /**
-     * Writes part of the byte array.
+     * Writes {@code len} bytes from the specified byte array to the LOB.
+     *
      * @param b byte array
      * @param off offset from where to read from the byte array
-     * @param len number of bytes to be copied
-     * @param pos starting postion
-     * @return new postion
-     * @throws IOException, StandardException
+     * @param len number of bytes to be written
+     * @param pos starting position
+     * @return The position after the bytes have been written to the LOB.
+     * @throws IOException if writing to the LOB fails
+     * @throws StandardException if writing to the LOB fails
+     * @throws IndexOutOfBoundsException if {@code len} is larger than
+     *       {@code b.length - off}
      */
     synchronized long write(byte[] b, int off, int len, long pos)
             throws IOException, StandardException {

Modified: db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java?rev=709408&r1=709407&r2=709408&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java (original)
+++ db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java Fri Oct 31 06:39:43 2008
@@ -610,6 +610,76 @@
      }
      
     /**
+     * Tests the return count on insertion when the Blob is represented as a
+     * byte array in memory.
+     */
+    public void testSetBytesReturnValueSmall()
+            throws SQLException {
+        Blob myBlob = getConnection().createBlob();
+        byte[] byteBatch = new byte[] {
+                    0x65, 0x66, 0x67, 0x68, 0x69,
+                    0x65, 0x66, 0x67, 0x68, 0x69
+                };
+        assertEquals("Wrong insertion count",
+                byteBatch.length, myBlob.setBytes(1, byteBatch));
+        // Try again, overwrites the bytes.
+        assertEquals("Wrong insertion count",
+                byteBatch.length, myBlob.setBytes(1, byteBatch));
+        // Last time, start at a different index.
+        assertEquals("Wrong insertion count",
+                byteBatch.length, myBlob.setBytes(4, byteBatch));
+    }
+
+    /**
+     * Tests the return count on insertion when the Blob is represented as a
+     * temporary file on disk.
+     */
+    public void testSetBytesReturnValueLarge()
+            throws IOException, SQLException {
+        Blob myBlob = getConnection().createBlob();
+        // Insert one MB, should cause Blob to spill to disk.
+        OutputStream blobWriter = myBlob.setBinaryStream(1);
+        transferAlphabetData(blobWriter, 1*1024*1024);
+        byte[] byteBatch = new byte[] {
+                    0x65, 0x66, 0x67, 0x68, 0x69,
+                    0x65, 0x66, 0x67, 0x68, 0x69
+                };
+        assertEquals("Wrong insertion count",
+                byteBatch.length, myBlob.setBytes(1, byteBatch));
+        // Try again, overwrites the bytes.
+        assertEquals("Wrong insertion count",
+                byteBatch.length, myBlob.setBytes(1, byteBatch));
+        // Start at a different, low index.
+        assertEquals("Wrong insertion count",
+                byteBatch.length, myBlob.setBytes(4, byteBatch));
+        // Start at a different, higher index.
+        assertEquals("Wrong insertion count",
+                byteBatch.length, myBlob.setBytes(512*1024, byteBatch));
+    }
+
+    /**
+     * Tests the return count on insertion when the Blob is fetched from the
+     * database and then modified.
+     * <p>
+     * The main point for this test is to provoke the transition from a
+     * read-only internal representation to a writable representation.
+     * For a Blob of "considerable" size, this involved going from a store
+     * stream representation to a {@code LOBStreamControl} representation using
+     * a temporary file.
+     */
+    public void testSetBytesReturnValueLargeStateChange()
+            throws IOException, SQLException {
+        // Get a Blob from the database, don't create an empty one.
+        initializeLongBlob(); // Ignoring id for now, use instance variable.
+        assertEquals("Wrong insertion count",
+                1, blob.setBytes(30000, new byte[] {0x69}));
+        assertEquals("Wrong insertion count",
+                1, blob.setBytes(1, new byte[] {0x69}));
+        assertEquals("Wrong insertion count",
+                2, blob.setBytes(1235, new byte[] {0x69, 0x69}));
+    }
+
+    /**
      * Test that a lock held on the corresponding row is released when free() is
      * called on the Blob object.
      * @throws java.sql.SQLException 
@@ -740,6 +810,23 @@
         }
     }
 
+    /**
+     * Transfers the specified number of bytes generated from the modern latin
+     * alphabet (lowercase) to the destination stream.
+     *
+     * @param writer the destination
+     * @param length number of bytes to write
+     * @throws IOException if writing to the destination stream fails
+     */
+    public static void transferAlphabetData(OutputStream writer, long length)
+            throws IOException {
+        byte[] buffer = new byte[8*1024];
+        int bytesRead = 0;
+        LoopingAlphabetStream contents = new LoopingAlphabetStream(length);
+        while ((bytesRead = contents.read(buffer)) > 0) {
+            writer.write(buffer, 0, bytesRead);
+        }
+    }
     
     /**
      * Create test suite for this test.