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
|