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 kr...@apache.org on 2008/08/05 19:11:33 UTC
svn commit: r682803 - in /db/derby/code/branches/10.4/java:
engine/org/apache/derby/impl/jdbc/
testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/
Author: kristwaa
Date: Tue Aug 5 10:11:32 2008
New Revision: 682803
URL: http://svn.apache.org/viewvc?rev=682803&view=rev
Log:
DERBY-3766, DERBY-3783 (second patch): EmbedBlob.setPosition is highly ineffective for streams.
Backporting from trunk: 677619 (derby-3766-1a-preparations.diff), 681359 (derby-3766-2a-position_fix.diff), and 678388 (d3783-initCause.diff).
Modified:
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/AutoPositioningStream.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUpdatableReader.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBInputStream.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBOutputStream.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UpdatableBlobStream.java
db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/Util.java
db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/AutoPositioningStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/AutoPositioningStream.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/AutoPositioningStream.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/AutoPositioningStream.java Tue Aug 5 10:11:32 2008
@@ -156,9 +156,7 @@
}
}
catch (StandardException se) {
- IOException ioe = new IOException (se.getMessage());
- ioe.initCause (se);
- throw ioe;
+ throw Util.newIOException(se);
}
}
}
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUpdatableReader.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUpdatableReader.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUpdatableReader.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUpdatableReader.java Tue Aug 5 10:11:32 2008
@@ -222,9 +222,7 @@
stream = clob.getInternalClob().getRawByteStream();
}
catch (SQLException e) {
- IOException ioe = new IOException (e.getMessage());
- ioe.initCause (e);
- throw ioe;
+ throw Util.newIOException(e);
}
init ((LOBInputStream) stream, pos);
materialized = true;
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java Tue Aug 5 10:11:32 2008
@@ -104,9 +104,7 @@
pos += ret;
}
catch (SQLException e) {
- IOException ioe = new IOException (e.getMessage());
- ioe.initCause (e);
- throw ioe;
+ throw Util.newIOException(e);
}
}
}
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java Tue Aug 5 10:11:32 2008
@@ -33,6 +33,7 @@
import java.sql.SQLException;
import java.sql.Blob;
+import java.io.EOFException;
import java.io.InputStream;
import java.io.IOException;
@@ -78,7 +79,12 @@
* Derby store, and is read-only.
*/
private boolean materialized;
- private InputStream myStream;
+ /**
+ * The underlying positionable store stream, if any.
+ * <p>
+ * If {@link #materialized} is {@code true}, the stream is {@code null}.
+ */
+ private PositionedStoreStream myStream;
/**
* Locator value for this Blob, used as a handle by the client driver to
@@ -91,21 +97,22 @@
/**
* Length of the stream representing the Blob.
* <p>
- * Set to -1 when the stream has been materialized {@link #materialized} or
+ * Set to -1 when the stream has been {@link #materialized} or
* the length of the stream is not currently known.
*/
private long streamLength = -1;
- // note: cannot control position of the stream since user can do a getBinaryStream
- private long pos;
- // this stream sits on top of myStream
- private BinaryToRawStream biStream;
-
- // buffer for reading in blobs from a stream (long column)
- // and trashing them (to set the position of the stream etc.)
- private static int BLOB_BUF_SIZE = 4096;
- private byte buf[];
-
+ /**
+ * Position offset for the stream representing the Blob, if any.
+ * <p>
+ * This offset accounts for the bytes encoding the stream length at the
+ * head of the stream. Data byte {@code pos} is at
+ * {@code pos + streamPositionOffset} in the underlying stream.
+ * Set to {@code Integer.MIN_VALUE} if the Blob isn't represented by a
+ * store stream.
+ */
+ private final int streamPositionOffset;
+
//This boolean variable indicates whether the Blob object has
//been invalidated by calling free() on it
private boolean isValid = true;
@@ -128,6 +135,7 @@
try {
control = new LOBStreamControl (con.getDBName(), blobBytes);
materialized = true;
+ streamPositionOffset = Integer.MIN_VALUE;
//add entry in connection so it can be cleared
//when transaction is not valid
con.addLOBReference (this);
@@ -152,10 +160,11 @@
if (SanityManager.DEBUG)
SanityManager.ASSERT(!dvd.isNull(), "blob is created on top of a null column");
- myStream = dvd.getStream();
- if (myStream == null)
+ InputStream dvdStream = dvd.getStream();
+ if (dvdStream == null)
{
materialized = true;
+ streamPositionOffset = Integer.MIN_VALUE;
// copy bytes into memory so that blob can live after result set
// is closed
byte[] dvdBytes = dvd.getBytes();
@@ -182,12 +191,14 @@
implementing the getStream() method for dvd.getStream(), does not
guarantee this for us
*/
- if (SanityManager.DEBUG)
- SanityManager.ASSERT(myStream instanceof Resetable);
- //make myStream a position aware stream
- myStream = new PositionedStoreStream (myStream);
+ if (SanityManager.DEBUG) {
+ SanityManager.ASSERT(dvdStream instanceof Resetable);
+ }
+ // Create a position aware stream on top of dvdStream so we can
+ // more easily move back and forth in the Blob.
+ myStream = new PositionedStoreStream(dvdStream);
try {
- ((Resetable) myStream).initStream();
+ myStream.initStream();
} catch (StandardException se) {
if (se.getMessageId().equals(SQLState.DATA_CONTAINER_CLOSED)) {
throw StandardException
@@ -196,72 +207,97 @@
throw se;
}
}
- // set up the buffer for trashing the bytes to set the position of
- // the
- // stream, only need a buffer when we have a long column
- buf = new byte[BLOB_BUF_SIZE];
+ try {
+ // The BinaryToRawStream will read the encoded length bytes.
+ BinaryToRawStream tmpStream =
+ new BinaryToRawStream(myStream, con);
+ streamPositionOffset = (int)myStream.getPosition();
+ // Check up front if the stream length is specified.
+ streamLength = tmpStream.getLength();
+ tmpStream.close();
+ } catch (IOException ioe) {
+ throw StandardException.newException(
+ SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION, ioe);
+ }
}
- pos = 0;
//add entry in connection so it can be cleared
//when transaction is not valid
con.addLOBReference (this);
}
- /*
- Sets the position of the stream to position newPos, where position 0 is
- the beginning of the stream.
-
- @param newPos the position to set to
- @exception StandardException (BLOB_SETPOSITION_FAILED) throws this if
- the stream runs out before we get to newPos
- */
- private void setPosition(long newPos)
+ /**
+ * Sets the position of the Blob to {@code logicalPos}, where position 0 is
+ * the beginning of the Blob content.
+ * <p>
+ * The position is only guaranteed to be valid from the time this method is
+ * invoked until the synchronization monitor is released, or until the next
+ * invokation of this method.
+ * <p>
+ * The position is logical in the sense that it specifies the requested
+ * position in the Blob content. This position might be at a different
+ * position in the underlying representation, for instance the Derby store
+ * stream prepends the Blob content with a length field.
+ *
+ * @param logicalPos requested Blob position, 0-based
+ * @return The new position, which will be equal to the requested position.
+ * @throws IOException if reading/accessing the Blob fails
+ * @throws StandardException throws BLOB_POSITION_TOO_LARGE if the requested
+ * position is larger than the Blob length, throws other SQL states if
+ * resetting the stream fails
+ */
+ //@GuardedBy(getConnectionSynchronization())
+ private long setBlobPosition(long logicalPos)
throws StandardException, IOException
{
if (SanityManager.DEBUG)
- SanityManager.ASSERT(newPos >= 0);
- if (materialized)
- pos = newPos;
- else {
- // Always resets the stream to the beginning first, because user can
- // influence the state of the stream without letting us know.
- ((Resetable)myStream).resetStream();
- // PT could try to save creating a new object each time
- biStream = new BinaryToRawStream(myStream, this);
- pos = 0;
- while (pos < newPos)
- {
- int size = biStream.read(
- buf,0,(int) Math.min((newPos-pos), (long) BLOB_BUF_SIZE));
- if (size <= 0) // ran out of stream
- throw StandardException.newException(SQLState.BLOB_LENGTH_TOO_LONG);
- pos += size;
+ SanityManager.ASSERT(logicalPos >= 0);
+ if (materialized) {
+ // Nothing to do here, except checking if the position is valid.
+ if (logicalPos >= control.getLength()) {
+ throw StandardException.newException(
+ SQLState.BLOB_POSITION_TOO_LARGE, new Long(logicalPos));
+ }
+ } else {
+ // Reposition the store stream, account for the length field offset.
+ try {
+ this.myStream.reposition(
+ logicalPos + this.streamPositionOffset);
+ } catch (EOFException eofe) {
+ throw StandardException.newException(
+ SQLState.BLOB_POSITION_TOO_LARGE, eofe,
+ new Long(logicalPos));
}
}
+ return logicalPos;
}
- /*
- Reads one byte, either from the byte array or else from the stream.
- */
- private int read() throws IOException, SQLException {
+ /**
+ * Reads one byte from the Blob at the specified position.
+ * <p>
+ * Depending on the representation, this might result in a read from a byte
+ * array, a temporary file on disk or from a Derby store stream.
+ *
+ * @param pos the 0-based position in the Blob to read
+ * @return The byte at the specified position.
+ * @throws IOException if reading from the underlying data representation
+ * fails
+ */
+ private int read(long pos)
+ throws IOException, StandardException {
int c;
- if (materialized)
- {
- try {
- if (pos >= control.getLength())
- return -1;
- else
- c = control.read (pos);
- }
- catch (StandardException se) {
- throw Util.generateCsSQLException (se);
- }
+ if (materialized) {
+ if (pos >= control.getLength())
+ return -1;
+ else
+ c = control.read (pos);
+ } else {
+ // Make sure we're at the right position.
+ this.myStream.reposition(pos + this.streamPositionOffset);
+ // Read one byte from the stream.
+ c = this.myStream.read();
}
- else
- c = biStream.read();
- pos++;
return c;
}
@@ -299,35 +335,34 @@
if (pushStack)
setupContextStack();
- setPosition(0);
- // If possible get the length from the encoded
- // length at the front of the raw stream.
- if ((streamLength = biStream.getLength()) != -1) {
- biStream.close();
- return streamLength;
+ // We have to read the entire stream!
+ myStream.resetStream();
+ BinaryToRawStream tmpStream =
+ new BinaryToRawStream(myStream, this);
+ streamLength = 0;
+ if (SanityManager.DEBUG) {
+ SanityManager.ASSERT(tmpStream.getLength() == -1);
}
-
- // Otherwise have to read the entire stream!
+
for (;;)
{
- long skipped = biStream.skip(Limits.DB2_LOB_MAXWIDTH);
+ long skipped = tmpStream.skip(Limits.DB2_LOB_MAXWIDTH);
if (SanityManager.DEBUG) {
SanityManager.ASSERT(skipped >= 0);
}
- pos += skipped;
+ streamLength += skipped;
// If skip reports zero bytes skipped, verify EOF.
if (skipped == 0) {
- if (biStream.read() == -1) {
+ if (tmpStream.read() == -1) {
break; // Exit the loop, no more data.
} else {
- pos++;
+ streamLength++;
}
}
}
+ tmpStream.close();
// Save for future uses.
- streamLength = pos;
- biStream.close();
- return pos;
+ return streamLength;
}
}
catch (Throwable t)
@@ -403,11 +438,10 @@
if (pushStack)
setupContextStack();
- setPosition(startPos-1);
+ setBlobPosition(startPos-1);
// read length bytes into a string
result = new byte[length];
- int n = InputStreamUtil.readLoop(biStream,result,0,length);
- pos += n;
+ int n = InputStreamUtil.readLoop(myStream,result,0,length);
/*
According to the spec, if there are only n < length bytes
to return, we should just return these bytes. Rather than
@@ -478,7 +512,9 @@
if (pushStack)
setupContextStack();
- ((Resetable)myStream).resetStream();
+ // Reset stream, because AutoPositionigStream wants to read
+ // the encoded length bytes.
+ myStream.resetStream();
return new UpdatableBlobStream (this,
new AutoPositioningStream (this, myStream, this));
}
@@ -533,33 +569,29 @@
if (pushStack)
setupContextStack();
- setPosition(start-1);
+ long pos = setBlobPosition(start -1);
// look for first character
int lookFor = pattern[0];
long curPos;
int c;
while (true)
{
- c = read();
+ c = read(pos++); // Note the position increment.
if (c == -1) // run out of stream
return -1;
if (c == lookFor)
{
curPos = pos;
- if (checkMatch(pattern))
+ if (checkMatch(pattern, pos))
return curPos;
else
- setPosition(curPos);
+ pos = setBlobPosition(curPos);
}
}
}
}
- catch (StandardException e)
- { // if this is a setPosition exception then not found
- if (e.getMessageId().equals(SQLState.BLOB_LENGTH_TOO_LONG))
- return -1;
- else
- throw handleMyExceptions(e);
+ catch (StandardException e) {
+ throw handleMyExceptions(e);
}
catch (Throwable t)
{
@@ -573,21 +605,24 @@
}
-
- /*
- check whether pattern (starting from the second byte) appears inside
- posStream (at the current position)
- @param posStream the stream to search inside
- @param pattern the byte array passed in by the user to search with
- @return true if match, false otherwise
+ /**
+ * Checks if the pattern (starting from the second byte) appears inside
+ * the Blob content.
+ * <p>
+ * At this point, the first byte of the pattern must already have been
+ * matched, and {@code pos} must be pointing at the second byte to compare.
+ *
+ * @param pattern the byte array to search for, passed in by the user
+ * @param pos the position in the Blob content to start searching from
+ * @return {@code true} if a match is found, {@code false} if not.
*/
- private boolean checkMatch(byte[] pattern)
- throws IOException, SQLException {
+ private boolean checkMatch(byte[] pattern, long pos)
+ throws IOException, StandardException {
// check whether rest matches
// might improve performance by reading more
for (int i = 1; i < pattern.length; i++)
{
- int b = read();
+ int b = read(pos++);
if ((b < 0) || (b != pattern[i])) // mismatch or stream runs out
return false;
}
@@ -628,7 +663,7 @@
if (pushStack)
setupContextStack();
- setPosition(start-1);
+ long pos = setBlobPosition(start-1);
// look for first character
byte[] b;
try
@@ -646,26 +681,22 @@
long curPos;
while (true)
{
- c = read();
+ c = read(pos++); // Note the position increment.
if (c == -1) // run out of stream
return -1;
if (c == lookFor)
{
curPos = pos;
- if (checkMatch(pattern))
+ if (checkMatch(pattern, pos))
return curPos;
else
- setPosition(curPos);
+ pos = setBlobPosition(curPos);
}
}
}
}
- catch (StandardException e)
- { // if this is a setPosition exception then not found
- if (e.getMessageId().equals(SQLState.BLOB_LENGTH_TOO_LONG))
- return -1;
- else
- throw handleMyExceptions(e);
+ catch (StandardException e) {
+ throw handleMyExceptions(e);
}
catch (Throwable t)
{
@@ -680,16 +711,16 @@
}
- /*
- check whether pattern (starting from the second byte) appears inside
- posStream (at the current position)
- @param posStream the stream to search inside
- @param pattern the blob passed in by the user to search with
- @return true if match, false otherwise
+ /**
+ * Checks if the pattern (starting from the second byte) appears inside
+ * the Blob content.
+ *
+ * @param pattern the Blob to search for, passed in by the user
+ * @param pos the position in the Blob (this) content to start searching
+ * @return {@code true} if a match is found, {@code false} if not.
*/
- private boolean checkMatch(Blob pattern)
- throws IOException, SQLException
- {
+ private boolean checkMatch(Blob pattern, long pos)
+ throws IOException, StandardException {
// check whether rest matches
// might improve performance by reading buffer at a time
InputStream pStream;
@@ -713,7 +744,7 @@
b1 = pStream.read();
if (b1 < 0) // search blob runs out
return true;
- int b2 = read();
+ int b2 = read(pos++);
if ((b1 != b2) || (b2 < 0)) // mismatch or stream runs out
return false;
}
@@ -744,7 +775,7 @@
protected void finalize()
{
if (!materialized)
- ((Resetable)myStream).closeStream();
+ myStream.closeStream();
}
/**
@@ -885,7 +916,7 @@
{
if (len > length())
throw Util.generateCsSQLException(
- SQLState.BLOB_LENGTH_TOO_LONG, new Long(pos));
+ SQLState.BLOB_LENGTH_TOO_LONG, new Long(len));
try {
if (materialized) {
control.truncate (len);
@@ -939,9 +970,10 @@
//if it is a stream then close it.
//if a array of bytes then initialize it to null
//to free up space
- if (!materialized)
- ((Resetable)myStream).closeStream();
- else {
+ if (!materialized) {
+ myStream.closeStream();
+ myStream = null;
+ } else {
try {
control.free ();
control = null;
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBInputStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBInputStream.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBInputStream.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBInputStream.java Tue Aug 5 10:11:32 2008
@@ -131,7 +131,7 @@
SQLState.BLOB_INVALID_OFFSET))) {
throw new ArrayIndexOutOfBoundsException(se.getMessage());
} else {
- throw new IOException(se.getMessage());
+ throw Util.newIOException(se);
}
}
}
@@ -173,7 +173,7 @@
pos += 1;
return ret;
} catch (StandardException se) {
- throw new IOException (se.getMessage());
+ throw Util.newIOException(se);
}
}
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBOutputStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBOutputStream.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBOutputStream.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBOutputStream.java Tue Aug 5 10:11:32 2008
@@ -68,7 +68,7 @@
try {
pos = control.write(b, pos);
} catch (StandardException se) {
- throw new IOException (se.getMessage());
+ throw Util.newIOException(se);
}
}
@@ -113,7 +113,7 @@
SQLState.BLOB_INVALID_OFFSET))) {
throw new ArrayIndexOutOfBoundsException(se.getMessage());
}
- throw new IOException (se.getMessage());
+ throw Util.newIOException(se);
}
}
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/LOBStreamControl.java Tue Aug 5 10:11:32 2008
@@ -114,9 +114,7 @@
throw (StandardException)e;
if (e instanceof IOException)
throw (IOException) e;
- IOException ioe = new IOException (e.getMessage());
- ioe.initCause (e);
- throw ioe;
+ throw Util.newIOException(e);
}
isBytes = false;
//now this call will write into the file
@@ -397,9 +395,7 @@
throw (IOException) e;
if (e instanceof RuntimeException)
throw (RuntimeException) e;
- IOException ioe = new IOException(e.getMessage());
- ioe.initCause(e);
- throw ioe;
+ throw Util.newIOException(e);
}
}
/**
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java Tue Aug 5 10:11:32 2008
@@ -142,9 +142,7 @@
try {
this.positionedIn.resetStream();
} catch (StandardException se) {
- IOException ioe = new IOException(se.getMessage());
- ioe.initCause(se);
- throw ioe;
+ throw Util.newIOException(se);
}
} else {
this.positionedIn = null;
@@ -567,10 +565,7 @@
parent.restoreContextStack();
}
} catch (SQLException sqle) {
- IOException ioe =
- new IOException(sqle.getSQLState() + ": " + sqle.getMessage());
- ioe.initCause(sqle);
- throw ioe;
+ throw Util.newIOException(sqle);
}
}
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UpdatableBlobStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UpdatableBlobStream.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UpdatableBlobStream.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/UpdatableBlobStream.java Tue Aug 5 10:11:32 2008
@@ -110,9 +110,7 @@
try {
stream = blob.getBinaryStream();
} catch (SQLException ex) {
- IOException ioe = new IOException (ex.getMessage());
- ioe.initCause (ex);
- throw ioe;
+ throw Util.newIOException(ex);
}
long leftToSkip = pos;
while (leftToSkip > 0) {
Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/Util.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/Util.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/Util.java (original)
+++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/Util.java Tue Aug 5 10:11:32 2008
@@ -282,6 +282,18 @@
}
/**
+ * Create an {@code IOException} that wraps another {@code Throwable}.
+ *
+ * @param cause the underlying cause of the error
+ * @return an {@code IOException} linked to {@code cause}
+ */
+ static IOException newIOException(Throwable cause) {
+ IOException ioe = new IOException(cause.getMessage());
+ ioe.initCause(cause);
+ return ioe;
+ }
+
+ /**
* this method is called to replace the exception factory to be
* used to generate the SQLException or the subclass
*/
Modified: db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java?rev=682803&r1=682802&r2=682803&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java (original)
+++ db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java Tue Aug 5 10:11:32 2008
@@ -21,6 +21,7 @@
import java.io.ByteArrayInputStream;
import java.io.CharArrayReader;
+import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
@@ -42,6 +43,7 @@
import junit.framework.*;
import java.sql.*;
+import org.apache.derbyTesting.functionTests.util.streams.ByteAlphabet;
import org.apache.derbyTesting.junit.TestConfiguration;
/**
@@ -1866,6 +1868,76 @@
}
/**
+ * Tests the {@code Blob.position} using a deterministic sequence of
+ * actions and arguments.
+ */
+ public void testPositionBlobDeterministic()
+ throws IOException, SQLException {
+ getConnection().setAutoCommit(false);
+ final int size = 100000;
+ PreparedStatement ps = prepareStatement(
+ "INSERT INTO testBlob (a, b) VALUES (?, ?)");
+ ps.setBinaryStream(1, new LoopingAlphabetStream(size), size);
+ ps.setInt(2, size);
+ ps.executeUpdate();
+ ps.close();
+ ps = prepareStatement("select a from testBlob where b = ?");
+ ps.setInt(1, size);
+ ResultSet rs = ps.executeQuery();
+ assertTrue("No data found", rs.next());
+ Blob blob = rs.getBlob(1);
+ // Try with a one-byte pattern.
+ byte[] pattern = new byte[] {(byte)'k'}; // k number 11 in the alphabet
+ assertEquals(11, blob.position(pattern, 1));
+ // Try with a non-existing pattern.
+ pattern = new byte[] {(byte)'p', (byte)'o'};
+ assertEquals(-1, blob.position(pattern, size / 3));
+
+ // Loop through all matches
+ pattern = new byte[] {(byte)'d', (byte)'e'};
+ long foundAtPos = 1;
+ int index = 0;
+ int stepSize = ByteAlphabet.modernLatinLowercase().byteCount();
+ while ((foundAtPos = blob.position(pattern, foundAtPos +1)) != -1) {
+ assertEquals((stepSize * index++) + 4, foundAtPos);
+ byte[] fetchedPattern = blob.getBytes(foundAtPos, pattern.length);
+ assertTrue(Arrays.equals(pattern, fetchedPattern));
+ }
+
+ // Try a longer pattern.
+ int pSize = 65*1024; // 65 KB
+ pattern = new byte[pSize];
+ assertEquals(pSize, new LoopingAlphabetStream(pSize).read(pattern));
+ assertEquals(1, blob.position(pattern, 1));
+ assertEquals(stepSize * 100 +1,
+ blob.position(pattern, stepSize * 99 + 7));
+ // Try again after getting the length.
+ assertEquals(size, blob.length());
+ assertEquals(stepSize * 100 +1,
+ blob.position(pattern, stepSize * 99 + 7));
+
+ // Try specifing a starting position that's too big.
+ try {
+ blob.position(pattern, size*2);
+ fail("Accepted position after end of Blob");
+ } catch (SQLException sqle) {
+ assertSQLState("XJ076", sqle);
+ }
+
+ // Fetch the last 5 bytes, try with a partial match at the end.
+ byte[] blobEnd = blob.getBytes(size - 4, 5);
+ pattern = new byte[6];
+ System.arraycopy(blobEnd, 0, pattern, 0, blobEnd.length);
+ pattern[5] = 'X'; // Only lowercase in the looping alphabet stream.
+ assertEquals(-1, blob.position(pattern, size - 10));
+
+ // Get the very last byte, try with a partial match at the end.
+ blobEnd = blob.getBytes(size, 1);
+ pattern = new byte[] {blobEnd[0], 'X'};
+ assertEquals(-1, blob.position(pattern, size - 5));
+ }
+
+ /**
* Test Blob.position() with blob argument
*/
public void testPositionBlob() throws Exception {