db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kahat...@apache.org
Subject svn commit: r1169698 - in /db/derby/code/branches/10.8: ./ java/build/org/apache/derbyBuild/ java/client/org/apache/derby/client/am/ java/client/org/apache/derby/client/net/ java/drda/org/apache/derby/impl/drda/ java/shared/org/apache/derby/shared/comm...
Date Mon, 12 Sep 2011 11:32:11 GMT
Author: kahatlen
Date: Mon Sep 12 11:32:10 2011
New Revision: 1169698

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

Merged fix from trunk (revisions 1104365, 1163131, 1164495, 1167017,
1167470, 1169692) and bumped the DRDA maintenance version on the
branch.

Modified:
    db/derby/code/branches/10.8/   (props changed)
    db/derby/code/branches/10.8/java/build/org/apache/derbyBuild/MessageBundleTest.java
    db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlException.java
    db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlWarning.java
    db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/Sqlca.java
    db/derby/code/branches/10.8/java/client/org/apache/derby/client/net/NetCursor.java   (contents, props changed)
    db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/AppRequester.java
    db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DDMWriter.java
    db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
    db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAStatement.java
    db/derby/code/branches/10.8/java/shared/org/apache/derby/shared/common/reference/SQLState.java
    db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/PrepareStatementTest.java
    db/derby/code/branches/10.8/tools/ant/properties/release.properties

Propchange: db/derby/code/branches/10.8/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Sep 12 11:32:10 2011
@@ -1,2 +1,2 @@
 /db/derby/code/branches/10.7:1061570,1061578,1082235
-/db/derby/code/trunk:1063809,1088633,1089795,1091000,1091221,1091285,1092067,1092795,1094315,1094572,1094728,1095247,1096741,1096890,1096991,1097247,1097249,1097460,1097469,1097471,1098033,1101059,1101839,1102620,1102826,1103681,1103718,1103742,1125305,1126358,1126468,1127825,1127883,1128243,1128942,1129136,1129764,1129797,1130077,1130084,1130632,1130895,1131030,1131272,1132546,1132664,1132747,1132860,1132928,1133304,1133317,1133741,1133752,1134139,1136363,1136371,1136397,1136844,1137213,1138201,1138341,1138444,1138787,1138795,1139449,1139451,1140222,1140744,1141924,1142583,1142635,1145057,1146644,1146915,1146962,1147219,1147242,1147335,1148344,1148354,1148429,1148658,1149054,1149090,1149270,1149482,1149662,1151101,1151612,1158108,1160593,1160597,1161208,1163616,1164358,1164370,1165221
+/db/derby/code/trunk:1063809,1088633,1089795,1091000,1091221,1091285,1092067,1092795,1094315,1094572,1094728,1095247,1096741,1096890,1096991,1097247,1097249,1097460,1097469,1097471,1098033,1101059,1101839,1102620,1102826,1103681,1103718,1103742,1104365,1125305,1126358,1126468,1127825,1127883,1128243,1128942,1129136,1129764,1129797,1130077,1130084,1130632,1130895,1131030,1131272,1132546,1132664,1132747,1132860,1132928,1133304,1133317,1133741,1133752,1134139,1136363,1136371,1136397,1136844,1137213,1138201,1138341,1138444,1138787,1138795,1139449,1139451,1140222,1140744,1141924,1142583,1142635,1145057,1146644,1146915,1146962,1147219,1147242,1147335,1148344,1148354,1148429,1148658,1149054,1149090,1149270,1149482,1149662,1151101,1151612,1158108,1160593,1160597,1161208,1163131,1163616,1164358,1164370,1164495,1165221,1167017,1167470,1169692

Modified: db/derby/code/branches/10.8/java/build/org/apache/derbyBuild/MessageBundleTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/build/org/apache/derbyBuild/MessageBundleTest.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/build/org/apache/derbyBuild/MessageBundleTest.java (original)
+++ db/derby/code/branches/10.8/java/build/org/apache/derbyBuild/MessageBundleTest.java Mon Sep 12 11:32:10 2011
@@ -30,8 +30,6 @@ import java.util.ResourceBundle;
 import java.util.Locale;
 import java.util.Iterator;
 
