You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by km...@apache.org on 2013/04/09 20:40:45 UTC
svn commit: r1466174 - in /db/derby/code/branches/10.8.3.1_testcompat: ./
java/client/org/apache/derby/client/am/
java/engine/org/apache/derby/impl/jdbc/
java/testing/org/apache/derbyTesting/functionTests/tests/lang/
Author: kmarsden
Date: Tue Apr 9 18:40:45 2013
New Revision: 1466174
URL: http://svn.apache.org/r1466174
Log:
DERBY-5489 prevent double retrieve on lob column to prevent wrong results.
partial merge of tests revision 1330681
Modified:
db/derby/code/branches/10.8.3.1_testcompat/ (props changed)
db/derby/code/branches/10.8.3.1_testcompat/java/client/org/apache/derby/client/am/ResultSet.java
db/derby/code/branches/10.8.3.1_testcompat/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
db/derby/code/branches/10.8.3.1_testcompat/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdatableResultSetTest.java
Propchange: db/derby/code/branches/10.8.3.1_testcompat/
------------------------------------------------------------------------------
Merged /db/derby/code/trunk:r1330681
Modified: db/derby/code/branches/10.8.3.1_testcompat/java/client/org/apache/derby/client/am/ResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8.3.1_testcompat/java/client/org/apache/derby/client/am/ResultSet.java?rev=1466174&r1=1466173&r2=1466174&view=diff
==============================================================================
--- db/derby/code/branches/10.8.3.1_testcompat/java/client/org/apache/derby/client/am/ResultSet.java (original)
+++ db/derby/code/branches/10.8.3.1_testcompat/java/client/org/apache/derby/client/am/ResultSet.java Tue Apr 9 18:40:45 2013
@@ -1057,11 +1057,18 @@ public abstract class ResultSet implemen
try
{
closeCloseFilterInputStream();
-
if (agent_.loggingEnabled()) {
agent_.logWriter_.traceEntry(this, "getString", column);
}
checkGetterPreconditions(column, "getString");
+ int type = resultSetMetaData_.types_[column - 1];
+ if (type == Types.BLOB || type == Types.CLOB) {
+ checkLOBMultiCall(column);
+ // If the above didn't fail, this is the first getter
+ // invocation, or only getBytes and/or getString have been
+ // invoked previously. The special treatment of these getters
+ // is allowed for backwards compatibility.
+ }
String result = null;
if (wasNonNullSensitiveUpdate(column)) {
result = (String) agent_.crossConverters_.setObject(java.sql.Types.CHAR, updatedColumns_[column - 1]);
@@ -1090,6 +1097,14 @@ public abstract class ResultSet implemen
agent_.logWriter_.traceEntry(this, "getBytes", column);
}
checkGetterPreconditions(column, "getBytes");
+ int type = resultSetMetaData_.types_[column - 1];
+ if (type == Types.BLOB) {
+ checkLOBMultiCall(column);
+ // If the above didn't fail, this is the first getter
+ // invocation, or only getBytes has been invoked previously.
+ // The special treatment of this getter is allowed for
+ // backwards compatibility.
+ }
byte[] result = null;
if (wasNonNullSensitiveUpdate(column)) {
result = (byte[]) agent_.crossConverters_.setObject(java.sql.Types.BINARY, updatedColumns_[column - 1]);
@@ -1360,6 +1375,10 @@ public abstract class ResultSet implemen
// used by DBMD
Object getObjectX(int column) throws SqlException {
checkGetterPreconditions(column, "getObject");
+ int type = resultSetMetaData_.types_[column - 1];
+ if (type == Types.BLOB || type == Types.CLOB) {
+ useStreamOrLOB(column);
+ }
Object result = null;
if (wasNonNullSensitiveUpdate(column)) {
result = updatedColumns_[column - 1];
@@ -5472,6 +5491,26 @@ public abstract class ResultSet implemen
* @throws SQLException if the column has already been accessed
*/
void useStreamOrLOB(int columnIndex) throws SqlException {
+ checkLOBMultiCall(columnIndex);
+ columnUsedFlags_[columnIndex - 1] = true;
+ }
+
+ /**
+ * Checks if a stream or a LOB object has already been created for the
+ * specified LOB column.
+ * <p>
+ * Accessing a LOB column more than once is not forbidden by the JDBC
+ * specification, but the Java API states that for maximum portability,
+ * result set columns within each row should be read in left-to-right order,
+ * and each column should be read only once. The restriction was implemented
+ * in Derby due to complexities with the positioning of store streams when
+ * the user was given multiple handles to the stream.
+ *
+ * @param columnIndex 1-based index of the LOB column
+ * @throws SqlException if the column has already been accessed
+ */
+ private void checkLOBMultiCall(int columnIndex)
+ throws SqlException {
if (columnUsedFlags_ == null) {
columnUsedFlags_ = new boolean[resultSetMetaData_.columns_];
}
@@ -5479,11 +5518,8 @@ public abstract class ResultSet implemen
throw new SqlException(agent_.logWriter_,
new ClientMessageId(SQLState.LANG_STREAM_RETRIEVED_ALREADY));
}
-
- columnUsedFlags_[columnIndex - 1] = true;
}
-
/**
* Clears the flags for used columns, typically invoked when changing the
* result set position.
Modified: db/derby/code/branches/10.8.3.1_testcompat/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8.3.1_testcompat/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java?rev=1466174&r1=1466173&r2=1466174&view=diff
==============================================================================
--- db/derby/code/branches/10.8.3.1_testcompat/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java (original)
+++ db/derby/code/branches/10.8.3.1_testcompat/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java Tue Apr 9 18:40:45 2013
@@ -677,7 +677,14 @@ public abstract class EmbedResultSet ext
*/
public final String getString(int columnIndex) throws SQLException {
checkIfClosed("getString");
-
+ int columnType = getColumnType(columnIndex);
+ if (columnType == Types.BLOB || columnType == Types.CLOB) {
+ checkLOBMultiCall(columnIndex);
+ // If the above didn't fail, this is the first getter invocation,
+ // or only getString and/or getBytes have been invoked previously.
+ // The special treatment of these getters is allowed for
+ // backwards compatibility.
+ }
try {
DataValueDescriptor dvd = getColumn(columnIndex);
@@ -688,7 +695,7 @@ public abstract class EmbedResultSet ext
String value = dvd.getString();
// check for the max field size limit
- if (maxFieldSize > 0 && isMaxFieldSizeType(getColumnType(columnIndex)))
+ if (maxFieldSize > 0 && isMaxFieldSizeType(columnType))
{
if (value.length() > maxFieldSize )
{
@@ -876,6 +883,13 @@ public abstract class EmbedResultSet ext
*/
public final byte[] getBytes(int columnIndex) throws SQLException {
checkIfClosed("getBytes");
+ int columnType = getColumnType(columnIndex);
+ if (columnType == Types.BLOB) {
+ checkLOBMultiCall(columnIndex);
+ // If the above didn't fail, this is the first getter invocation,
+ // or only getBytes has been invoked previously. The special
+ // treatment of this getter is allowed for backwards compatibility.
+ }
try {
DataValueDescriptor dvd = getColumn(columnIndex);
@@ -886,7 +900,7 @@ public abstract class EmbedResultSet ext
byte[] value = dvd.getBytes();
// check for the max field size limit
- if (maxFieldSize > 0 && isMaxFieldSizeType(getColumnType(columnIndex)))
+ if (maxFieldSize > 0 && isMaxFieldSizeType(columnType))
{
if (value.length > maxFieldSize)
{
@@ -4639,12 +4653,31 @@ public abstract class EmbedResultSet ext
* @throws SQLException if the column has already been accessed
*/
final void useStreamOrLOB(int columnIndex) throws SQLException {
+ checkLOBMultiCall(columnIndex);
+ columnUsedFlags[columnIndex - 1] = true;
+ }
+
+ /**
+ * Checks if a stream or a LOB object has already been created for the
+ * specified LOB column.
+ * <p>
+ * Accessing a LOB column more than once is not forbidden by the JDBC
+ * specification, but the Java API states that for maximum portability,
+ * result set columns within each row should be read in left-to-right order,
+ * and each column should be read only once. The restriction was implemented
+ * in Derby due to complexities with the positioning of store streams when
+ * the user was given multiple handles to the stream.
+ *
+ * @param columnIndex 1-based index of the LOB column
+ * @throws SQLException if the column has already been accessed
+ */
+ private void checkLOBMultiCall(int columnIndex)
+ throws SQLException {
if (columnUsedFlags == null) {
columnUsedFlags = new boolean[getMetaData().getColumnCount()];
} else if (columnUsedFlags[columnIndex - 1]) {
throw newSQLException(SQLState.LANG_STREAM_RETRIEVED_ALREADY);
}
- columnUsedFlags[columnIndex - 1] = true;
}
/**
Modified: db/derby/code/branches/10.8.3.1_testcompat/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdatableResultSetTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8.3.1_testcompat/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdatableResultSetTest.java?rev=1466174&r1=1466173&r2=1466174&view=diff
==============================================================================
--- db/derby/code/branches/10.8.3.1_testcompat/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdatableResultSetTest.java (original)
+++ db/derby/code/branches/10.8.3.1_testcompat/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdatableResultSetTest.java Tue Apr 9 18:40:45 2013
@@ -3177,18 +3177,20 @@ public class UpdatableResultSetTest ext
if (usingEmbedded() && JDBC.vmSupportsJDBC3()) {
println(" updateClob and then cancelRowUpdates");
String clb1 = rs.getString(13);
+ String clb2 = rs1.getString(13);
rs.updateClob(13, rs1.getClob(13));
assertEquals("FAIL - wrong value returned by getXXX method",
- rs1.getString(13), rs.getString(13));
+ clb2, rs.getString(13));
rs.cancelRowUpdates();
assertEquals("FAIL - wrong value returned by getXXX method",
clb1, rs.getString(13));
println(" updateBlob and then cancelRowUpdates");
bts = rs.getBytes(17);
+ byte[] bts2 = rs1.getBytes(17);
rs.updateBlob(17,rs1.getBlob(17));
assertTrue("FAIL - wrong value returned by getXXX method",
- java.util.Arrays.equals(rs.getBytes(17),rs1.getBytes(17)));
+ java.util.Arrays.equals(rs.getBytes(17), bts2));
rs.cancelRowUpdates();
assertTrue("FAIL - wrong value returned by getXXX method",
java.util.Arrays.equals(rs.getBytes(17),bts));