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 ka...@apache.org on 2011/08/30 10:21:53 UTC

svn commit: r1163131 - /db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java

Author: kahatlen
Date: Tue Aug 30 08:21:52 2011
New Revision: 1163131

URL: http://svn.apache.org/viewvc?rev=1163131&view=rev
Log:
DERBY-5236: Client driver silently truncates strings that exceed 32KB

Prepare the network client for the possibility that a column is split
over more than two blocks in the response. This cannot happen until a
fix that makes the server stop sending truncated strings, has been
checked in.

Modified:
    db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java?rev=1163131&r1=1163130&r2=1163131&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java Tue Aug 30 08:21:52 2011
@@ -413,18 +413,7 @@ public class NetCursor extends org.apach
 
 
     private int readFdocaInt() throws org.apache.derby.client.am.DisconnectException, SqlException {
-        if ((position_ + 4) > lastValidBytePosition_) {
-            // Check for ENDQRYRM, throw SqlException if already received one.
-            checkAndThrowReceivedEndqryrm();
-
-            // Send CNTQRY to complete the row/rowset.
-            int lastValidByteBeforeFetch = completeSplitRow();
-
-            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-            // throw a SqlException for the ENDQRYRM.
-            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
-        }
-
+        checkForSplitRowAndComplete(4);
         int i = SignedBinary.getInt(dataBuffer_, position_);
         position_ += 4;
         return i;
@@ -433,38 +422,14 @@ public class NetCursor extends org.apach
     // Reads 1-byte from the dataBuffer from the current position.
     // If position is already at the end of the buffer, send CNTQRY to get more data.
     private int readFdocaOneByte() throws org.apache.derby.client.am.DisconnectException, SqlException {
-        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-        // so there is no need to drive a flowFetch (continue query) request for singleton select.
-        if (position_ == lastValidBytePosition_) {
-            // Check for ENDQRYRM, throw SqlException if already received one.
-            checkAndThrowReceivedEndqryrm();
-
-            // Send CNTQRY to complete the row/rowset.
-            int lastValidByteBeforeFetch = completeSplitRow();
-
-            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-            // throw a SqlException for the ENDQRYRM.
-            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
-        }
+        checkForSplitRowAndComplete(1);
         return dataBuffer_[position_++] & 0xff;
     }
 
     // Reads 1-byte from the dataBuffer from the current position.
     // If position is already at the end of the buffer, send CNTQRY to get more data.
     private int readFdocaOneByte(int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
-        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-        // so there is no need to drive a flowFetch (continue query) request for singleton select.
-        if (position_ == lastValidBytePosition_) {
-            // Check for ENDQRYRM, throw SqlException if already received one.
-            checkAndThrowReceivedEndqryrm();
-
-            // Send CNTQRY to complete the row/rowset.
-            int lastValidByteBeforeFetch = completeSplitRow(index);
-
-            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-            // throw a SqlException for the ENDQRYRM.
-            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
-        }
+        checkForSplitRowAndComplete(1, index);
         return dataBuffer_[position_++] & 0xff;
     }
 
@@ -473,26 +438,11 @@ public class NetCursor extends org.apach
     // If current position plus length goes past the lastValidBytePosition, send
     // CNTQRY to get more data.
     private byte[] readFdocaBytes(int length) throws org.apache.derby.client.am.DisconnectException, SqlException {
-        byte[] b = new byte[length];
-        ;
-
-        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-        // so there is no need to drive a flowFetch (continue query) request for singleton select.
-        if ((position_ + length) > lastValidBytePosition_) {
-            // Check for ENDQRYRM, throw SqlException if already received one.
-            checkAndThrowReceivedEndqryrm();
-
-            // Send CNTQRY to complete the row/rowset.
-            int lastValidByteBeforeFetch = completeSplitRow();
+        checkForSplitRowAndComplete(length);
 
-            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-            // throw a SqlException for the ENDQRYRM.
-            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
-        }
-
-        for (int i = 0; i < length; i++) {
-            b[i] = dataBuffer_[position_++];
-        }
+        byte[] b = new byte[length];
+        System.arraycopy(dataBuffer_, position_, b, 0, length);
+        position_ += length;
 
         return b;
     }
@@ -501,40 +451,14 @@ public class NetCursor extends org.apach
     // returns an integer constructed from the 2-bytes.  If current position plus
     // 2 bytes goes past the lastValidBytePosition, send CNTQRY to get more data.
     private int readFdocaTwoByteLength() throws org.apache.derby.client.am.DisconnectException, SqlException {
-        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-        // so there is no need to drive a flowFetch (continue query) request for singleton select.
-        if ((position_ + 2) > lastValidBytePosition_) {
-            // Check for ENDQRYRM, throw SqlException if already received one.
-            checkAndThrowReceivedEndqryrm();
-
-            // Send CNTQRY to complete the row/rowset.
-            int lastValidByteBeforeFetch = completeSplitRow();
-
-            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-            // throw a SqlException for the ENDQRYRM.
-            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
-        }
-
+        checkForSplitRowAndComplete(2);
         return
                 ((dataBuffer_[position_++] & 0xff) << 8) +
                 ((dataBuffer_[position_++] & 0xff) << 0);
     }
 
     private int readFdocaTwoByteLength(int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
-        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-        // so there is no need to drive a flowFetch (continue query) request for singleton select.
-        if ((position_ + 2) > lastValidBytePosition_) {
-            // Check for ENDQRYRM, throw SqlException if already received one.
-            checkAndThrowReceivedEndqryrm();
-
-            // Send CNTQRY to complete the row/rowset.
-            int lastValidByteBeforeFetch = completeSplitRow(index);
-
-            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-            // throw a SqlException for the ENDQRYRM.
-            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
-        }
-
+        checkForSplitRowAndComplete(2, index);
         return
                 ((dataBuffer_[position_++] & 0xff) << 8) +
                 ((dataBuffer_[position_++] & 0xff) << 0);
@@ -545,38 +469,13 @@ public class NetCursor extends org.apach
     // length - number of bytes to skip
     // returns the number of bytes skipped
     private int skipFdocaBytes(int length) throws org.apache.derby.client.am.DisconnectException, SqlException {
-        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-        // so there is no need to drive a flowFetch (continue query) request for singleton select.
-        if ((position_ + length) > lastValidBytePosition_) {
-            // Check for ENDQRYRM, throw SqlException if already received one.
-            checkAndThrowReceivedEndqryrm();
-
-            // Send CNTQRY to complete the row/rowset.
-            int lastValidByteBeforeFetch = completeSplitRow();
-
-            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-            // throw a SqlException for the ENDQRYRM.
-            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
-        }
+        checkForSplitRowAndComplete(length);
         position_ += length;
         return length;
     }
 
     private int skipFdocaBytes(int length, int index) throws org.apache.derby.client.am.DisconnectException, SqlException {
-        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-        // so there is no need to drive a flowFetch (continue query) request for singleton select.
-        if ((position_ + length) > lastValidBytePosition_) {
-            // Check for ENDQRYRM, throw SqlException if already received one.
-            checkAndThrowReceivedEndqryrm();
-
-            // Send CNTQRY to complete the row/rowset.
-            int lastValidByteBeforeFetch = completeSplitRow(index);
-
-            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-            // throw a SqlException for the ENDQRYRM.
-            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
-        }
-
+        checkForSplitRowAndComplete(length, index);
         position_ += length;
         return length;
     }
@@ -603,6 +502,11 @@ public class NetCursor extends org.apach
         lastValidBytePosition_ = length;
     }
 
+    /**
+     * Adjust column offsets after fetching the next part of a split row.
+     * @param index the index of the column that was split, or -1 when not
+     * fetching column data
+     */
     private void adjustColumnOffsetsForColumnsPreviouslyCalculated(int index) {
         for (int j = 0; j <= index; j++) {
             columnDataPosition_[j] -= currentRowPosition_;
@@ -971,19 +875,7 @@ public class NetCursor extends org.apach
             return null;
         }
 
-        // For singleton select, the complete row always comes back, even if multiple query blocks are required,
-        // so there is no need to drive a flowFetch (continue query) request for singleton select.
-        if ((position_ + length) > lastValidBytePosition_) {
-            // Check for ENDQRYRM, throw SqlException if already received one.
-            checkAndThrowReceivedEndqryrm();
-
-            // Send CNTQRY to complete the row/rowset.
-            int lastValidByteBeforeFetch = completeSplitRow();
-
-            // if lastValidBytePosition_ has not changed, and an ENDQRYRM was received,
-            // throw a SqlException for the ENDQRYRM.
-            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
-        }
+        checkForSplitRowAndComplete(length);
 
         String s = null;
 
@@ -1239,6 +1131,43 @@ public class NetCursor extends org.apach
         extdtaData_ = null;
     }
 
+    /**
+     * Check if the data we want crosses a row split, and fetch more data
+     * if necessary.
+     *
+     * @param length the length in bytes of the data needed
+     * @param index the index of the column to be fetched, or -1 when not
+     * fetching column data
+     */
+    private void checkForSplitRowAndComplete(int length, int index)
+            throws SqlException {
+        // For singleton select, the complete row always comes back, even if
+        // multiple query blocks are required, so there is no need to drive a
+        // flowFetch (continue query) request for singleton select.
+        while ((position_ + length) > lastValidBytePosition_) {
+            // Check for ENDQRYRM, throw SqlException if already received one.
+            checkAndThrowReceivedEndqryrm();
+
+            // Send CNTQRY to complete the row/rowset.
+            int lastValidByteBeforeFetch = completeSplitRow(index);
+
+            // If lastValidBytePosition_ has not changed, and an ENDQRYRM was
+            // received, throw a SqlException for the ENDQRYRM.
+            checkAndThrowReceivedEndqryrm(lastValidByteBeforeFetch);
+        }
+    }
+
+    /**
+     * Check if the data we want crosses a row split, and fetch more data
+     * if necessary. This method is not for column data; use
+     * {@link #checkForSplitRowAndComplete(int, int)} for that.
+     *
+     * @param length the length in bytes of the data needed
+     */
+    private void checkForSplitRowAndComplete(int length) throws SqlException {
+        checkForSplitRowAndComplete(length, -1);
+    }
+
     // It is possible for the driver to have received an QRYDTA(with incomplete row)+ENDQRYRM+SQLCARD.
     // This means some error has occurred on the server and the server is terminating the query.
     // Before sending a CNTQRY to retrieve the rest of the split row, check if an ENDQRYRM has already
@@ -1274,21 +1203,14 @@ public class NetCursor extends org.apach
         checkAndThrowReceivedEndqryrm();
     }
 
-    private int completeSplitRow() throws DisconnectException, SqlException {
-        int lastValidBytePositionBeforeFetch = 0;
-        if (netResultSet_ != null && netResultSet_.scrollable_) {
-            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
-            netResultSet_.flowFetchToCompleteRowset();
-        } else {
-            // Shift partial row to the beginning of the dataBuffer
-            shiftPartialRowToBeginning();
-            resetCurrentRowPosition();
-            lastValidBytePositionBeforeFetch = lastValidBytePosition_;
-            netResultSet_.flowFetch();
-        }
-        return lastValidBytePositionBeforeFetch;
-    }
-
+    /**
+     * Fetch more data for a row that has been split up.
+     *
+     * @param index the index of the column that was split, or -1 when not
+     * fetching column data
+     * @return the value of {@code lastValidBytePosition_} before more data
+     * was fetched
+     */
     private int completeSplitRow(int index) throws DisconnectException, SqlException {
         int lastValidBytePositionBeforeFetch = 0;
         if (netResultSet_ != null && netResultSet_.scrollable_) {