-import java.lang.Exception;
-
 
 /**
  * This class does everything we can to validate that the messages_en.properties
@@ -170,8 +168,11 @@ public class MessageBundleTest {
                 // messages.xml:
                 // XCL32: will never be exposed to users (see DERBY-1414)
                 // XSAX1: shared SQLState explains; not exposed to users. 
+                // 01004: automatically assigned by java.sql.DataTruncation and
+                //        never used to generate a message
                 if (!(sqlStateId.equalsIgnoreCase("XCL32.S") ||
-                    sqlStateId.equalsIgnoreCase("XSAX1"))) {
+                      sqlStateId.equalsIgnoreCase("XSAX1")   ||
+                      sqlStateId.equalsIgnoreCase("01004"))) {
                 // Don't fail out on the first one, we want to catch
                 // all of them.  Just note there was a failure and continue
                     failbuild=true;

Modified: db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlException.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlException.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlException.java (original)
+++ db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlException.java Mon Sep 12 11:32:10 2011
@@ -22,7 +22,6 @@
 package org.apache.derby.client.am;
 
 import java.sql.SQLException;
-import java.util.TreeMap;
 
 import org.apache.derby.shared.common.i18n.MessageUtil;
 import org.apache.derby.shared.common.error.ExceptionUtil;
@@ -281,6 +280,13 @@ public class SqlException extends Except
         this.sqlca_ = sqlca;
         messageNumber_ = number;
         sqlstate_ = sqlca.getSqlState(number);
+
+        // If the SQLState indicates that this is a java.sql.DataTruncation
+        // type of exception, generate one right away.
+        if (SQLState.DATA_TRUNCATION_READ.equals(sqlstate_)) {
+            wrappedException_ = sqlca.getDataTruncation();
+        }
+
         int nextMsg = number + 1;
         if (chain && (sqlca.numberOfMessages() > nextMsg)) {
             setThrowable(new SqlException(sqlca, nextMsg, true));

Modified: db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlWarning.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlWarning.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlWarning.java (original)
+++ db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/SqlWarning.java Mon Sep 12 11:32:10 2011
@@ -92,6 +92,10 @@ public class SqlWarning extends SqlExcep
      */
     public SQLWarning getSQLWarning()
     {
+        if (wrappedException_ != null) {
+            return (SQLWarning) wrappedException_;
+        }
+
         SQLWarning sqlw = new SQLWarning(getMessage(), getSQLState(), 
             getErrorCode());
 

Modified: db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/Sqlca.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/Sqlca.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/Sqlca.java (original)
+++ db/derby/code/branches/10.8/java/client/org/apache/derby/client/am/Sqlca.java Mon Sep 12 11:32:10 2011
@@ -21,6 +21,7 @@
 
 package org.apache.derby.client.am;
 
+import java.sql.DataTruncation;
 import org.apache.derby.shared.common.reference.SQLState;
 import org.apache.derby.client.net.Typdef;
 
@@ -58,6 +59,9 @@ public abstract class Sqlca {
      */
     private static final String sqlErrmcDelimiter__ = "\u0014\u0014\u0014";
 
+    /** Token delimiter for SQLERRMC. */
+    private final static String SQLERRMC_TOKEN_DELIMITER = "\u0014";
+
     // JDK stack trace calls e.getMessage(), so we must set some state on the sqlca that says return tokens only.
     private boolean returnTokensOnlyInMessageText_ = false;
 
@@ -365,6 +369,25 @@ public abstract class Sqlca {
         }
         return false;
     }
+
+    /**
+     * Get a {@code java.sql.DataTruncation} warning based on the information
+     * in this SQLCA.
+     *
+     * @return a {@code java.sql.DataTruncation} instance
+     */
+    DataTruncation getDataTruncation() {
+        // The network server has serialized all the parameters needed by
+        // the constructor in the SQLERRMC field.
+        String[] tokens = getSqlErrmc().split(SQLERRMC_TOKEN_DELIMITER);
+        return new DataTruncation(
+                Integer.parseInt(tokens[0]),                // index
+                Boolean.valueOf(tokens[1]).booleanValue(),  // parameter
+                Boolean.valueOf(tokens[2]).booleanValue(),  // read
+                Integer.parseInt(tokens[3]),                // dataSize
+                Integer.parseInt(tokens[4]));               // transferSize
+    }
+
     // ------------------- helper methods ----------------------------------------
 
     private void processSqlErrmcTokens(byte[] tokenBytes) {

Modified: db/derby/code/branches/10.8/java/client/org/apache/derby/client/net/NetCursor.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/client/org/apache/derby/client/net/NetCursor.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/client/org/apache/derby/client/net/NetCursor.java (original)
+++ db/derby/code/branches/10.8/java/client/org/apache/derby/client/net/NetCursor.java Mon Sep 12 11:32:10 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_) {

Propchange: db/derby/code/branches/10.8/java/client/org/apache/derby/client/net/NetCursor.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Sep 12 11:32:10 2011
@@ -1,2 +1,2 @@
 /db/derby/code/branches/10.7/java/client/org/apache/derby/client/net/NetCursor.java:1061570,1061578,1082235
-/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java:1063809,1088633,1089795,1091000,1091221,1091285,1092067,1092795,1094315,1094572,1094728,1095247,1096741,1096890,1096991,1097247,1097249,1097460,1097469,1097471,1098033,1101059,1101839,1102620,1102826,1103681,1103718,1103742,1125305,1126358,1126468,1127825,1127883,1128243,1128942,1129136,1129764,1129797,1130077,1130084,1130632,1130895,1131030,1131272,1132546,1132664,1132747,1132860,1132928,1133304,1133317,1133741,1133752,1134139,1136363,1136371,1136397,1136844,1137213,1138201,1138341,1138444,1138787,1138795,1139449,1139451,1140222,1140744,1141924,1142583,1142635,1145057,1145961,1146644,1146915,1146962,1147219,1147242,1147335,1148344,1148354,1148429,1148658,1149054,1149090,1149270,1149482,1149662,1151101,1151612,1158108,1160593,1160597,1161208,1163616,1164358,1164370,1165221
+/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java:1063809,1088633,1089795,1091000,1091221,1091285,1092067,1092795,1094315,1094572,1094728,1095247,1096741,1096890,1096991,1097247,1097249,1097460,1097469,1097471,1098033,1101059,1101839,1102620,1102826,1103681,1103718,1103742,1104365,1125305,1126358,1126468,1127825,1127883,1128243,1128942,1129136,1129764,1129797,1130077,1130084,1130632,1130895,1131030,1131272,1132546,1132664,1132747,1132860,1132928,1133304,1133317,1133741,1133752,1134139,1136363,1136371,1136397,1136844,1137213,1138201,1138341,1138444,1138787,1138795,1139449,1139451,1140222,1140744,1141924,1142583,1142635,1145057,1145961,1146644,1146915,1146962,1147219,1147242,1147335,1148344,1148354,1148429,1148658,1149054,1149090,1149270,1149482,1149662,1151101,1151612,1158108,1160593,1160597,1161208,1163131,1163616,1164358,1164370,1164495,1165221,1167017,1167470,1169692

Modified: db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/AppRequester.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/AppRequester.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/AppRequester.java (original)
+++ db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/AppRequester.java Mon Sep 12 11:32:10 2011
@@ -331,6 +331,21 @@ class AppRequester
 	}
 
     /**
+     * Return true if the client contains the fix for DERBY-5236, which allows
+     * DDMWriter.writeLDString() to write strings that need up to 64K-1 bytes
+     * when represented in UTF-8. Otherwise, writeLDString() should use the
+     * old maximum length, which is 32700 bytes.
+     */
+    protected boolean supportsLongerLDStrings() {
+        // The fix for DERBY-5236 went into the 10.8 branch after the first
+        // release off that branch. The DRDA maintenance version was bumped
+        // to 1 when the fix went in (the third argument in the call to
+        // greaterThanOrEqualTo() refers to that maintenance version, not to
+        // the third digit of the product's version number).
+        return clientType == DNC_CLIENT && greaterThanOrEqualTo(10, 8, 1);
+    }
+
+    /**
      * The timestamp length may be truncated for old versions of Derby.
      * See DERBY-2602.
      */

Modified: db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DDMWriter.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DDMWriter.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DDMWriter.java (original)
+++ db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DDMWriter.java Mon Sep 12 11:32:10 2011
@@ -32,6 +32,7 @@ import java.nio.CharBuffer;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
 import java.nio.charset.CodingErrorAction;
+import java.sql.DataTruncation;
 import java.sql.SQLException;
 import java.util.Arrays;
 
@@ -58,6 +59,12 @@ class DDMWriter
 	// Default buffer size
 	private final static int DEFAULT_BUFFER_SIZE = 32767;
 
+    /**
+     * The maximum length in bytes for strings sent by {@code writeLDString()},
+     * which is the maximum unsigned integer value that fits in two bytes.
+     */
+    private final static int MAX_VARCHAR_BYTE_LENGTH = 0xFFFF;
+
 	/**
 	 * Output buffer.
 	 */
@@ -176,6 +183,35 @@ class DDMWriter
 		this.dssTrace = dssTrace;
 	}
 
