db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
Subject svn commit: r427969 - in /db/derby/code/trunk/java: client/org/apache/derby/client/am/ByteArrayCombinerStream.java client/org/apache/derby/client/am/Lob.java testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java
Date Wed, 02 Aug 2006 12:50:33 GMT
Author: rhillegas
Date: Wed Aug  2 05:50:33 2006
New Revision: 427969

URL: http://svn.apache.org/viewvc?rev=427969&view=rev
Log:
DERBY-1417: Commit derby-1417-7a-clientborderfix.diff, fixing a hang on a border condition.

Modified:
    db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java
    db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java?rev=427969&r1=427968&r2=427969&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java
(original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/ByteArrayCombinerStream.java
Wed Aug  2 05:50:33 2006
@@ -35,10 +35,17 @@
  * the byte buffer, or doing a single big copy to combine the byte arrays in
  * the end. This is important for the temporary solution, since we must
  * materialize the stream to find the length anyway.
+ *
+ * If there is less data available than the specified length, an exception is
+ * thrown. Available data is determined by the length of the byte arrays, not
+ * the contents of them. A byte array with all 0's is considered valid data.
+ *
+ * Besides from truncation, this stream does not change the underlying data in
+ * any way.
  */
 public class ByteArrayCombinerStream
     extends InputStream {
-    
+
     /** A list of the arrays to combine. */
     private final ArrayList arrays;
     /** Length of the stream. */
@@ -50,8 +57,8 @@
     /** The array we are currently reading from. */
     private byte[] curArray;
     /** The local offset into the current array. */
-    private int off = 0; 
-    
+    private int off = 0;
+
     /**
      * Create a stream whose source is a list of byte arrays.
      *
@@ -59,27 +66,37 @@
      *      byte arrays. The references are copied to a new
      *      <code>ArrayList</code> instance.
      * @param length the length of the stream. Never published outside
-     *      this object
+     *      this object. Note that the length specified can be shorter
+     *      than the actual number of bytes in the byte arrays.
+     * @throws IllegalArgumentException if there is less data available than
+     *      specified by <code>length</code>, or <code>length</code>
is
+     *      negative.
      */
     public ByteArrayCombinerStream(ArrayList arraysIn, long length) {
+        // Don't allow negative length.
+        if (length < 0) {
+            throw new IllegalArgumentException("Length cannot be negative: " +
+                    length);
+        }
         this.specifiedLength = length;
+        long tmpRemaining = length;
         if (arraysIn != null && arraysIn.size() > 0) {
             // Copy references to the byte arrays to a new ArrayList.
             int arrayCount = arraysIn.size();
-            long tmpRemaining = length;
             byte[] tmpArray;
             arrays = new ArrayList(arrayCount);
             // Truncate data if there are more bytes then specified.
             // Done to simplify boundary checking in the read-methods.
-            for (int i=0; i < arrayCount; i++) {
+            for (int i=0; i < arrayCount && tmpRemaining > 0; i++) {
                 tmpArray = (byte[])arraysIn.get(i);
                 if (tmpRemaining < tmpArray.length) {
                     // Create a new shrunk array.
-                    byte[] shrunkArray = 
+                    byte[] shrunkArray =
                         new byte[(int)(tmpRemaining)];
-                    System.arraycopy(tmpArray, 0, 
+                    System.arraycopy(tmpArray, 0,
                                      shrunkArray, 0, shrunkArray.length);
                     arrays.add(shrunkArray);
+                    tmpRemaining -= shrunkArray.length;
                     break;
                 } else {
                     // Add the whole array.
@@ -94,6 +111,12 @@
             gOffset = length;
             arrays = null;
         }
+        // If we don't have enough data, throw exception.
+        if (tmpRemaining > 0) {
+            throw new IllegalArgumentException("Not enough data, " + 
+                    tmpRemaining + " bytes short of specified length " +
+                    length);
+        }
     }
 
     /**
@@ -143,7 +166,7 @@
         } else {
             int toRead = 0;
             while (curArray != null && read < length) {
-                toRead = Math.min(curArray.length, length - read);
+                toRead = Math.min(curArray.length - off, length - read);
                 System.arraycopy(curArray, off, buf, offset + read, toRead);
                 read += toRead;
                 gOffset += toRead;

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java?rev=427969&r1=427968&r2=427969&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Lob.java Wed Aug  2 05:50:33
2006
@@ -137,7 +137,9 @@
                         curBytes = new byte[GROWBY];
                     }
                 }
-                totalLength += partLength;
+                if (partLength > 0) {
+                    totalLength += partLength;
+                }
             } while (partLength == GROWBY);
             // Make sure stream is exhausted.
             if (is.read() != -1) {
@@ -149,7 +151,9 @@
                                 typeDesc
                         );
             }
-            byteArrays.add(curBytes);
+            if (partLength > 0) {
+                byteArrays.add(curBytes);
+            }
 
             // Cleanup and set state.
             curBytes = null;

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java?rev=427969&r1=427968&r2=427969&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/ByteArrayCombinerStreamTest.java
Wed Aug  2 05:50:33 2006
@@ -39,27 +39,27 @@
             77,78,79,80,81,82,83,84,85,86,87,88};
 
     private ByteArrayCombinerStream combiner;
-    
+
     public ByteArrayCombinerStreamTest(String name) {
         super(name);
     }
 
     public void testCombineNullRead()
             throws IOException {
-        combiner = new ByteArrayCombinerStream(null, 10);
+        combiner = new ByteArrayCombinerStream(null, 0);
         assertEquals(-1, combiner.read());
     }
 
     public void testCombineNullReadArray()
             throws IOException {
-        combiner = new ByteArrayCombinerStream(null, 10);
+        combiner = new ByteArrayCombinerStream(null, 0);
         assertEquals(-1, combiner.read(new byte[10], 0, 10));
     }
 
     public void testCombineAvailableNull()
             throws IOException {
-        combiner = new ByteArrayCombinerStream(null, -34);
-        assertEquals(0, combiner.available()); 
+        combiner = new ByteArrayCombinerStream(null, 0);
+        assertEquals(0, combiner.available());
     }
 
     public void testCombineAvailable4bytes()
@@ -68,16 +68,37 @@
         ArrayList list = new ArrayList(1);
         list.add(array);
         combiner = new ByteArrayCombinerStream(list, 4);
-        assertEquals(4, combiner.available()); 
+        assertEquals(4, combiner.available());
+    }
+
+    /**
+     * Make sure an extra "empty" array doesn't cause errors.
+     * This test is based on knowledge of the implementation, where an extra
+     * byte array was not removed during the reducation process. This can
+     * cause <code>nextArray</code> to not return <code>null</code>
when it
+     * should, causing an <code>ArrayIndexOutOfBoundsException</code>.
+     * This bug was corrected by DERBY-1417.
+     */
+    public void testCombineWithExtraEmptyByteArray()
+            throws IOException {
+        byte[] array = {65,66,77,79};
+        ArrayList list = new ArrayList(2);
+        list.add(array);
+        list.add(new byte[4]);
+        combiner = new ByteArrayCombinerStream(list, array.length);
+        byte[] resArray = new byte[array.length];
+        assertEquals(array.length,
+                     combiner.read(resArray, 0, resArray.length));
+        assertTrue(combiner.read() == -1);
     }
-    
+
     public void testCombineOneArray()
             throws IOException {
         ArrayList list = new ArrayList(1);
         list.add(defaultArray);
         combiner = new ByteArrayCombinerStream(list, defaultArray.length);
         byte[] resArray = new byte[defaultArray.length];
-        assertEquals(defaultArray.length, 
+        assertEquals(defaultArray.length,
                      combiner.read(resArray,0, resArray.length));
         assertTrue(combiner.read() == -1);
         assertTrue(Arrays.equals(defaultArray, resArray));
@@ -106,7 +127,7 @@
         assertTrue(combiner.read() == -1);
         assertTrue(Arrays.equals(targetArray, resArray));
     }
-    
+
     public void testTruncateDataFromOneArray()
             throws IOException {
         int length = defaultArray.length -5;
@@ -121,7 +142,7 @@
         assertTrue(combiner.read() == -1);
         assertTrue(Arrays.equals(targetArray, resArray));
     }
-    
+
     public void testTruncateDataFromTwoArrays()
             throws IOException {
         int length = (defaultArray.length *2) -7;
@@ -132,7 +153,7 @@
         System.arraycopy(defaultArray, 0,
                          targetArray, 0, defaultArray.length);
         System.arraycopy(defaultArray, 0,
-                         targetArray, defaultArray.length, 
+                         targetArray, defaultArray.length,
                          length - defaultArray.length);
         byte[] resArray = new byte[length];
         combiner = new ByteArrayCombinerStream(list, length);
@@ -140,4 +161,81 @@
         assertTrue(combiner.read() == -1);
         assertTrue(Arrays.equals(targetArray, resArray));
     }
-} // End class ByteArrayCombinerStreamTest 
+
+    /**
+     * Make sure an exception is thrown if there is less data available than
+     * the specified length.
+     */
+    public void testTooLittleDataNoCombine() {
+        ArrayList list = new ArrayList(1);
+        list.add(new byte[5]);
+        try {
+            combiner = new ByteArrayCombinerStream(list, 10);
+            fail("An IllegalArgumentException singalling too little data " +
+                    "should have been thrown");
+        } catch (IllegalArgumentException iae) {
+            // This should happen, continue.
+        }
+    }
+
+    /**
+     * Make sure an exception is thrown if there is less data available than
+     * the specified length.
+     */
+    public void testTooLittleDataWithCombine() {
+        ArrayList list = new ArrayList(3);
+        byte[] data = {65,66,67,68,69};
+        list.add(data);
+        list.add(data);
+        list.add(data);
+        try {
+            combiner = new ByteArrayCombinerStream(list, data.length *3 + 1);
+            fail("An IllegalArgumentException singalling too little data " +
+                    "should have been thrown");
+        } catch (IllegalArgumentException iae) {
+            // This should happen, continue.
+        }
+    }
+
+    /**
+     * Make sure an exception is thrown if a negative length is specified.
+     */
+    public void testNegativeLengthArgument() {
+        ArrayList list = new ArrayList(1);
+        list.add(new byte[1234]);
+        try {
+            combiner = new ByteArrayCombinerStream(list, -54);
+            fail("An IllegalArgumentException singalling negative length " +
+                    "should have been thrown");
+        } catch (IllegalArgumentException iae) {
+            // This should happen, continue.
+
+        }
+    }
+
+    /**
+     * Demonstrate that the stream does not change negative values in the
+     * underlying data.
+     * This can cause code to believe the stream is exhausted even though it is
+     * not.
+     */
+    public void testNegativeValueInDataCausesEndOfStream()
+            throws IOException {
+        byte[] data = {66,67,-123,68,69};
+        byte[] targetData = {66,67,0,0,0};
+        byte[] resData = new byte[5];
+        ArrayList list = new ArrayList(1);
+        list.add(data);
+        combiner = new ByteArrayCombinerStream(list, data.length);
+        byte b;
+        int index = 0;
+        while ((b = (byte)combiner.read()) > 0) {
+            resData[index++] = b;
+        }
+        assertTrue(Arrays.equals(targetData, resData));
+        // Even though we think the stream is exhausted, it is not...
+        assertEquals(data[3], (byte)combiner.read());
+        assertEquals(data[4], (byte)combiner.read());
+        assertEquals(-1, (byte)combiner.read());
+    }
+} // End class ByteArrayCombinerStreamTest



Mime
View raw message