Author: kmarsden
Date: Thu Oct 20 15:18:36 2005
New Revision: 327012
URL: http://svn.apache.org/viewcvs?rev=327012&view=rev
Log:
DERBY-500 - Update/Select failure when BLOB/CLOB fields updated in several rows by PreparedStatement
using setBinaryStream and setCharacterStream
Sunitha merged r326307 from trunk manually because of conflicts.
Contributed by Sunitha Kambhampati (ksunithaghm@gmail.com)
Modified:
db/derby/code/branches/10.1/java/engine/org/apache/derby/iapi/reference/SQLState.java
db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/RawToBinaryFormatStream.java
db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/ReaderToUTF8Stream.java
db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/RememberBytesInputStream.java
db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java
db/derby/code/branches/10.1/java/engine/org/apache/derby/loc/messages_en.properties
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/forbitdata.out
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/streamingColumn.out
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forbitdata.java
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn.java
db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn_derby.properties
Modified: db/derby/code/branches/10.1/java/engine/org/apache/derby/iapi/reference/SQLState.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/engine/org/apache/derby/iapi/reference/SQLState.java?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/engine/org/apache/derby/iapi/reference/SQLState.java
(original)
+++ db/derby/code/branches/10.1/java/engine/org/apache/derby/iapi/reference/SQLState.java
Thu Oct 20 15:18:36 2005
@@ -1358,6 +1358,7 @@
String INVALID_JDBCTYPE = "XJ021.S";
String SET_STREAM_FAILURE = "XJ022.S";
String SET_STREAM_INEXACT_LENGTH_DATA = "XJ023.S";
+ String STREAM_EOF = "XJ085.S";
String SET_UNICODE_INVALID_LENGTH = "XJ024.S";
String NEGATIVE_STREAM_LENGTH = "XJ025.S";
String NO_AUTO_COMMIT_ON = "XJ030.S";
Modified: db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/RawToBinaryFormatStream.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/RawToBinaryFormatStream.java?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/RawToBinaryFormatStream.java
(original)
+++ db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/RawToBinaryFormatStream.java
Thu Oct 20 15:18:36 2005
@@ -23,6 +23,7 @@
import java.io.InputStream;
import java.io.FilterInputStream;
import java.io.IOException;
+import java.io.EOFException;
import org.apache.derby.iapi.services.io.LimitInputStream;
import org.apache.derby.iapi.services.i18n.MessageService;
@@ -32,10 +33,16 @@
Stream that takes a raw input stream and converts it
to the format of the binary types by prepending the
length of the value. In this case 0 is always written.
+ Note: This stream cannot be re-used. Once end of file is
+ reached, the next read call will throw an EOFException
*/
class RawToBinaryFormatStream extends LimitInputStream {
private int dummyBytes = 4;
+
+ // flag to indicate the stream has already been read
+ // and eof reached
+ private boolean eof = false;
/**
@param in Application's raw binary stream passed into JDBC layer
@@ -50,9 +57,15 @@
/**
Read from the wrapped stream prepending the intial bytes if needed.
+ If stream has been read, and eof reached, in that case any subsequent
+ read will throw an EOFException
*/
public int read() throws IOException {
+ if ( eof )
+ throw new EOFException(MessageService.getTextMessage
+ (SQLState.STREAM_EOF));
+
if (dummyBytes != 0) {
dummyBytes--;
return 0;
@@ -73,8 +86,13 @@
*/
private void checkSufficientData() throws IOException
{
+ // if we reached here, then read call returned -1, and we
+ // have already reached the end of stream, so set eof=true
+ // so that subsequent reads on this stream will return an
+ // EOFException
+ eof = true;
if (!limitInPlace)
- return;
+ return;
int remainingBytes = clearLimit();
@@ -99,8 +117,13 @@
/**
Read from the wrapped stream prepending the intial bytes if needed.
+ If stream has been read, and eof reached, in that case any subsequent
+ read will throw an EOFException
*/
public int read(byte b[], int off, int len) throws IOException {
+
+ if ( eof )
+ throw new EOFException(MessageService.getTextMessage(SQLState.STREAM_EOF));
int dlen = dummyBytes;
@@ -124,7 +147,6 @@
return dlen;
checkSufficientData();
-
return realRead;
}
Modified: db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/ReaderToUTF8Stream.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/ReaderToUTF8Stream.java?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/ReaderToUTF8Stream.java
(original)
+++ db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/jdbc/ReaderToUTF8Stream.java
Thu Oct 20 15:18:36 2005
@@ -54,8 +54,22 @@
blen = -1;
}
+ /**
+ * read from stream; characters converted to utf-8 derby specific encoding.
+ * If stream has been read, and eof reached, in that case any subsequent
+ * read will throw an EOFException
+ * @see java.io.InputStream#read()
+ */
public int read() throws IOException {
+ // when stream has been read and eof reached, stream is closed
+ // and buffer is set to null ( see close() method)
+ // since stream cannot be re-used, check if stream is closed and
+ // if so throw an EOFException
+ if ( buffer == null)
+ throw new EOFException(MessageService.getTextMessage(SQLState.STREAM_EOF));
+
+
// first read
if (blen < 0)
fillBuffer(2);
@@ -64,7 +78,14 @@
{
// reached end of buffer, read more?
if (eof)
- return -1;
+ {
+ // we have reached the end of this stream
+ // cleanup here and return -1 indicating
+ // eof of stream
+ close();
+ return -1;
+ }
+
fillBuffer(0);
}
@@ -74,7 +95,16 @@
}
public int read(byte b[], int off, int len) throws IOException {
- // first read
+
+ // when stream has been read and eof reached, stream is closed
+ // and buffer is set to null ( see close() method)
+ // since stream cannot be re-used, check if stream is closed and
+ // if so throw an EOFException
+ if ( buffer == null )
+ throw new EOFException(MessageService.getTextMessage
+ (SQLState.STREAM_EOF));
+
+ // first read
if (blen < 0)
fillBuffer(2);
@@ -90,8 +120,18 @@
{
if (eof)
{
- return readCount == 0 ? readCount : -1;
- }
+ if (readCount > 0)
+ {
+ return readCount;
+ }
+ else
+ {
+ // we have reached the eof, so close the stream
+ close();
+ return -1;
+ }
+ }
+
fillBuffer(0);
continue;
}
@@ -105,7 +145,6 @@
readCount += copyBytes;
}
-
return readCount;
}
@@ -184,6 +223,7 @@
buffer[0] = (byte) ((utflen >>> 8) & 0xFF);
buffer[1] = (byte) ((utflen >>> 0) & 0xFF);
+
}
else
{
@@ -193,10 +233,23 @@
}
}
+ /**
+ * return resources
+ */
public void close() throws IOException
{
- buffer = null;
- reader.close();
+ // since stream has been read and eof reached, return buffer back to
+ // the vm.
+ // Instead of using another variable to indicate stream is closed
+ // a check on (buffer==null) is used instead.
+ buffer = null;
+
+ // Note : Do not call reader.close() here since the reader
+ // holds the user's stream and calling reader.close would close
+ // the user's stream and that is incorrect. Derby must not
+ // close the user's stream, but it is the responsibility of the
+ // application to close the stream or do whatever the application
+ // wishes.
}
/**
Modified: db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/RememberBytesInputStream.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/RememberBytesInputStream.java?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/RememberBytesInputStream.java
(original)
+++ db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/RememberBytesInputStream.java
Thu Oct 20 15:18:36 2005
@@ -44,6 +44,12 @@
{
ByteHolder bh;
boolean recording = true;
+
+ // In case of streams (e.g ReaderToUTF8Stream,
+ // RawToBinaryFormatStream) that cannot be re-used
+ // a read on a closed stream will throw an EOFException
+ // hence keep track if the stream is closed or not
+ boolean streamClosed = false;
/**
Construct a RememberBytesInputStream.
@@ -58,6 +64,7 @@
SanityManager.ASSERT(bh.writingMode());
this.bh = bh;
+
}
/**
@@ -69,10 +76,19 @@
if (SanityManager.DEBUG)
SanityManager.ASSERT(recording,
"Must be in record mode to perform a read.");
- int value = super.read();
- if (value != -1)
- bh.write(value);
- return value;
+
+ int value = -1;
+
+ if ( !streamClosed )
+ {
+ value = super.read();
+ if ( value != -1 )
+ bh.write(value);
+ else
+ streamClosed =true;
+ }
+
+ return value;
}
/**
@@ -84,22 +100,46 @@
if (SanityManager.DEBUG)
SanityManager.ASSERT(recording,
"Must be in record mode to perform a read.");
- if ((len + off) > b.length)
- len = b.length - off;
- len = super.read(b,off,len);
- if (len != -1)
- bh.write(b,off,len);
- return len;
+
+ if ( !streamClosed ) {
+ if ((len + off) > b.length)
+ len = b.length - off;
+
+ len = super.read(b, off, len);
+ if (len > 0 )
+ bh.write(b, off, len);
+ else
+ streamClosed = true;
+ } else {
+ return -1;
+ }
+
+ return len;
}
/**
read len bytes from the input stream, and store it in the byte holder.
+ Note, fillBuf does not return negative values, if there are no
+ bytes to store in the byteholder, it will return 0
@exception IOException thrown on an io error spooling rememberd bytes
to backing storage.
*/
public long fillBuf(int len) throws IOException{
- return bh.write(this.in, len);
+
+ long val = 0;
+
+ if ( !streamClosed )
+ {
+ val = bh.write(this.in, len);
+
+ // if bh.write returns less than len, then the stream
+ // has reached end of stream. See logic in MemByteHolder.write
+ if ( val < len )
+ streamClosed=true;
+ }
+
+ return val;
}
/**
@@ -160,6 +200,7 @@
*/
public void setInput(InputStream in) {
this.in = in;
+ streamClosed = false;
}
/**
Modified: db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java
(original)
+++ db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java
Thu Oct 20 15:18:36 2005
@@ -6154,6 +6154,13 @@
// into the RememberBytesInputStream.
if (row[arrayPosition] instanceof StreamStorable)
((StreamStorable)row[arrayPosition]).setStream(bufferedIn);
+
+ // set column to the RememberBytesInputStream so that
+ // all future access to this column will be able to get
+ // at bytes that have been already read. This assignment
+ // is needed to ensure that if long column exception is
+ // thrown, the column is set correctly
+ column = bufferedIn;
}
// read the buffer by reading the max we can read.
Modified: db/derby/code/branches/10.1/java/engine/org/apache/derby/loc/messages_en.properties
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/engine/org/apache/derby/loc/messages_en.properties?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/engine/org/apache/derby/loc/messages_en.properties (original)
+++ db/derby/code/branches/10.1/java/engine/org/apache/derby/loc/messages_en.properties Thu
Oct 20 15:18:36 2005
@@ -1096,7 +1096,7 @@
XJ082.U=BLOB/CLOB values are not allowed as method parameters or receiver.
XJ083.U=''{0}'' not allowed because the ResultSet is not an updatable ResultSet.
XJ084.U=Column does not correspond to a column in the base table. Cannot issue ''{0}'' on
this column.
-
+XJ085.S=Stream has already been read and end-of-file reached and cannot be re-used.
0A000.S=Feature not implemented: {0}.
XJ004.C=Database ''{0}'' not found.
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/forbitdata.out
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/forbitdata.out?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/forbitdata.out
(original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/forbitdata.out
Thu Oct 20 15:18:36 2005
@@ -599,32 +599,62 @@
START testEncodedLengths
EL byte[] 10 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL stream 10 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL byte[] 10 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL stream 10 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL byte[] 30 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL stream 30 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL byte[] 30 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL stream 30 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL byte[] 31 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL stream 31 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL byte[] 31 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL stream 31 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL byte[] 32 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL stream 32 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL byte[] 32 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL stream 32 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL byte[] 1345 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL stream 1345 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL byte[] 1345 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL stream 1345 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL byte[] 23456 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL stream 23456 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL byte[] 23456 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL stream 23456 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL byte[] 32672 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
EL stream 32672 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL byte[] 32672 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL stream 32672 C1 OK DATA OK C2 OK DATA OK C3 OK DATA OK
+ EL byte[] 32700 C1 NULL C2 OK DATA OK C3 OK DATA OK
+ EL stream 32700 C1 NULL C2 OK DATA OK C3 OK DATA OK
EL byte[] 32700 C1 NULL C2 OK DATA OK C3 OK DATA OK
EL stream 32700 C1 NULL C2 OK DATA OK C3 OK DATA OK
EL byte[] 32767 C1 NULL C2 NULL C3 OK DATA OK
EL stream 32767 C1 NULL C2 NULL C3 OK DATA OK
+ EL byte[] 32767 C1 NULL C2 NULL C3 OK DATA OK
+ EL stream 32767 C1 NULL C2 NULL C3 OK DATA OK
EL byte[] 32768 C1 NULL C2 NULL C3 OK DATA OK
EL stream 32768 C1 NULL C2 NULL C3 OK DATA OK
+ EL byte[] 32768 C1 NULL C2 NULL C3 OK DATA OK
+ EL stream 32768 C1 NULL C2 NULL C3 OK DATA OK
+ EL byte[] 32769 C1 NULL C2 NULL C3 OK DATA OK
+ EL stream 32769 C1 NULL C2 NULL C3 OK DATA OK
EL byte[] 32769 C1 NULL C2 NULL C3 OK DATA OK
EL stream 32769 C1 NULL C2 NULL C3 OK DATA OK
EL byte[] 65535 C1 NULL C2 NULL C3 OK DATA OK
EL stream 65535 C1 NULL C2 NULL C3 OK DATA OK
+ EL byte[] 65535 C1 NULL C2 NULL C3 OK DATA OK
+ EL stream 65535 C1 NULL C2 NULL C3 OK DATA OK
+ EL byte[] 65536 C1 NULL C2 NULL C3 OK DATA OK
+ EL stream 65536 C1 NULL C2 NULL C3 OK DATA OK
EL byte[] 65536 C1 NULL C2 NULL C3 OK DATA OK
EL stream 65536 C1 NULL C2 NULL C3 OK DATA OK
EL byte[] 65537 C1 NULL C2 NULL C3 OK DATA OK
EL stream 65537 C1 NULL C2 NULL C3 OK DATA OK
+ EL byte[] 65537 C1 NULL C2 NULL C3 OK DATA OK
+ EL stream 65537 C1 NULL C2 NULL C3 OK DATA OK
+ EL byte[] 115882 C1 NULL C2 NULL C3 OK DATA OK
+ EL stream 115882 C1 NULL C2 NULL C3 OK DATA OK
EL byte[] 115882 C1 NULL C2 NULL C3 OK DATA OK
EL stream 115882 C1 NULL C2 NULL C3 OK DATA OK
END testEncodedLengths
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/streamingColumn.out
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/streamingColumn.out?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/streamingColumn.out
(original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/master/streamingColumn.out
Thu Oct 20 15:18:36 2005
@@ -98,4 +98,39 @@
===> testing trailing non-blanks(using setObject) length = 32703
expected exception for data > 32700 in length
Test 13 - long varchar truncation tests end in here
+======================================
+START DERBY-500 TEST
+Inserting rows
+Rows inserted =10
+Rows selected =10
+Update qualifies many rows + streams
+EXPECTED EXCEPTION - streams cannot be re-used
+EXPECTED SQL Exception: (XSDA4) An unexpected exception was thrown
+EXPECTED SQL Exception: (XJ001) Java exception: 'Stream has already been read and end-of-file
reached and cannot be re-used.: java.io.EOFException'.
+Rows selected =10
+DERBY500 #2 Rows updated =1
+Rows selected =1
+DERBY500 #3 Rows deleted =10
+Rows selected =0
+DERBY500 #4 Rows deleted =0
+Rows selected =0
+EXPECTED EXCEPTION - streams cannot be re-used
+EXPECTED SQL Exception: (XSDA4) An unexpected exception was thrown
+EXPECTED SQL Exception: (XJ001) Java exception: 'Stream has already been read and end-of-file
reached and cannot be re-used.: java.io.EOFException'.
+END DERBY-500 TEST
+======================================
+======================================
+START DERBY-500 TEST for varchar
+Rows inserted =10
+Rows selected =10
+DERBY500 for varchar #1 Rows updated =11
+Rows selected =10
+DERBY500 for varchar #2 Rows updated =1
+Rows selected =1
+DERBY500 for varchar #3 Rows deleted =11
+Rows selected =0
+DERBY500 for varchar #4 Rows deleted =0
+Rows selected =0
+END DERBY-500 TEST for varchar
+======================================
Test streamingColumn finished
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forbitdata.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forbitdata.java?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forbitdata.java
(original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/lang/forbitdata.java
Thu Oct 20 15:18:36 2005
@@ -717,44 +717,7 @@
psi.executeUpdate();
conn.commit();
- ResultSet rs = pss.executeQuery();
- while (rs.next())
- {
- System.out.print(" EL byte[] " + length);
- byte[] v = rs.getBytes(1);
- if (v != null) {
- System.out.print(" C1 " + ((v.length == length) ? "OK" : ("FAIL <" + v.length + ">")));
- System.out.print(" DATA " + ((v[off] == 0x23) ? "OK" : ("FAIL " + off)));
- }
- else
- System.out.print(" C1 NULL");
-
- v = rs.getBytes(2);
- if (v != null) {
- System.out.print(" C2 " + ((v.length == length) ? "OK" : ("FAIL <" + v.length + ">")));
- System.out.print(" DATA " + ((v[off] == 0x23) ? "OK" : ("FAIL " + off)));
- }
- else
- System.out.print(" C2 NULL");
- InputStream c3 = rs.getBinaryStream(3);
- checkEncodedLengthValue("C3", c3, length, off);
-
- System.out.println("");
- }
- rs.close();
-
- rs = pss.executeQuery();
- while (rs.next())
- {
- System.out.print(" EL stream " + length);
-
- checkEncodedLengthValue("C1", rs.getBinaryStream(1), length, off);
- checkEncodedLengthValue("C2", rs.getBinaryStream(2), length, off);
- checkEncodedLengthValue("C3", rs.getBinaryStream(3), length, off);
-
- System.out.println("");
- }
- rs.close();
+ selectData(pss,data,off,length);
conn.commit();
@@ -762,21 +725,68 @@
conn.commit();
+ // Set values using stream and then verify that select is successful
psi.setBinaryStream(1, (length <= 32672) ? new java.io.ByteArrayInputStream(data) :
null, length);
psi.setBinaryStream(2, (length <= 32700) ? new java.io.ByteArrayInputStream(data) :
null, length);
psi.setBinaryStream(3, new java.io.ByteArrayInputStream(data), length); // BLOB column
psi.executeUpdate();
conn.commit();
- psd.executeUpdate();
+ selectData(pss,data,off,length);
+ conn.commit();
+ psd.executeUpdate();
conn.commit();
}
+ private static void selectData(PreparedStatement pss,byte[] data,int off,int length)
+ throws SQLException,IOException
+ {
+
+ ResultSet rs = pss.executeQuery();
+ while (rs.next())
+ {
+ System.out.print(" EL byte[] " + length);
+ byte[] v = rs.getBytes(1);
+ if (v != null) {
+ System.out.print(" C1 " + ((v.length == length) ? "OK" : ("FAIL <" + v.length
+ ">")));
+ System.out.print(" DATA " + ((v[off] == 0x23) ? "OK" : ("FAIL " + off)));
+ }
+ else
+ System.out.print(" C1 NULL");
+
+ v = rs.getBytes(2);
+ if (v != null) {
+ System.out.print(" C2 " + ((v.length == length) ? "OK" : ("FAIL <" + v.length
+ ">")));
+ System.out.print(" DATA " + ((v[off] == 0x23) ? "OK" : ("FAIL " + off)));
+ }
+ else
+ System.out.print(" C2 NULL");
+ InputStream c3 = rs.getBinaryStream(3);
+ checkEncodedLengthValue("C3", c3, length, off);
+
+ System.out.println("");
+ }
+ rs.close();
+
+ rs = pss.executeQuery();
+ while (rs.next())
+ {
+ System.out.print(" EL stream " + length);
+
+ checkEncodedLengthValue("C1", rs.getBinaryStream(1), length, off);
+ checkEncodedLengthValue("C2", rs.getBinaryStream(2), length, off);
+ checkEncodedLengthValue("C3", rs.getBinaryStream(3), length, off);
+
+ System.out.println("");
+ }
+ rs.close();
+
+ }
private static void checkEncodedLengthValue(String col, InputStream is, int length, int
off) throws IOException {
if (is == null) {
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn.java
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn.java?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn.java
(original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn.java
Thu Oct 20 15:18:36 2005
@@ -92,7 +92,9 @@
streamTest5(conn, 0);
streamTest5(conn, 1500);
streamTest5(conn, 5000);
- streamTest5(conn, 100000);
+ // This test fails when running w/ derby.language.logStatementText=true
+ // see DERBY-595
+ //streamTest5(conn, 100000);
streamTest6(conn, 5000);
streamTest7(conn);
@@ -117,6 +119,19 @@
// bug 5592 test - any character(including blank character) truncation should give error
for long varchars
streamTest13(conn);
+
+
+ // Derby500
+ // user supplied stream parameter values are not re-used
+ derby500Test(conn);
+
+ // currently in case of char,varchar,long varchar types
+ // stream paramter value is materialized the first time around
+ // and used for executions. Hence verify that the fix to
+ // DERBY-500 did not change the behavior for char,varchar
+ // and long varchar types when using streams.
+ derby500_verifyVarcharStreams(conn);
+
// turn autocommit on because in JCC, java.sql.Connection.close() can not be
// requested while a transaction is in progress on the connection.
// If autocommit is off in JCC, the transaction remains active,
@@ -1145,6 +1160,438 @@
}
+
+ /**
+ * Streams are not re-used. This test tests the fix for
+ * DERBY-500. If an update statement has multiple rows that
+ * is affected, and one of the parameter values is a stream,
+ * the update will fail because streams are not re-used.
+ * @param conn database connection
+ */
+ private static void derby500Test(Connection conn) {
+
+ Statement stmt;
+
+ System.out.println("======================================");
+ System.out.println("START DERBY-500 TEST ");
+
+ try {
+ stmt = conn.createStatement();
+ conn.setAutoCommit(false);
+ stmt.execute("CREATE TABLE t1 (" + "id INTEGER NOT NULL,"
+ + "mname VARCHAR( 254 ) NOT NULL," + "mvalue INT NOT NULL,"
+ + "bytedata BLOB NOT NULL," + "chardata CLOB NOT NULL,"
+ + "PRIMARY KEY ( id ))");
+
+ PreparedStatement ps = conn
+ .prepareStatement("insert into t1 values (?,?,?,?,?)");
+
+ // insert 10 rows.
+ int rowCount = 0;
+ // use blob and clob values
+ int len = 10000;
+ byte buf[] = new byte[len];
+ char cbuf[] = new char[len];
+ char orig = 'c';
+ for (int i = 0; i < len; i++) {
+ buf[i] = (byte)orig;
+ cbuf[i] = orig;
+ }
+ int randomOffset = 9998;
+ buf[randomOffset] = (byte) 'e';
+ cbuf[randomOffset] = 'e';
+ System.out.println("Inserting rows ");
+ for (int i = 0; i < 10; i++) {
+ ps.setInt(1, i);
+ ps.setString(2, "mname" + i);
+ ps.setInt(3, 0);
+ ps.setBinaryStream(4, new ByteArrayInputStream(buf), len);
+ ps.setAsciiStream(5, new ByteArrayInputStream(buf), len);
+ rowCount += ps.executeUpdate();
+ }
+ conn.commit();
+ System.out.println("Rows inserted =" + rowCount);
+
+
+ //conn.commit();
+ PreparedStatement pss = conn
+ .prepareStatement(" select chardata,bytedata from t1 where id = ?");
+ verifyDerby500Test(pss, buf, cbuf,0, 10, true);
+
+ // do the update, update must qualify more than 1 row and update will fail
+ // as currently we dont allow stream values to be re-used
+ PreparedStatement psu = conn
+ .prepareStatement("update t1 set bytedata = ? "
+ + ", chardata = ? where mvalue = ? ");
+
+ buf[randomOffset + 1] = (byte) 'u';
+ cbuf[randomOffset +1] = 'u';
+ rowCount = 0;
+ System.out.println("Update qualifies many rows + streams");
+
+ try {
+ psu.setBinaryStream(1, new ByteArrayInputStream(buf), len);
+ psu.setCharacterStream(2, new CharArrayReader(cbuf), len);
+ psu.setInt(3, 0);
+ rowCount += psu.executeUpdate();
+ System.out.println("DERBY500 #1 Rows updated ="
+ + rowCount);
+
+ } catch (SQLException sqle) {
+ System.out
+ .println("EXPECTED EXCEPTION - streams cannot be re-used");
+ expectedException(sqle);
+ conn.rollback();
+ }
+
+ //verify data
+ //set back buffer value to what was inserted.
+ buf[randomOffset + 1] = (byte)orig;
+ cbuf[randomOffset + 1] = orig;
+
+ verifyDerby500Test(pss, buf,cbuf, 0, 10,true);
+
+ PreparedStatement psu2 = conn
+ .prepareStatement("update t1 set bytedata = ? "
+ + ", chardata = ? where id = ? ");
+
+ buf[randomOffset + 1] = (byte) 'u';
+ cbuf[randomOffset + 1] = 'u';
+
+ rowCount = 0;
+ try {
+ psu2.setBinaryStream(1, new ByteArrayInputStream(buf), len);
+ psu2.setAsciiStream(2, new ByteArrayInputStream(buf), len);
+ psu2.setInt(3, 0);
+ rowCount += psu2.executeUpdate();
+ System.out.println("DERBY500 #2 Rows updated ="
+ + rowCount);
+
+ } catch (SQLException sqle) {
+ System.out
+ .println("UNEXPECTED EXCEPTION - update should have actually gone
through");
+ dumpSQLExceptions(sqle);
+ }
+ conn.commit();
+ verifyDerby500Test(pss, buf,cbuf, 0, 1,true);
+
+ // delete
+ // as currently we dont allow stream values to be re-used
+ PreparedStatement psd = conn
+ .prepareStatement("delete from t1 where mvalue = ?");
+
+ rowCount = 0;
+ try {
+ psd.setInt(1, 0);
+ rowCount += psd.executeUpdate();
+ rowCount += psd.executeUpdate();
+ System.out.println("DERBY500 #3 Rows deleted ="
+ + rowCount);
+
+ } catch (SQLException sqle) {
+ System.out
+ .println("UNEXPECTED EXCEPTION - delete should have actually gone through");
+ dumpSQLExceptions(sqle);
+ }
+
+ conn.commit();
+ //verify data
+
+ verifyDerby500Test(pss, buf,cbuf, 0, 10, true);
+
+ PreparedStatement psd2 = conn
+ .prepareStatement("delete from t1 where id = ?");
+
+ rowCount = 0;
+ try {
+ psd2.setInt(1, 0);
+ rowCount += psd2.executeUpdate();
+ System.out.println("DERBY500 #4 Rows deleted ="
+ + rowCount);
+
+ } catch (SQLException sqle) {
+ System.out
+ .println("UNEXPECTED EXCEPTION - delete should have actually gone
through");
+ dumpSQLExceptions(sqle);
+ }
+ conn.commit();
+ verifyDerby500Test(pss, buf,cbuf, 1, 2,true);
+
+ try
+ {
+ ps.setInt(1,11);
+ rowCount += ps.executeUpdate();
+ System.out.println("Rows inserted = "+ rowCount);
+ } catch (SQLException sqle) {
+ System.out
+ .println("EXPECTED EXCEPTION - streams cannot be re-used");
+ expectedException(sqle);
+ conn.rollback();
+ }
+
+ stmt.execute("drop table t1");
+ conn.commit();
+ stmt.close();
+ pss.close();
+ psu2.close();
+ psu.close();
+ psd.close();
+ psd2.close();
+ System.out.println("END DERBY-500 TEST ");
+ System.out.println("======================================");
+
+ } catch (SQLException sqle) {
+ dumpSQLExceptions(sqle);
+ } catch (Exception e) {
+ System.out.println("DERBY-500 TEST FAILED!");
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * Test that DERBY500 fix did not change the behavior for varchar,
+ * char, long varchar types when stream api is used.
+ * Currently, for char,varchar and long varchar - the stream is
+ * read once and materialized, hence the materialized stream value
+ * will/can be used for multiple executions of the prepared statement
+ * @param conn database connection
+ */
+ private static void derby500_verifyVarcharStreams(Connection conn) {
+
+ Statement stmt;
+
+ System.out.println("======================================");
+ System.out.println("START DERBY-500 TEST for varchar ");
+
+ try {
+ stmt = conn.createStatement();
+ stmt.execute("CREATE TABLE t1 (" + "id INTEGER NOT NULL,"
+ + "mname VARCHAR( 254 ) NOT NULL," + "mvalue INT NOT NULL,"
+ + "vc varchar(32500)," + "lvc long varchar NOT NULL,"
+ + "PRIMARY KEY ( id ))");
+
+ PreparedStatement ps = conn
+ .prepareStatement("insert into t1 values (?,?,?,?,?)");
+
+ // insert 10 rows.
+ int rowCount = 0;
+ // use blob and clob values
+ int len = 10000;
+ byte buf[] = new byte[len];
+ char cbuf[] = new char[len];
+ char orig = 'c';
+ for (int i = 0; i < len; i++) {
+ buf[i] = (byte)orig;
+ cbuf[i] = orig;
+ }
+ int randomOffset = 9998;
+ buf[randomOffset] = (byte)'e';
+ cbuf[randomOffset] = 'e';
+ for (int i = 0; i < 10; i++) {
+ ps.setInt(1, i);
+ ps.setString(2, "mname" + i);
+ ps.setInt(3, 0);
+ ps.setCharacterStream(4, new CharArrayReader(cbuf), len);
+ ps.setAsciiStream(5, new ByteArrayInputStream(buf), len);
+ rowCount += ps.executeUpdate();
+ }
+ conn.commit();
+ System.out.println("Rows inserted =" + rowCount);
+
+ try
+ {
+ ps.setInt(1,11);
+ rowCount += ps.executeUpdate();
+ } catch (SQLException sqle) {
+ System.out.println("UNEXPECTED EXCEPTION - streams cannot be "+
+ "re-used but in case of varchar, stream is materialized the"+
+ " first time around. So multiple executions using streams should "+
+ " work fine. ");
+ dumpSQLExceptions(sqle);
+ }
+
+ PreparedStatement pss = conn
+ .prepareStatement(" select lvc,vc from t1 where id = ?");
+ verifyDerby500Test(pss, buf, cbuf,0, 10,false);
+
+ // do the update, update must qualify more than 1 row and update will
+ // pass for char,varchar,long varchar columns.
+ PreparedStatement psu = conn
+ .prepareStatement("update t1 set vc = ? "
+ + ", lvc = ? where mvalue = ? ");
+
+ buf[randomOffset +1] = (byte)'u';
+ cbuf[randomOffset +1] = 'u';
+ rowCount = 0;
+ try {
+ psu.setAsciiStream(1, new ByteArrayInputStream(buf), len);
+ psu.setCharacterStream(2, new CharArrayReader(cbuf), len);
+ psu.setInt(3, 0);
+ rowCount += psu.executeUpdate();
+ } catch (SQLException sqle) {
+ System.out
+ .println("EXPECTED EXCEPTION - streams cannot be re-used");
+ expectedException(sqle);
+ }
+ System.out.println("DERBY500 for varchar #1 Rows updated ="
+ + rowCount);
+
+ //verify data
+ verifyDerby500Test(pss, buf,cbuf, 0, 10, false);
+
+ PreparedStatement psu2 = conn
+ .prepareStatement("update t1 set vc = ? "
+ + ", lvc = ? where id = ? ");
+
+ buf[randomOffset +1] = (byte)'h';
+ cbuf[randomOffset + 1] = 'h';
+
+ rowCount = 0;
+ try {
+ psu2.setAsciiStream(1, new ByteArrayInputStream(buf), len);
+ psu2.setAsciiStream(2, new ByteArrayInputStream(buf), len);
+ psu2.setInt(3, 0);
+ rowCount += psu2.executeUpdate();
+ } catch (SQLException sqle) {
+ System.out
+ .println("UNEXPECTED EXCEPTION - update should have actually gone
through");
+ dumpSQLExceptions(sqle);
+ }
+ conn.commit();
+ System.out.println("DERBY500 for varchar #2 Rows updated ="
+ + rowCount);
+ verifyDerby500Test(pss, buf,cbuf, 0, 1,false);
+
+ // delete
+ // as currently we dont allow stream values to be re-used
+ PreparedStatement psd = conn
+ .prepareStatement("delete from t1 where mvalue = ?");
+
+ rowCount = 0;
+ try {
+ psd.setInt(1, 0);
+ rowCount += psd.executeUpdate();
+ rowCount += psd.executeUpdate();
+ } catch (SQLException sqle) {
+ System.out
+ .println("UNEXPECTED EXCEPTION - delete should have actually gone through");
+ dumpSQLExceptions(sqle);
+ }
+ System.out.println("DERBY500 for varchar #3 Rows deleted ="
+ + rowCount);
+
+ //verify data
+ verifyDerby500Test(pss, buf,cbuf, 0, 10,false);
+
+ PreparedStatement psd2 = conn
+ .prepareStatement("delete from t1 where id = ?");
+
+ rowCount = 0;
+ try {
+ psd2.setInt(1, 0);
+ rowCount += psd2.executeUpdate();
+ } catch (SQLException sqle) {
+ System.out
+ .println("UNEXPECTED EXCEPTION - delete should have actually gone
through");
+ dumpSQLExceptions(sqle);
+ }
+ conn.commit();
+ System.out.println("DERBY500 for varchar #4 Rows deleted ="
+ + rowCount);
+ verifyDerby500Test(pss, buf,cbuf, 1, 2,false);
+
+ stmt.execute("drop table t1");
+ conn.commit();
+ stmt.close();
+ pss.close();
+ psu2.close();
+ psu.close();
+ psd.close();
+ psd2.close();
+ System.out.println("END DERBY-500 TEST for varchar");
+ System.out.println("======================================");
+
+ } catch (SQLException sqle) {
+ dumpSQLExceptions(sqle);
+ } catch (Exception e) {
+ System.out.println("DERBY-500 TEST for varchar FAILED!");
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * verify the data in the derby500Test
+ * @param ps select preparedstatement
+ * @param buf byte array to compare the blob data
+ * @param cbuf char array to compare the clob data
+ * @param startId start id of the row to check data for
+ * @param endId end id of the row to check data for
+ * @param binaryType flag to indicate if the second column in resultset
+ * is a binary type or not. true for binary type
+ * @throws Exception
+ */
+ private static void verifyDerby500Test(PreparedStatement ps, byte[] buf,char[] cbuf,
+ int startId, int endId,boolean binaryType) throws Exception {
+ byte[] retrieveData = null;
+ int rowCount = 0;
+ ResultSet rs = null;
+ for (int i = startId; i < endId; i++) {
+ ps.setInt(1, i);
+ rs = ps.executeQuery();
+ if(rs.next())
+ {
+ compareCharArray(rs.getCharacterStream(1), cbuf,cbuf.length);
+ if(binaryType)
+ byteArrayEquals(rs.getBytes(2), 0, buf.length, buf, 0, buf.length);
+ else
+ compareCharArray(rs.getCharacterStream(2), cbuf,cbuf.length);
+
+ rowCount++;
+ }
+ }
+ System.out.println("Rows selected =" + rowCount);
+ rs.close();
+ }
+ /**
+ * compare char data
+ * @param stream data from stream to compare
+ * @param compare base data to compare against
+ * @param length compare length number of chars.
+ * @throws Exception
+ */
+ private static void compareCharArray(Reader stream, char[] compare,
+ int length) throws Exception {
+ int c1 = 0;
+ int i = 0;
+ do {
+ c1 = stream.read();
+ if (c1 != compare[i++]) {
+ System.out
+ .println("FAIL -- MISMATCH in data stored versus data retrieved at
"
+ + (i - 1));
+ break;
+ }
+ length--;
+ } while (c1 != -1 && length > 0);
+
+ }
+
+ private static void expectedException(SQLException sqle) {
+
+ while (sqle != null) {
+ String sqlState = sqle.getSQLState();
+ if (sqlState == null) {
+ sqlState = "<NULL>";
+ }
+ System.out.println("EXPECTED SQL Exception: (" + sqlState + ") "
+ + sqle.getMessage());
+
+ sqle = sqle.getNextException();
+ }
+ }
+
private static void streamTestDataVerification(ResultSet rs, int maxValueAllowed)
throws Exception{
ResultSetMetaData met;
@@ -1417,4 +1864,6 @@
se = se.getNextException();
}
}
+
+
}
Modified: db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn_derby.properties
URL: http://svn.apache.org/viewcvs/db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn_derby.properties?rev=327012&r1=327011&r2=327012&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn_derby.properties
(original)
+++ db/derby/code/branches/10.1/java/testing/org/apache/derbyTesting/functionTests/tests/store/streamingColumn_derby.properties
Thu Oct 20 15:18:36 2005
@@ -4,5 +4,5 @@
derby.drda.debug=true
derby.drda.traceAll=true
derby.stream.error.logSeverityLevel=0
-derby.language.logStatementText=true
+#derby.language.logStatementText=true - this masks exceptions - DERBY595
derby.infolog.append=true
|