+    /**
+     * Get the current position in the output buffer.
+     * @return current position
+     */
+    protected int getBufferPosition() {
+        return buffer.position();
+    }
+
+    /**
+     * Change the current position in the output buffer.
+     * @param position new position
+     */
+    protected void setBufferPosition(int position) {
+        buffer.position(position);
+    }
+
+    /**
+     * Get a copy of a subsequence of the output buffer, starting at the
+     * specified position and ending at the current buffer position.
+     *
+     * @param startPos the position of the first byte to copy
+     * @return all bytes from {@code startPos} up to the current position
+     */
+    protected byte[] getBufferContents(int startPos) {
+        byte[] bytes = new byte[buffer.position() - startPos];
+        System.arraycopy(buffer.array(), startPos, bytes, 0, bytes.length);
+        return bytes;
+    }
+
 	/**
 	 * set protocol to CMD protocol
 	 */
@@ -1114,7 +1150,7 @@ class DDMWriter
 	 */
 	protected void writeLDString(String s) throws DRDAProtocolException
 	{
-		writeLDString(s,0);
+		writeLDString(s, 0, null, false);
 	}
 
 	/**
@@ -1185,49 +1221,103 @@ class DDMWriter
 	 *
 	 * @param s              value to be written with integer
 	 * @param index          column index to put in warning
+     * @param stmt           the executing statement (null if not invoked as
+     *                       part of statement execution)
+     * @param isParameter    true if the value written is for an output
+     *                       parameter in a procedure call
 	 * @exception DRDAProtocolException
 	 */
-	protected void writeLDString(String s, int index) throws DRDAProtocolException
+	protected void writeLDString(String s, int index, DRDAStatement stmt,
+                                 boolean isParameter)
+            throws DRDAProtocolException
 	{
 		// Position on which to write the length of the string (in bytes). The
 		// actual writing of the length is delayed until we have encoded the
 		// string.
 		final int lengthPos = buffer.position();
-		// Position on which to start writing the string (right after length,
-		// which is 2 bytes long).
-		final int stringPos = lengthPos + 2;
-		// don't send more than LONGVARCHAR_MAX_LEN bytes
-		final int maxStrLen =
-			Math.min(maxEncodedLength(s), FdocaConstants.LONGVARCHAR_MAX_LEN);
-
-		ensureLength(2 + maxStrLen);
-
-		// limit the writable area of the output buffer
-		buffer.position(stringPos);
-		buffer.limit(stringPos + maxStrLen);
 
-		// encode the string
-		CharBuffer input = CharBuffer.wrap(s);
-		encoder.reset();
-		CoderResult res = encoder.encode(input, buffer, true);
-		if (res == CoderResult.UNDERFLOW) {
-			res = encoder.flush(buffer);
-		}
-		if (SanityManager.DEBUG) {
-			// UNDERFLOW is returned if the entire string was encoded, OVERFLOW
-			// is returned if the string was truncated at LONGVARCHAR_MAX_LEN
-			SanityManager.ASSERT(
-				res == CoderResult.UNDERFLOW || res == CoderResult.OVERFLOW,
-				"Unexpected coder result: " + res);
-		}
+        // Reserve two bytes for the length field and move the position to
+        // where the string should be inserted.
+        ensureLength(2);
+        final int stringPos = lengthPos + 2;
+        buffer.position(stringPos);
+
+        // Write the string.
+        writeString(s);
+
+        // Find out how long strings the client supports, and possibly
+        // truncate the string before sending it.
+
+        int maxByteLength = MAX_VARCHAR_BYTE_LENGTH;
+        boolean warnOnTruncation = true;
+
+        AppRequester appRequester = agent.getSession().appRequester;
+        if (appRequester != null && !appRequester.supportsLongerLDStrings()) {
+            // The client suffers from DERBY-5236, and it doesn't support
+            // receiving as long strings as newer clients do. It also doesn't
+            // know exactly what to do with a DataTruncation warning, so skip
+            // sending it to old clients.
+            maxByteLength = FdocaConstants.LONGVARCHAR_MAX_LEN;
+            warnOnTruncation = false;
+        }
+
+        int byteLength = buffer.position() - stringPos;
 
-		// write the length in bytes
-		buffer.putShort(lengthPos, (short) (maxStrLen - buffer.remaining()));
+        // If the byte representation of the string is too long, it needs to
+        // be truncated.
+        if (byteLength > maxByteLength) {
+            // Truncate the string down to the maximum byte length.
+            byteLength = maxByteLength;
+            // Align with character boundaries so that we don't send over
+            // half a character.
+            while (isContinuationByte(buffer.get(stringPos + byteLength))) {
+                byteLength--;
+            }
+
+            // Check how many chars that were truncated.
+            int truncatedChars = 0;
+            for (int i = stringPos + byteLength; i < buffer.position(); i++) {
+                if (!isContinuationByte(buffer.get(i))) {
+                    truncatedChars++;
+                }
+            }
 
-		// remove the limit on the output buffer
-		buffer.limit(buffer.capacity());
+            // Set the buffer position right after the truncated string.
+            buffer.position(stringPos + byteLength);
+
+            // If invoked as part of statement execution, and the client
+            // supports receiving DataTruncation warnings, add a warning about
+            // the string being truncated.
+            if (warnOnTruncation && stmt != null) {
+                DataTruncation dt = new DataTruncation(
+                        index,
+                        isParameter,
+                        true,  // this is a warning for a read operation
+                        s.length(),                   // dataSize
+                        s.length() - truncatedChars); // transferSize
+                stmt.addTruncationWarning(dt);
+            }
+        }
+
+        // Go back and write the length in bytes.
+        buffer.putShort(lengthPos, (short) byteLength);
 	}
 
+    /**
+     * Check if a byte value represents a continuation byte in a UTF-8 byte
+     * sequence. Continuation bytes in UTF-8 always match the bit pattern
+     * {@code 10xxxxxx}.
+     *
+     * @param b the byte to check
+     * @return {@code true} if {@code b} is a continuation byte, or
+     * {@code false} if it is the first byte in a UTF-8 sequence
+     */
+    private static boolean isContinuationByte(byte b) {
+        // Check the values of the two most significant bits. If they are
+        // 10xxxxxx, it's a continuation byte.
+        return (b & 0xC0) == 0x80;
+    }
+
 	/**
 	 * Write string with default encoding
 	 *

Modified: db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (original)
+++ db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAConnThread.java Mon Sep 12 11:32:10 2011
@@ -31,6 +31,7 @@ import java.io.UnsupportedEncodingExcept
 import java.math.BigDecimal;
 import java.sql.CallableStatement;
 import java.sql.Connection;
+import java.sql.DataTruncation;
 import java.sql.ParameterMetaData;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
@@ -6175,6 +6176,8 @@ class DRDAConnThread extends Thread {
 		
 		if (se instanceof EmbedSQLException  && ! severe)
 			sqlerrmc = buildTokenizedSqlerrmc(se);
+        else if (se instanceof DataTruncation)
+            sqlerrmc = buildDataTruncationSqlerrmc((DataTruncation) se);
 		else {
 			// If this is not an EmbedSQLException or is a severe excecption where
 			// we have no hope of succussfully calling the SYSIBM.SQLCAMESSAGE send
@@ -6260,6 +6263,21 @@ class DRDAConnThread extends Thread {
 		return sqlerrmc;
 	}
 
+    /**
+     * Build the SQLERRMC for a {@code java.sql.DataTruncation} warning.
+     * Serialize all the fields of the {@code DataTruncation} instance in the
+     * order in which they appear in the parameter list of the constructor.
+     *
+     * @param dt the {@code DataTruncation} instance to serialize
+     * @return the SQLERRMC string with all fields of the warning
+     */
+    private String buildDataTruncationSqlerrmc(DataTruncation dt) {
+        return dt.getIndex() + SQLERRMC_TOKEN_DELIMITER +
+               dt.getParameter() + SQLERRMC_TOKEN_DELIMITER +
+               dt.getRead() + SQLERRMC_TOKEN_DELIMITER +
+               dt.getDataSize() + SQLERRMC_TOKEN_DELIMITER +
+               dt.getTransferSize();
+    }
 	
 	/**
 	 * Write SQLCAXGRP
@@ -7078,11 +7096,19 @@ class DRDAConnThread extends Thread {
 				}
 			}
 
+            // Save the position where we start writing the warnings in case
+            // we need to add more warnings later.
+            final int sqlcagrpStart = writer.getBufferPosition();
+
 			if (sqlw == null)
                 writeSQLCAGRP(nullSQLState, 0, -1, -1);
 			else
 				writeSQLCAGRP(sqlw, sqlw.getErrorCode(), 1, -1);
 
+            // Save the position right after the warnings so we know where to
+            // insert more warnings later.
+            final int sqlcagrpEnd = writer.getBufferPosition();
+
 			// if we were asked not to return data, mark QRYDTA null; do not
 			// return yet, need to make rowCount right
 			// if the row has been deleted return QRYDTA null (delete hole)
@@ -7121,8 +7147,8 @@ class DRDAConnThread extends Thread {
 						case  DRDAConstants.DRDA_TYPE_NLOBCMIXED:
 							EXTDTAInputStream extdtaStream=  
 								EXTDTAInputStream.getEXTDTAStream(rs, i, drdaType);
-							writeFdocaVal(i,extdtaStream, drdaType,
-										  precision,scale,extdtaStream.isNull(),stmt);
+                            writeFdocaVal(i, extdtaStream, drdaType, precision,
+                                    scale, extdtaStream.isNull(), stmt, false);
 							break;
 						case DRDAConstants.DRDA_TYPE_NINTEGER:
 							int ival = rs.getInt(i);
@@ -7178,12 +7204,14 @@ class DRDAConnThread extends Thread {
 							if (SanityManager.DEBUG)
 								trace("====== writing char/varchar/mix :"+ valStr + ":");
 							writeFdocaVal(i, valStr, drdaType,
-										  precision,scale,rs.wasNull(),stmt);
+										  precision, scale, rs.wasNull(),
+                                          stmt, false);
 							break;
 						default:
                             val = getObjectForWriteFdoca(rs, i, drdaType);
                             writeFdocaVal(i, val, drdaType,
-										  precision,scale,rs.wasNull(),stmt);
+										  precision, scale, rs.wasNull(),
+                                          stmt, false);
 					}
 				}
 				else
@@ -7204,13 +7232,33 @@ class DRDAConnThread extends Thread {
                         val = getObjectForWriteFdoca(
                                 (CallableStatement) stmt.ps, i, drdaType);
 						valNull = (val == null);
-						writeFdocaVal(i,val,drdaType,precision, scale, valNull,stmt);
+						writeFdocaVal(i, val, drdaType, precision, scale,
+                                      valNull, stmt, true);
 					}
 					else
-						writeFdocaVal(i,null,drdaType,precision,scale,true,stmt);
+						writeFdocaVal(i, null, drdaType, precision, scale,
+                                      true, stmt, true);
 
 				}
 			}
+
+            DataTruncation truncated = stmt.getTruncationWarnings();
+            if (truncated != null) {
+                // Some of the data was truncated, so we need to add a
+                // truncation warning. Save a copy of the row data, then move
+                // back to the SQLCAGRP section and overwrite it with the new
+                // warnings, and finally re-insert the row data after the new
+                // SQLCAGRP section.
+                byte[] data = writer.getBufferContents(sqlcagrpEnd);
+                writer.setBufferPosition(sqlcagrpStart);
+                if (sqlw != null) {
+                    truncated.setNextWarning(sqlw);
+                }
+                writeSQLCAGRP(truncated, CodePoint.SVRCOD_WARNING, 1, -1);
+                writer.writeBytes(data);
+                stmt.clearTruncationWarnings();
+            }
+
 			// does all this fit in one QRYDTA
 			if (writer.getDSSLength() > blksize)
 			{
@@ -7871,6 +7919,7 @@ class DRDAConnThread extends Thread {
    * @param drdaType  FD:OCA DRDA Type from FdocaConstants
    * @param precision Precision
    * @param stmt       Statement being processed
+   * @param isParam   True when writing a value for a procedure parameter
    *
    * @exception DRDAProtocolException  
    * 
@@ -7881,8 +7930,8 @@ class DRDAConnThread extends Thread {
 
 	protected void writeFdocaVal(int index, Object val, int drdaType,
 								 int precision, int scale, boolean valNull,
-								 
-								 DRDAStatement stmt) throws DRDAProtocolException, SQLException
+								 DRDAStatement stmt, boolean isParam)
+            throws DRDAProtocolException, SQLException
 	{
 		writeNullability(drdaType,valNull);
 
@@ -7945,7 +7994,7 @@ class DRDAConnThread extends Thread {
 				case DRDAConstants.DRDA_TYPE_NLONGMIX:
 					//WriteLDString and generate warning if truncated
 					// which will be picked up by checkWarning()
-					writer.writeLDString(val.toString(), index);
+					writer.writeLDString(val.toString(), index, stmt, isParam);
 					break;
 				case DRDAConstants.DRDA_TYPE_NLOBBYTES:
 				case DRDAConstants.DRDA_TYPE_NLOBCMIXED:
@@ -7981,7 +8030,7 @@ class DRDAConnThread extends Thread {
 				default:
 					if (SanityManager.DEBUG) 
 						trace("ndrdaType is: "+ndrdaType);
-					writer.writeLDString(val.toString(), index);
+					writer.writeLDString(val.toString(), index, stmt, isParam);
 			}
 		}
 	}

Modified: db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAStatement.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAStatement.java (original)
+++ db/derby/code/branches/10.8/java/drda/org/apache/derby/impl/drda/DRDAStatement.java Mon Sep 12 11:32:10 2011
@@ -39,6 +39,7 @@ import java.util.StringTokenizer;
 import java.util.Vector;
 import java.lang.reflect.Array;
 
+import java.sql.DataTruncation;
 import org.apache.derby.iapi.jdbc.BrokeredConnection;
 import org.apache.derby.iapi.jdbc.BrokeredPreparedStatement;
 import org.apache.derby.iapi.jdbc.EnginePreparedStatement;
@@ -102,6 +103,12 @@ class DRDAStatement
 	private ArrayList resultSetKeyList;  // ordered list of hash keys
 	private int numResultSets = 0;  
 
+    /**
+     * A chain of warnings indicating whether some of the data values returned
+     * by this statement had to be truncated before being sent to the client.
+     */
+    private DataTruncation truncationWarnings;
+
 	/** This class is used to keep track of the statement's parameters
 	 * as they are received from the client. It uses arrays to track
 	 * the DRDA type, the length in bytes and the externalness of each
@@ -343,6 +350,33 @@ class DRDAStatement
 		return stmt;
 	}
 
+    /**
+     * Add a warning about data having been truncated.
+     * @param w the warning to add
+     */
+    protected void addTruncationWarning(DataTruncation w) {
+        if (truncationWarnings == null) {
+            truncationWarnings = w;
+        } else {
+            truncationWarnings.setNextWarning(w);
+        }
+    }
+
+    /**
+     * Get the chain of truncation warnings added to this statement.
+     * @return chain of truncation warnings, possibly {@code null}
+     */
+    protected DataTruncation getTruncationWarnings() {
+        return truncationWarnings;
+    }
+
+    /**
+     * Clear the chain of truncation warnings for this statement.
+     */
+    protected void clearTruncationWarnings() {
+        truncationWarnings = null;
+    }
+
 	/**Set resultSet defaults to match 
 	 * the statement defaults sent on EXCSQLSTT
 	 * This might be overridden on OPNQRY or CNTQRY
@@ -1033,6 +1067,7 @@ class DRDAStatement
 		ps = null;
 		stmtPmeta = null;
 		stmt = null;
+        truncationWarnings = null;
 		rslsetflg = null;
 		procName = null;
 		outputTypes = null;
@@ -1071,6 +1106,7 @@ class DRDAStatement
 		outputTypes = null;
 		outputExpected = false;
 		stmt = null;
+        truncationWarnings = null;
 		
 		currentDrdaRs.reset();
 		resultSetTable = null;

Modified: db/derby/code/branches/10.8/java/shared/org/apache/derby/shared/common/reference/SQLState.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/shared/org/apache/derby/shared/common/reference/SQLState.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/shared/org/apache/derby/shared/common/reference/SQLState.java (original)
+++ db/derby/code/branches/10.8/java/shared/org/apache/derby/shared/common/reference/SQLState.java Mon Sep 12 11:32:10 2011
@@ -668,6 +668,8 @@ public interface SQLState {
 
 	String LANG_TOO_MANY_DYNAMIC_RESULTS_RETURNED					   = "0100E";
 
+    // State used by java.sql.DataTruncation for truncation in read operations.
+    String DATA_TRUNCATION_READ = "01004";
 
 	// Invalid role specification: standard says class 0P, no subclass.
 	String ROLE_INVALID_SPECIFICATION                                  = "0P000";

Modified: db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/PrepareStatementTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/PrepareStatementTest.java?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/PrepareStatementTest.java (original)
+++ db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/PrepareStatementTest.java Mon Sep 12 11:32:10 2011
@@ -22,13 +22,17 @@
 package org.apache.derbyTesting.functionTests.tests.derbynet;
 
 import java.sql.BatchUpdateException;
+import java.sql.CallableStatement;
+import java.sql.DataTruncation;
 import java.sql.Date;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.SQLWarning;
 import java.sql.Statement;
 import java.sql.Time;
 import java.sql.Timestamp;
+import java.sql.Types;
 
 import java.math.BigDecimal;
 import java.io.ByteArrayInputStream;
@@ -1288,9 +1292,16 @@ public class PrepareStatementTest extend
      */
     private static String makeString(int length)
     {
-        StringBuffer buf = new StringBuffer();
-        for (int i = 0; i < length; ++i) buf.append("X");
-        return buf.toString();
+        return makeString(length, 'X');
+    }
+
+    /**
+     * Return a string of the given length filled with the specified character.
+     */
+    private static String makeString(int length, char ch) {
+        char[] buf = new char[length];
+        Arrays.fill(buf, ch);
+        return new String(buf);
     }
 
     /**
@@ -1319,4 +1330,158 @@ public class PrepareStatementTest extend
         rs.close();
     }
 
+    /**
+     * Verify that string values aren't truncated when their UTF-8 encoded
+     * representation exceeds 32KB. DERBY-5236.
+     */
+    public void testLongColumn() throws Exception {
+        PreparedStatement ps = prepareStatement(
+                "values cast(? as varchar(32672))");
+
+        String s1 = makeString(20000, '\u4e10');
+        ps.setString(1, s1);
+        JDBC.assertSingleValueResultSet(ps.executeQuery(), s1);
+
+        // 64K-1 bytes, should be OK.
+        String s2 =
+                s1 + makeString(64 * 1024 - s1.getBytes("UTF-8").length - 1);
+        ps.setString(1, s2);
+        JDBC.assertSingleValueResultSet(ps.executeQuery(), s2);
+
+        // 64K bytes, will be truncated to 64K-1 by the client driver because
+        // of limitation in the protocol.
+        String s3 = s2 + 'X';
+        ps.setString(1, s3);
+        if (usingDerbyNetClient()) {
+            String expected = s3.substring(0, s3.length() - 1);
+            ResultSet rs = ps.executeQuery();
+            assertTrue("Empty result", rs.next());
+            assertDataTruncation(
+                    new String[] { expected },
+                    new String[] { rs.getString(1) },
+                    1, false, true, s3.length(), expected.length(),
+                    rs.getWarnings());
+            assertFalse("Too many rows", rs.next());
+            rs.close();
+        } else {
+            // Embedded is OK. No truncation.
+            JDBC.assertSingleValueResultSet(ps.executeQuery(), s3);
+        }
+
+        // 64K+1 bytes, will be truncated by the client driver because of
+        // limitation in the protocol. Should be truncated to to 64K-2 to
+        // match the character boundary.
+        String s4 = s3.substring(0, s3.length() - 2) + '\u4e10';
+        ps.setString(1, s4);
+        if (usingDerbyNetClient()) {
+            String expected = s4.substring(0, s4.length() - 1);
+            ResultSet rs = ps.executeQuery();
+            assertTrue("Empty result", rs.next());
+            assertDataTruncation(
+                    new String[] { expected },
+                    new String[] { rs.getString(1) },
+                    1, false, true, s4.length(), expected.length(),
+                    rs.getWarnings());
+            assertFalse("Too many rows", rs.next());
+            rs.close();
+        } else {
+            // Embedded is OK. No truncation.
+            JDBC.assertSingleValueResultSet(ps.executeQuery(), s4);
+        }
+
+        // Try two columns at 64K+1 bytes. Expect same result as above.
+        PreparedStatement ps2 = prepareStatement(
+                "values (cast(? as varchar(32672)), " +
+                "cast(? as varchar(32672)))");
+        ps2.setString(1, s4);
+        ps2.setString(2, s4);
+        if (usingDerbyNetClient()) {
+            String expected = s4.substring(0, s4.length() - 1);
+            ResultSet rs = ps2.executeQuery();
+            assertTrue("Empty result", rs.next());
+            // We should actually have received two warnings here, but the
+            // network client driver currently only supports one warning.
+            assertDataTruncation(
+                    new String[] { expected, expected },
+                    new String[] { rs.getString(1), rs.getString(2) },
+                    1, false, true, s4.length(), expected.length(),
+                    rs.getWarnings());
+            assertFalse("Too many rows", rs.next());
+            rs.close();
+        } else {
+            String[][] expectedRow = {{s4, s4}};
+            JDBC.assertFullResultSet(ps2.executeQuery(), expectedRow);
+        }
+
+        // Now test 64KB in a procedure call. Will be truncated to 64KB-1 on
+        // the network client.
+        Statement s = createStatement();
+        s.execute("create procedure derby_5236_proc" +
+                  "(in x varchar(32672), out y varchar(32672))" +
+                  "language java parameter style java external name '" +
+                  getClass().getName() + ".copyString'");
+        CallableStatement cs = prepareCall("call derby_5236_proc(?,?)");
+        cs.setString(1, s3);
+        cs.registerOutParameter(2, Types.VARCHAR);
+        cs.execute();
+        if (usingDerbyNetClient()) {
+            assertDataTruncation(
+                    new String[] { s3.substring(0, s3.length() - 1) },
+                    new String[] { cs.getString(2) },
+                    2, true, true, s3.length(), s3.length() - 1,
+                    cs.getWarnings());
+        } else {
+            assertEquals(s3, cs.getString(2));
+        }
+    }
+
+    /**
+     * Copy a string value from {@code in} to {@code out[0}}. Used as a
+     * stored procedure in {@link #testLongColumn()}.
+     *
+     * @param in stored procedure input parameter
+     * @param out stored procedure output parameter
+     */
+    public static void copyString(String in, String[] out) {
+        out[0] = in;
+    }
+
+    /**
+     * Assert that data returned from the server was truncated, and that the
+     * proper warning came with the result.
+     *
+     * @param expectedRow the expected values
+     * @param actualRow   the actual values returned
+     * @param index       the expected column/parameter index in the warning
+     * @param parameter   whether the values came from a procedure parameter
+     * @param read        whether the values came from a read operation
+     * @param dataSize    the expected full size of the truncated value
+     * @param transferSize the expected size of the value after truncation
+     * @param warning     the received warning
+     */
+    private static void assertDataTruncation(
+            String[] expectedRow, String[] actualRow,
+            int index, boolean parameter, boolean read,
+            int dataSize, int transferSize, SQLWarning warning) {
+        assertEquals("Wrong number of columns",
+                     expectedRow.length, actualRow.length);
+        assertNotNull("Expected data truncation warning", warning);
+        for (int i = 0; i < expectedRow.length; i++) {
+            assertEquals("column #" + (i + 1), expectedRow[i], actualRow[i]);
+
+            if (warning instanceof DataTruncation) {
+                DataTruncation dt = (DataTruncation) warning;
+                assertEquals("index", index, dt.getIndex());
+                assertEquals("parameter", parameter, dt.getParameter());
+                assertEquals("read", read, dt.getRead());
+                assertEquals("dataSize", dataSize, dt.getDataSize());
+                assertEquals("transferSize", transferSize, dt.getTransferSize());
+            } else {
+                fail("Unexpected warning", warning);
+            }
+
+            assertNull("Chained warnings not expected on network client",
+                       warning.getNextWarning());
+        }
+    }
 }

Modified: db/derby/code/branches/10.8/tools/ant/properties/release.properties
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/tools/ant/properties/release.properties?rev=1169698&r1=1169697&r2=1169698&view=diff
==============================================================================
--- db/derby/code/branches/10.8/tools/ant/properties/release.properties (original)
+++ db/derby/code/branches/10.8/tools/ant/properties/release.properties Mon Sep 12 11:32:10 2011
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 
-drdamaint=0
+drdamaint=1
 maint=1000006
 major=10
 minor=8



Mime
View raw message