Author: kristwaa
Date: Wed Jun 6 04:46:43 2007
New Revision: 544814
URL: http://svn.apache.org/viewvc?view=rev&rev=544814
Log:
DERBY-2646: Cleanup of Clob control/support structures. Added new versions of EmbedClob and ClobStreamControl. This commit enables the code committed earlier for this issue. This is the last major patch, and bugs/remaining work will be handled under separate Jiras.
Patch file: derby-2646-06b-embedclob_clobstreamcontrol.diff
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobStreamControl.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobStreamControl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobStreamControl.java?view=diff&rev=544814&r1=544813&r2=544814
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobStreamControl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobStreamControl.java Wed Jun 6 04:46:43 2007
@@ -23,21 +23,60 @@
package org.apache.derby.impl.jdbc;
import java.io.BufferedInputStream;
+import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
import java.io.Reader;
-import java.io.UTFDataFormatException;
import java.io.Writer;
import java.sql.SQLException;
import org.apache.derby.iapi.error.StandardException;
-import org.apache.derby.iapi.reference.SQLState;
-import org.apache.derby.iapi.util.ByteArray;
+import org.apache.derby.iapi.util.UTF8Util;
-final class ClobStreamControl extends LOBStreamControl {
+/**
+ * A Clob representation where the Clob is stored either in memory or on disk.
+ * <p>
+ * Character positions given as input to methods in this class are always
+ * 1-based. Byte positions are always 0-based.
+ */
+final class ClobStreamControl implements InternalClob {
+ /**
+ * Connection child assoicated with this Clob.
+ * <p>
+ * Currently only used for synchronization in *some* streams associated
+ * with the Clob. This suggests something is off wrt. synchronization.
+ */
private ConnectionChild conChild;
+ /** Underlying structure holding this Clobs raw bytes. */
+ //@GuardedBy("this")
+ private final LOBStreamControl bytes;
+ /** Tells whether this Clob has been released or not. */
+ // GuardedBy("this")
+ private boolean released = false;
+
+ /** Simple one-entry cache for character-byte position. */
+ // @GuardedBy("this")
+ private final CharToBytePositionCache posCache =
+ new CharToBytePositionCache();
+
+ /**
+ * Clones the content of another internal Clob.
+ *
+ * @param dbName name of the assoicated database
+ * @param conChild assoiated connection child
+ * @param clob the Clob whose content to clone
+ * @return A read-write Clob.
+ * @throws IOException if accessing the I/O resources fail (read or write)
+ * @throws SQLException if accessing underlying resources fail
+ */
+ static InternalClob cloneClobContent(String dbName,
+ ConnectionChild conChild,
+ InternalClob clob)
+ throws IOException, SQLException {
+ ClobStreamControl newClob = new ClobStreamControl(dbName, conChild);
+ newClob.copyClobContent(clob);
+ return newClob;
+ }
/**
* Constructs a <code>ClobStreamControl</code> object used to perform
@@ -45,10 +84,44 @@
*
* @param dbName name of the database the CLOB value belongs to
* @param conChild connection object used to obtain synchronization object
+ * @throws NullPointerException if <code>conChild</code> is
+ * <code>null</code>
*/
ClobStreamControl (String dbName, ConnectionChild conChild) {
- super (dbName);
+ if (conChild == null) {
+ throw new NullPointerException("conChild cannot be <null>");
+ }
this.conChild = conChild;
+ this.bytes = new LOBStreamControl(dbName);
+ }
+
+ /**
+ * Releases this Clob by freeing assoicated resources.
+ *
+ * @throws IOException if accessing underlying I/O resources fail
+ */
+ public synchronized void release()
+ throws IOException {
+ if (!this.released) {
+ this.released = true;
+ this.bytes.free();
+ }
+ }
+
+ /**
+ * Returns a stream serving the raw bytes of this Clob.
+ * <p>
+ * The stream is managed by the underlying byte store, and can serve bytes
+ * both from memory and from a file on disk.
+ *
+ * @return A stream serving the raw bytes of the stream, initialized at
+ * byte position <code>0</code>.
+ * @throws IOException if obtaining the stream fails
+ */
+ public synchronized InputStream getRawByteStream()
+ throws IOException {
+ checkIfValid();
+ return this.bytes.getInputStream(0L);
}
/**
@@ -57,51 +130,35 @@
* See comments in SQLChar.readExternal for more notes on
* processing the UTF8 format.
*
- * @param startPos start position in number of bytes
* @param charPos character position
* @return Stream position in bytes for the given character position.
- * @throws IOException
+ * @throws EOFException if the character position specified is greater than
+ * the Clob length +1
+ * @throws IOException if accessing underlying I/O resources fail
*/
- synchronized long getStreamPosition (long startPos, long charPos) throws IOException {
- InputStream in = new BufferedInputStream (getInputStream (startPos));
- long charLength = 0;
- long streamLength = 0;
- //utf decoding routine
- while (charLength < charPos) {
- int c = in.read();
- if (c < 0)
- return -1;
- charLength ++;
- if ((c & 0x80) == 0x00) {
- //found char of one byte width
- streamLength++;
- }
- else if ((c & 0x60) == 0x40) // we know the top bit is set here
- {
- //found char of two byte width
- if (in.skip (1) != 1) {
- //no second and third byte present
- throw new UTFDataFormatException();
- }
- streamLength += 2;
- }
- else if ((c & 0x70) == 0x60) // we know the top bit is set here
- {
- //found char of three byte width
- if (in.skip (2) != 2) {
- //no second and third byte present
- throw new UTFDataFormatException();
- }
- streamLength += 3;
- }
- else
- {
- throw new UTFDataFormatException();
+ public synchronized long getBytePosition (final long charPos)
+ throws IOException {
+ checkIfValid();
+ long bytePos;
+ if (charPos == this.posCache.getCharPos()) {
+ // We already know the position.
+ bytePos = this.posCache.getBytePos();
+ } else {
+ long startingBytePosition = 0L; // Default to start at position 0.
+ long charsToSkip = charPos -1; // Subtract one to get number to skip.
+ if (charPos > this.posCache.getCharPos()) {
+ // Exploit the last known character position.
+ startingBytePosition = this.posCache.getBytePos();
+ charsToSkip -= (this.posCache.getCharPos() -1);
}
+ InputStream utf8Bytes =
+ this.bytes.getInputStream(startingBytePosition);
+ bytePos = startingBytePosition +
+ UTF8Util.skipFully(new BufferedInputStream(utf8Bytes),
+ charsToSkip);
+ this.posCache.updateCachedPos(charPos, bytePos);
}
-
- in.close();
- return streamLength;
+ return bytePos;
}
/**
@@ -112,109 +169,158 @@
* @throws IOException
* @throws SQLException if the specified position is invalid
*/
- synchronized Writer getWriter (long pos) throws IOException, SQLException {
- long charPos = getStreamPosition (0, pos);
- if (charPos == -1)
- throw Util.generateCsSQLException (SQLState.BLOB_POSITION_TOO_LARGE,
- "" + (pos + 1));
- return new ClobUtf8Writer (this, getStreamPosition (0, charPos));
+ public synchronized Writer getWriter (long pos) throws IOException, SQLException {
+ checkIfValid();
+ // If pos is too large, an error will first be thrown when the writer
+ // is written to. Is this okay behavior, is does it break the spec?
+ if (pos < this.posCache.getCharPos()) {
+ this.posCache.reset();
+ }
+ return new ClobUtf8Writer (this, pos);
}
/**
* Constructs and returns a <code>Reader</code>.
* @param pos initial position of the returned <code>Reader</code> in
- * number of characters
+ * number of characters. Expected to be non-negative. The first
+ * character is at position <code>0</code>.
* @return A <code>Reader</code> with the underlying <code>CLOB</code>
* value as source.
* @throws IOException
- * @throws SQLException if the specified position is invalid
+ * @throws SQLException if the specified position is too big
*/
- Reader getReader (long pos) throws IOException, SQLException {
+ public synchronized Reader getReader (long pos)
+ throws IOException, SQLException {
+ checkIfValid();
+ if (pos < 1) {
+ throw new IllegalArgumentException(
+ "Position must be positive: " + pos);
+ }
Reader isr = new ClobUpdateableReader (
- (LOBInputStream) getInputStream (0), conChild);
+ (LOBInputStream) getRawByteStream(), conChild);
- long leftToSkip = pos;
+ long leftToSkip = pos -1;
+ long skipped;
while (leftToSkip > 0) {
- leftToSkip -= isr.skip (leftToSkip);
+ skipped = isr.skip(leftToSkip);
+ // Since Reader.skip block until some characters are available,
+ // a return value of 0 must mean EOF.
+ if (skipped <= 0) {
+ throw new EOFException("Reached end-of-stream prematurely");
+ }
+ leftToSkip -= skipped;
}
return isr;
}
/**
- * Returns a substring.
- * @param bIndex
- * @param eIndex
- * @return A substring of the <code>CLOB</code> value.
- * @throws IOException
- * @throws SQLException
+ * Returns number of characters in the Clob.
+ *
+ * @return The length of the Clob in number of characters.
+ * @throws IOException if accessing the underlying I/O resources fail
*/
- synchronized String getSubstring (long bIndex, long eIndex)
- throws IOException, SQLException {
- Reader r = getReader(bIndex);
- char [] buff = new char [(int) (eIndex - bIndex)];
- int length = 0;
- do {
- int ret = r.read (buff, length, (int) (eIndex - bIndex) - length);
- if (ret == -1 )
- break;
- length += ret;
- } while (length < eIndex - bIndex);
- return new String (buff, 0, length);
- }
-
- /**
- * returns number of charecter in the clob.
- * @return char length
- * @throws IOException, SQLException
- */
- synchronized long getCharLength () throws IOException, SQLException {
- Reader reader = getReader(0);
- char [] dummy = new char [4 * 1024];
- int length = 0;
- do {
- long ret = reader.read (dummy);
- if (ret == -1) break;
- length += ret;
- }while (true);
- return length;
+ public synchronized long getCharLength() throws IOException {
+ checkIfValid();
+ return
+ UTF8Util.skipUntilEOF(new BufferedInputStream(getRawByteStream()));
}
/**
* Returns the size of the Clob in bytes.
+ *
* @return Number of bytes in the <code>CLOB</code> value.
- * @throws IOException
+ * @throws IOException if accessing the underlying I/O resources fail
*/
- long getByteLength () throws IOException {
- return super.getLength();
+ public synchronized long getByteLength () throws IOException {
+ checkIfValid();
+ return this.bytes.getLength();
}
/**
- * inserts a string at a given postion.
- * @param str
- * @param pos byte postion
- * @return current byte postion
- * @throws IOException
- * @throws StandardException
- * @throws SQLException
+ * Inserts a string at the given position.
+ *
+ * @param str the string to insert
+ * @param insertionPoint the character position to insert the string at
+ * @return Number of characters inserted.
+ * @throws EOFException if the position is larger than the Clob length +1
+ * @throws IOException if accessing the underlying I/O resources fail
+ * @throws SQLException if accessing the underlying resources fail
*/
- synchronized long insertString (String str, long pos)
- throws IOException, SQLException, StandardException {
- int len = str.length();
- if (pos == super.getLength()) {
- byte b [] = getByteFromString (str);
- long l = write (b, 0, b.length, pos);
- return str.length();
- }
- long endPos = getStreamPosition (pos, len);
- endPos = (endPos < 0) ? getLength() : pos + endPos;
- replaceBytes (getByteFromString (str), pos, endPos);
+ public synchronized long insertString (String str, long insertionPoint)
+ throws IOException, SQLException {
+ checkIfValid();
+ if (insertionPoint < 1) {
+ throw new IllegalArgumentException(
+ "Position must be positive: " + insertionPoint);
+ }
+ long byteInsertionPoint = getBytePosition(insertionPoint);
+ long curByteLength = this.bytes.getLength();
+ byte[] newBytes = getByteFromString(str);
+ // See if we are appending or replacing bytes.
+ if (byteInsertionPoint == curByteLength) {
+ try {
+ this.bytes.write(newBytes, 0, newBytes.length,
+ byteInsertionPoint);
+ } catch (StandardException se) {
+ throw Util.generateCsSQLException(se);
+ }
+ } else {
+ // Calculate end position of the byte block to replace.
+ // Either we only replace bytes, or we replace and append bytes.
+ long endPos;
+ try {
+ endPos = getBytePosition(insertionPoint + str.length());
+ // Must reset the position cache here, as the last obtained
+ // one may be invalid after we replace the bytes (because of
+ // the variable number of bytes per char).
+ this.posCache.updateCachedPos(
+ insertionPoint, byteInsertionPoint);
+ } catch (EOFException eofe) {
+ endPos = curByteLength; // We replace and append.
+ }
+ try {
+ this.bytes.replaceBytes(newBytes, byteInsertionPoint, endPos);
+ } catch (StandardException se) {
+ throw Util.generateCsSQLException(se);
+ }
+ }
return str.length();
}
/**
- * Converts a string into utf8 byte array.
- * @param str
- * @return utf8 bytes array
+ * Tells if this Clob is intended to be writable.
+ *
+ * @return <code>true</code>
+ */
+ public boolean isWritable() {
+ return true;
+ }
+
+ /**
+ * Truncate the Clob to the specifiec size.
+ *
+ * @param newLength the new length, in characters, of the Clob
+ * @throws IOException if accessing the underlying I/O resources fails
+ */
+ public synchronized void truncate(long newLength)
+ throws IOException, SQLException {
+ checkIfValid();
+ try {
+ this.bytes.truncate(newLength);
+ if (newLength <= this.posCache.getCharPos()) {
+ // Reset the cache if last cached position has been cut away.
+ this.posCache.reset();
+ }
+ } catch (StandardException se) {
+ throw Util.generateCsSQLException(se);
+ }
+ }
+
+ /**
+ * Converts a string into the modified UTF-8 byte encoding.
+ *
+ * @param str string to represent with modified UTF-8 encoding
+ * @return Byte array representing the string in modified UTF-8 encoding.
*/
private byte[] getByteFromString (String str) {
//create a buffer with max size possible
@@ -240,4 +346,100 @@
System.arraycopy (buffer, 0, buff, 0, len);
return buff;
}
+
+ /**
+ * Copies the content of another Clob into this one.
+ *
+ * @param clob the Clob to copy from
+ * @throws IOException if accessing I/O resources fail (both read and write)
+ * @throws SQLException if accessing underlying resources fail
+ */
+ private void copyClobContent(InternalClob clob)
+ throws IOException, SQLException {
+ try {
+ this.bytes.copyData(clob.getRawByteStream(), clob.getByteLength());
+ } catch (StandardException se) {
+ throw Util.generateCsSQLException(se);
+ }
+ }
+
+ /**
+ * Makes sure the Clob has not been released.
+ * <p>
+ * All operations are invalid on a released Clob.
+ *
+ * @throws IllegalStateException if the Clob has been released
+ */
+ private final void checkIfValid() {
+ if (this.released) {
+ throw new IllegalStateException(
+ "The Clob has been released and is not valid");
+ }
+ }
+
+ /**
+ * A simple class to hold the byte position for a character position.
+ * <p>
+ * The implementation is very simple and is basically intended to speed up
+ * writing a sequence of consequtive characters one character at a time.
+ * Even though this should be avoided if possible, the penalty of updating a
+ * large Clob this way and finding the correct byte position by navigating
+ * from the start of the byte stream each time is so severe that a simple
+ * caching mechanism should be in place. Note that for other encodings than
+ * UTF-8, this might not be a problem if the mapping between character
+ * position and byte position is one-to-one.
+ * <p>
+ * Note that to ensure consistency between character and byte positions,
+ * access to this class must be synchronized externally to avoid caller 1
+ * getting the character position, then caller 2 updates the cached values
+ * and then caller 1 gets the updated byte position.
+ */
+ //@NotThreadSafe
+ private static class CharToBytePositionCache {
+ private long charPos = 1L;
+ private long bytePos = 0L;
+
+ CharToBytePositionCache() {}
+
+ /**
+ * Returns the last cached byte position.
+ *
+ * @return The byte position for the last cached character position.
+ */
+ long getBytePos() {
+ return this.bytePos;
+ }
+
+ /**
+ * Returns the last cached character position.
+ *
+ * @return The last cached character position.
+ */
+ long getCharPos() {
+ return this.charPos;
+ }
+
+ /**
+ * Updates the position cache.
+ *
+ * @param charPos the character position to cache the byte position for
+ * @param bytePos byte position for the specified character position
+ */
+ void updateCachedPos(long charPos, long bytePos) {
+ if (charPos -1 > bytePos) {
+ throw new IllegalArgumentException("(charPos -1) cannot be " +
+ "greater than bytePos; " + (charPos -1) + " > " + bytePos);
+ }
+ this.charPos = charPos;
+ this.bytePos = bytePos;
+ }
+
+ /**
+ * Resets the position cache.
+ */
+ void reset() {
+ this.charPos = 1L;
+ this.bytePos = 0L;
+ }
+ } // End internal class CharToBytePositionCache
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java?view=diff&rev=544814&r1=544813&r2=544814
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/ClobUtf8Writer.java Wed Jun 6 04:46:43 2007
@@ -36,7 +36,7 @@
*/
final class ClobUtf8Writer extends Writer {
private ClobStreamControl control;
- private long pos; // Position in bytes.
+ private long pos; // Position in characters.
private boolean closed;
/**
@@ -107,9 +107,6 @@
IOException ioe = new IOException (e.getMessage());
ioe.initCause (e);
throw ioe;
- }
- catch (StandardException se) {
- throw new IOException (se.getMessage());
}
}
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java?view=diff&rev=544814&r1=544813&r2=544814
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java Wed Jun 6 04:46:43 2007
@@ -30,12 +30,9 @@
import org.apache.derby.impl.jdbc.ConnectionChild;
import org.apache.derby.impl.jdbc.EmbedConnection;
import org.apache.derby.impl.jdbc.Util;
-import org.apache.derby.impl.jdbc.UTF8Reader;
import org.apache.derby.impl.jdbc.ReaderToAscii;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringReader;
import java.io.Reader;
import java.io.IOException;
import java.io.EOFException;
@@ -71,49 +68,40 @@
*/
final class EmbedClob extends ConnectionChild implements Clob
{
- // clob is either a string or stream
- private boolean materialized;
- private InputStream myStream;
- private ClobStreamControl control;
- //This boolean variable indicates whether the Clob object has
- //been invalidated by calling free() on it
+ /**
+ * The underlying Clob object, which may change depending on what the user
+ * does with the Clob.
+ */
+ private InternalClob clob;
+
+ /** Tells whether the Clob has been freed or not. */
private boolean isValid = true;
/**
- * This constructor is used to create a empty Clob object. It is used by the
- * Connection interface method createClob().
- *
- * @param clobString A String object containing the data to be stores in the
- * Clob.
+ * Creates an empty Clob object.
*
* @param con The Connection object associated with this EmbedClob object.
* @throws SQLException
*
*/
- EmbedClob(String clobString,EmbedConnection con) throws SQLException {
+ EmbedClob(EmbedConnection con) throws SQLException {
super(con);
- materialized = true;
- control = new ClobStreamControl (con.getDBName(), this);
- try {
- control.insertString (clobString, 0);
- }
- catch (IOException e) {
- throw Util.setStreamFailure (e);
- }
- catch (StandardException se) {
- throw Util.generateCsSQLException (se);
- }
+ this.clob = new ClobStreamControl (con.getDBName(), this);
}
/**
+ * Creates a Clob on top of a data value descriptor.
+ * <p>
* This constructor should only be called by {@link EmbedResultSet#getClob}.
+ * The data value descriptor may provide a <code>String</code> or a stream
+ * as the source of the Clob.
*
- * @param dvd
- * @param con
+ * @param dvd data value descriptor providing the Clob source
+ * @param con associated connection for the Clob
* @throws StandardException
*/
- protected EmbedClob(DataValueDescriptor dvd, EmbedConnection con)
+ protected EmbedClob(EmbedConnection con, DataValueDescriptor dvd)
throws StandardException
{
super(con);
@@ -122,14 +110,12 @@
if (SanityManager.DEBUG)
SanityManager.ASSERT(!dvd.isNull(), "clob is created on top of a null column");
- myStream = dvd.getStream();
- if (myStream == null)
- {
- control = new ClobStreamControl (con.getDBName(), this);
- materialized = true;
+ InputStream storeStream = dvd.getStream();
+ // See if a String or a stream will be the source of the Clob.
+ if (storeStream == null) {
+ this.clob = new ClobStreamControl(con.getDBName(), this);
try {
- String str = dvd.getString();
- control.insertString (dvd.getString(), 0);
+ this.clob.insertString (dvd.getString(), 1L);
}
catch (SQLException sqle) {
throw StandardException.newException (sqle.getSQLState(), sqle);
@@ -138,9 +124,7 @@
throw StandardException.newException (
SQLState.SET_STREAM_FAILURE, e);
}
- }
- else
- {
+ } else {
/*
We are expecting this stream to be a FormatIdInputStream with an
OverflowInputStream inside. FormatIdInputStream implements
@@ -155,102 +139,61 @@
should not break the ASSERT below.
*/
if (SanityManager.DEBUG)
- SanityManager.ASSERT(myStream instanceof Resetable);
+ SanityManager.ASSERT(storeStream instanceof Resetable);
try {
- ((Resetable) myStream).initStream();
+ ((Resetable) storeStream).initStream();
} catch (StandardException se) {
if (se.getMessageId().equals(SQLState.DATA_CONTAINER_CLOSED)) {
throw StandardException
.newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);
}
+ throw se;
}
+ this.clob = new StoreStreamClob(storeStream, this);
}
}
-
/**
- * Returns the number of characters
- * in the <code>CLOB</code> value
+ * Returns the number of characters in the <code>CLOB</code> value
* designated by this <code>Clob</code> object.
- * @return length of the <code>CLOB</code> in characters
- * @exception SQLException if there is an error accessing the
- * length of the <code>CLOB</code>
+ *
+ * @return The length of the <code>CLOB</code> in number of characters.
+ * @exception SQLException if obtaining the length fails
*/
public long length() throws SQLException
{
//call checkValidity to exit by throwing a SQLException if
//the Clob object has been freed by calling free() on it
checkValidity();
- // if we have a string, not a stream
try {
- if (materialized)
- return control.getCharLength ();
- }
- catch (IOException e) {
- throw Util.setStreamFailure (e);
- }
-
-
- Object synchronization = getConnectionSynchronization();
- synchronized (synchronization)
- {
- Reader clobReader = null;
- setupContextStack();
- try {
-
- clobReader = getCharacterStream();
- long clobLength = 0;
- for (;;)
- {
- long size = clobReader.skip(32 * 1024);
- if (size == 0L)
- break;
- clobLength += size;
- }
- clobReader.close();
- clobReader = null;
-
- return clobLength;
- }
- catch (Throwable t)
- {
- throw noStateChangeLOB(t);
- }
- finally
- {
- if (clobReader != null) {
- try {
- clobReader.close();
- } catch (IOException ioe) {
- }
- }
- restoreContextStack();
- }
+ return this.clob.getCharLength();
+ } catch (IOException e) {
+ throw Util.setStreamFailure(e);
}
}
/**
- * Returns a copy of the specified substring
- * in the <code>CLOB</code> value
+ * Returns a copy of the specified substring in the <code>CLOB</code> value
* designated by this <code>Clob</code> object.
- * The substring begins at position
- * <code>pos</code> and has up to <code>length</code> consecutive
- * characters. The starting position must be between 1 and the length
- * of the CLOB plus 1. This allows for zero-length CLOB values, from
- * which only zero-length substrings can be returned.
+ * <p>
+ * The substring begins at position <code>pos</code> and has up to
+ * * <code>length</code> consecutive characters. The starting position must be
+ * between 1 and the length of the CLOB plus 1. This allows for zero-length
+ * CLOB values, from which only zero-length substrings can be returned.
* If a larger length is requested than there are characters available,
* characters from the start position to the end of the CLOB are returned.
+ * <p>
+ * <em>NOTE</em>: If the starting position is the length of the CLOB plus 1,
+ * zero characters are returned regardless of the length requested.
+ *
* @param pos the first character of the substring to be extracted.
- * The first character is at position 1.
+ * The first character is at position 1.
* @param length the number of consecutive characters to be copied
* @return a <code>String</code> that is the specified substring in
- * the <code>CLOB</code> value designated by this <code>Clob</code> object
- * @exception SQLException if there is an error accessing the
- * <code>CLOB</code>
-
- * NOTE: If the starting position is the length of the CLOB plus 1,
- * zero characters are returned regardless of the length requested.
+ * the <code>CLOB</code> value designated by this <code>Clob</code> object
+ * @exception SQLException if there is an error accessing the
+ * <code>CLOB</code>
*/
public String getSubString(long pos, int length) throws SQLException
{
@@ -265,141 +208,68 @@
throw Util.generateCsSQLException(
SQLState.BLOB_NONPOSITIVE_LENGTH, new Integer(length));
- // if we have a string, not a stream
- if (materialized)
- {
- try {
- long sLength = control.getCharLength ();
- if (sLength + 1 < pos)
- throw Util.generateCsSQLException(
- SQLState.BLOB_POSITION_TOO_LARGE, new Long(pos));
- int endIndex = ((int) pos) + length - 1;
- // cannot go over length of string
- return control.getSubstring (pos - 1,
- (sLength > endIndex ? endIndex : sLength));
- }
- catch (IOException e) {
- throw Util.setStreamFailure (e);
- }
- }
-
- Object synchronization = getConnectionSynchronization();
- synchronized (synchronization)
- {
- setupContextStack();
-
- UTF8Reader clobReader = null;
- try {
-
- clobReader = getCharacterStreamAtPos(pos, synchronization);
- if (clobReader == null)
- throw StandardException.newException(SQLState.BLOB_POSITION_TOO_LARGE, new Long(pos));
-
- StringBuffer sb = new StringBuffer(length);
- int remainToRead = length;
- while (remainToRead > 0) {
-
- int read = clobReader.readInto(sb, remainToRead);
- if (read == -1)
- break;
-
- remainToRead -= read;
+ String result;
+ // An exception will be thrown if the position is larger than the Clob.
+ try {
+ Reader reader = this.clob.getReader(pos);
+ char[] chars = new char[length];
+ int charsRead = 0;
+ // Read all the characters requested, or until EOF is reached.
+ while (charsRead < length) {
+ int read = reader.read(chars, charsRead, length - charsRead);
+ if (read == -1) {
+ break;
}
- clobReader.close();
- clobReader = null;
-
- return sb.toString();
- }
- catch (Throwable t)
- {
- throw noStateChangeLOB(t);
+ charsRead += read;
}
- finally
- {
- if (clobReader != null)
- clobReader.close();
- restoreContextStack();
+ reader.close();
+ // If we have an empty Clob or requested length is zero, return "".
+ if (charsRead == 0) {
+ result = "";
+ } else {
+ result = String.copyValueOf(chars, 0, charsRead);
}
+ } catch (EOFException eofe) {
+ throw Util.generateCsSQLException(
+ SQLState.BLOB_POSITION_TOO_LARGE, eofe);
+ } catch (IOException ioe) {
+ throw Util.setStreamFailure(ioe);
}
+ return result;
}
/**
- * Gets the <code>Clob</code> contents as a Unicode stream.
- * @return a Unicode stream containing the <code>CLOB</code> data
+ * Gets the <code>Clob</code> contents as a stream of characters.
+ * @return A character stream containing the <code>CLOB</code> data.
* @exception SQLException if there is an error accessing the
- * <code>CLOB</code>
+ * <code>CLOB</code>
*/
public java.io.Reader getCharacterStream() throws SQLException
{
//call checkValidity to exit by throwing a SQLException if
//the Clob object has been freed by calling free() on it
checkValidity();
-
-
- Object synchronization = getConnectionSynchronization();
- synchronized (synchronization)
- {
- setupContextStack();
-
- try {
- if (materialized) {
- return control.getReader (0);
- }
-
- return getCharacterStreamAtPos(1, synchronization);
- }
- catch (Throwable t)
- {
- throw noStateChangeLOB(t);
- }
- finally
- {
- restoreContextStack();
- }
+ try {
+ return this.clob.getReader(1L);
+ } catch (IOException ioe) {
+ throw Util.setStreamFailure(ioe);
}
}
/**
* Gets the <code>CLOB</code> value designated by this <code>Clob</code>
* object as a stream of Ascii bytes.
- * @return an ascii stream containing the <code>CLOB</code> data
+ * @return An Ascii stream containing the <code>CLOB</code> data. Valid values
+ * in the stream are 0 - 255.
* @exception SQLException if there is an error accessing the
- * <code>CLOB</code> value
+ * <code>CLOB</code> value
*/
public java.io.InputStream getAsciiStream() throws SQLException
{
- //call checkValidity to exit by throwing a SQLException if
- //the Clob object has been freed by calling free() on it
- checkValidity();
+ // Validity is checked in getCharacterStream().
return new ReaderToAscii(getCharacterStream());
}
- private UTF8Reader getCharacterStreamAtPos(long position, Object synchronization)
- throws IOException, StandardException {
- UTF8Reader clobReader = null;
- if (materialized)
- clobReader = new UTF8Reader (control.getInputStream (0), 0,
- control.getByteLength(),
- this, control);
- else {
- ((Resetable)myStream).resetStream();
- clobReader = new UTF8Reader(myStream, 0, this, synchronization);
- }
-
- // skip to the correct position (pos is one based)
- long remainToSkip = position - 1;
- while (remainToSkip > 0) {
- long skipBy = clobReader.skip(remainToSkip);
- if (skipBy == 0L)
- return null;
-
- remainToSkip -= skipBy;
- }
-
- return clobReader;
- }
-
-
/**
* Determines the character position at which the specified substring
* <code>searchStr</code> appears in the <code>CLOB</code> value. The search
@@ -442,17 +312,18 @@
//call checkValidity to exit by throwing a SQLException if
//the Clob object has been freed by calling free() on it
checkValidity();
+ if (start < 1)
+ throw Util.generateCsSQLException(
+ SQLState.BLOB_BAD_POSITION, new Long(start));
+ if (searchStr == null)
+ throw Util.generateCsSQLException(
+ SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);
+ if (searchStr == "")
+ return start; // match DB2's SQL LOCATE function
boolean pushStack = false;
try
{
- if (start < 1)
- throw StandardException.newException(
- SQLState.BLOB_BAD_POSITION, new Long(start));
- if (searchStr == null)
- throw StandardException.newException(SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);
- if (searchStr == "")
- return start; // match DB2's SQL LOCATE function
Object synchronization = getConnectionSynchronization();
synchronized (synchronization)
@@ -461,9 +332,9 @@
if (pushStack)
setupContextStack();
int matchCount = 0;
- long pos = start - 1;
+ long pos = start;
long newStart = -1;
- Reader reader = getCharacterStreamAtPos (start, this);
+ Reader reader = this.clob.getReader(start);
char [] tmpClob = new char [4096];
boolean reset;
for (;;) {
@@ -471,25 +342,21 @@
int readCount = reader.read (tmpClob);
if (readCount == -1)
return -1;
- if (readCount == 0)
- continue;
for (int clobOffset = 0;
clobOffset < readCount; clobOffset++) {
- if (tmpClob [clobOffset]
- == searchStr.charAt (matchCount)) {
+ if (tmpClob[clobOffset]
+ == searchStr.charAt(matchCount)) {
//find the new starting position in
// case this match is unsuccessful
if (matchCount != 0 && newStart == -1
- && tmpClob [clobOffset]
- == searchStr.charAt (0)) {
+ && tmpClob[clobOffset]
+ == searchStr.charAt(0)) {
newStart = pos + clobOffset + 1;
}
matchCount ++;
if (matchCount == searchStr.length()) {
- //return after converting the position
- //to 1 based index
return pos + clobOffset
- - searchStr.length() + 1 + 1;
+ - searchStr.length() + 1;
}
}
else {
@@ -506,8 +373,7 @@
if (newStart < pos) {
pos = newStart;
reader.close();
- reader = getCharacterStreamAtPos
- (newStart + 1, this);
+ reader = this.clob.getReader(newStart);
newStart = -1;
reset = true;
break;
@@ -524,20 +390,15 @@
}
}
- }
- catch (Throwable t)
- {
- throw noStateChangeLOB(t);
- }
- finally
- {
- if (pushStack)
+ } catch (IOException ioe) {
+ throw Util.setStreamFailure(ioe);
+ } finally {
+ if (pushStack) {
restoreContextStack();
+ }
}
-
}
-
/**
* Determines the character position at which the specified
* <code>Clob</code> object <code>searchstr</code> appears in this
@@ -557,35 +418,26 @@
//call checkValidity to exit by throwing a SQLException if
//the Clob object has been freed by calling free() on it
checkValidity();
+ if (start < 1)
+ throw Util.generateCsSQLException(
+ SQLState.BLOB_BAD_POSITION, new Long(start));
+ if (searchClob == null)
+ throw Util.generateCsSQLException(
+ SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);
boolean pushStack = false;
try
{
- if (start < 1)
- throw StandardException.newException(
- SQLState.BLOB_BAD_POSITION, new Long(start));
- if (searchClob == null)
- throw StandardException.newException(SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);
-
synchronized (getConnectionSynchronization())
{
char[] subPatternChar = new char[1024];
boolean seenOneCharacter = false;
- //System.out.println("BEGIN CLOB SEARCH @ " + start);
-
restartScan:
for (;;) {
-
long firstPosition = -1;
-
Reader patternReader = searchClob.getCharacterStream();
-
- //System.out.println("RESTART CLOB SEARCH @ " + start);
-
- try {
-
for (;;) {
int read = patternReader.read(subPatternChar, 0, subPatternChar.length);
@@ -593,20 +445,15 @@
//empty pattern
if (!seenOneCharacter)
return start; // matches DB2 SQL LOCATE function
-
return firstPosition;
}
if (read == 0) {
- //System.out.println("STUCK IN READ 0 HELL");
continue;
}
-
seenOneCharacter = true;
String subPattern = new String(subPatternChar, 0, read);
- //System.out.println("START CLOB SEARCH @ " + start + " -- " + subPattern);
long position = position(subPattern, start);
- //System.out.println("DONE SUB CLOB SEARCH @ " + start + " -- " + position);
if (position == -1) {
// never seen any match
if (firstPosition == -1)
@@ -626,34 +473,16 @@
// read is the length of the subPattern string
start = position + read;
- }
- } finally {
- patternReader.close();
- }
- }
- }
- }
- catch (Throwable t)
- {
- throw noStateChangeLOB(t);
- }
- finally
- {
- if (pushStack)
+ } // End inner for loop
+ } // End outer for loop
+ } // End synchronized block
+ } catch (IOException ioe) {
+ throw Util.setStreamFailure(ioe);
+ } finally {
+ if (pushStack) {
restoreContextStack();
+ }
}
-
- }
-
-
- /*
- If we have a stream, release the resources associated with it.
- */
- protected void finalize()
- {
- // System.out.println("finalizer called");
- if (!materialized)
- ((Resetable)myStream).closeStream();
}
/**
@@ -699,24 +528,28 @@
* @exception SQLException Feature not implemented for now.
*/
public int setString(long pos, String str, int offset, int len)
- throws SQLException {
+ throws SQLException {
+ checkValidity();
+ if (pos < 1)
+ throw Util.generateCsSQLException(
+ SQLState.BLOB_BAD_POSITION, new Long(pos));
try {
- if (!materialized) {
- control.copyData(myStream, length());
- materialized = true;
- }
- long charPos = control.getStreamPosition(0, pos - 1);
- if (charPos == -1)
- throw Util.generateCsSQLException(
- SQLState.BLOB_POSITION_TOO_LARGE, "" + pos);
- return (int) control.insertString(str.substring (offset,
- (offset + len)), charPos);
+ if (!this.clob.isWritable()) {
+ makeWritableClobClone();
+ }
+ // Note that Clob.length() +1 is a valid position for setString.
+ // If the position is larger than this, an EOFException will be
+ // thrown. This is cheaper then getting the length up front.
+ this.clob.insertString(str.substring(offset, (offset + len)),
+ pos);
+ } catch (EOFException eofe) {
+ throw Util.generateCsSQLException(
+ SQLState.BLOB_POSITION_TOO_LARGE,
+ new Long(pos));
} catch (IOException e) {
throw Util.setStreamFailure(e);
}
- catch (StandardException se) {
- throw Util.generateCsSQLException (se);
- }
+ return str.length();
}
/**
@@ -730,8 +563,9 @@
* @exception SQLException Feature not implemented for now.
*/
public java.io.OutputStream setAsciiStream(long pos) throws SQLException {
+ checkValidity();
try {
- return new ClobAsciiStream (control.getWriter(pos - 1));
+ return new ClobAsciiStream (this.clob.getWriter(pos));
} catch (IOException e) {
throw Util.setStreamFailure(e);
}
@@ -748,16 +582,14 @@
* @exception SQLException Feature not implemented for now.
*/
public java.io.Writer setCharacterStream(long pos) throws SQLException {
+ checkValidity();
try {
- if (!materialized) {
- control.copyData(myStream, length());
- materialized = true;
+ if (!this.clob.isWritable()) {
+ makeWritableClobClone();
}
- return control.getWriter(pos - 1);
- } catch (IOException e) {
- throw Util.setStreamFailure(e);
- } catch (StandardException se) {
- throw Util.generateCsSQLException (se);
+ return this.clob.getWriter(pos);
+ } catch (IOException ioe) {
+ throw Util.setStreamFailure(ioe);
}
}
@@ -781,32 +613,25 @@
//
/////////////////////////////////////////////////////////////////////////
/**
- * This method frees the <code>Clob</code> object and releases the resources the resources
- * that it holds. The object is invalid once the <code>free</code> method
+ * Frees the <code>Clob</code> and releases the resources that it holds.
+ * <p>
+ * The object is invalid once the <code>free</code> method
* is called. If <code>free</code> is called multiple times, the
* subsequent calls to <code>free</code> are treated as a no-op.
*
- * @throws SQLException if an error occurs releasing
- * the Clob's resources
+ * @throws SQLException if an error occurs releasing the Clobs resources
*/
public void free()
throws SQLException {
- //calling free() on a already freed object is treated as a no-op
- if (!isValid) return;
-
- //now that free has been called the Clob object is no longer
- //valid
- isValid = false;
-
- if (!materialized) {
- ((Resetable)myStream).closeStream();
- }
- else {
+ if (this.isValid) {
+ this.isValid = false;
+ // Release and nullify the internal Clob.
try {
- control.free();
- }
- catch (IOException e) {
+ this.clob.release();
+ } catch (IOException e) {
throw Util.setStreamFailure(e);
+ } finally {
+ this.clob = null;
}
}
}
@@ -817,31 +642,35 @@
}
/*
- **
- */
-
- static SQLException noStateChangeLOB(Throwable t) {
- if (t instanceof StandardException)
- {
- // container closed means the blob or clob was accessed after commit
- if (((StandardException) t).getMessageId().equals(SQLState.DATA_CONTAINER_CLOSED))
- {
- t = StandardException.newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);
- }
- }
- return org.apache.derby.impl.jdbc.EmbedResultSet.noStateChangeException(t);
- }
-
- /*
- * Checks is isValid is true. If it is not true throws
- * a SQLException stating that a method has been called on
- * an invalid LOB object
+ * Checks if the Clob is valid.
+ * <p>
+ * A Clob is invalidated when {@link #free} is called or if the parent
+ * connection is closed.
*
- * throws SQLException if isValid is not true.
+ * @throws SQLException if the Clob is not valid
*/
private void checkValidity() throws SQLException{
if(!isValid)
throw newSQLException(SQLState.LOB_OBJECT_INVALID);
localConn.checkIfClosed();
+ }
+
+ /**
+ * Makes a writable clone of the current Clob.
+ * <p>
+ * This is called when we have a {@link StoreStreamClob} and the user calls
+ * a method updating the content of the Clob. A temporary Clob will then be
+ * created to hold the updated content.
+ *
+ * @throws IOException if accessing underlying I/O resources fail
+ * @throws SQLException if accessing underlying resources fail
+ */
+ private void makeWritableClobClone()
+ throws IOException, SQLException {
+ InternalClob toBeAbandoned = this.clob;
+ this.clob = ClobStreamControl.cloneClobContent(
+ getEmbedConnection().getDBName(),
+ this, toBeAbandoned);
+ toBeAbandoned.release();
}
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java?view=diff&rev=544814&r1=544813&r2=544814
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java Wed Jun 6 04:46:43 2007
@@ -2256,7 +2256,7 @@
*/
public Clob createClob() throws SQLException {
checkIfClosed();
- return new EmbedClob("", this);
+ return new EmbedClob(this);
}
/**
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java?view=diff&rev=544814&r1=544813&r2=544814
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java Wed Jun 6 04:46:43 2007
@@ -4062,7 +4062,7 @@
if (pushStack)
setupContextStack();
- return new EmbedClob(dvd, getEmbedConnection());
+ return new EmbedClob(getEmbedConnection(), dvd);
} catch (Throwable t) {
throw handleException(t);
} finally {
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java?view=diff&rev=544814&r1=544813&r2=544814
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java Wed Jun 6 04:46:43 2007
@@ -128,10 +128,7 @@
private static final ExemptClobMD [] emd = new ExemptClobMD [] {
new ExemptClobMD( "getCharacterStream", new Class[] { long.class, long.class } ,true,true),
- new ExemptClobMD( "setAsciiStream", new Class[] { long.class } ,false,true),
- new ExemptClobMD( "setCharacterStream", new Class[] { long.class } ,true,true),
new ExemptClobMD( "setString", new Class[] { long.class, String.class } ,false,true),
- new ExemptClobMD( "setString", new Class[] { long.class, String.class, int.class, int.class},false,true),
new ExemptClobMD( "truncate", new Class[] { long.class },false,true),
new ExemptClobMD( "free", null,true,true)
};
@@ -201,7 +198,7 @@
*
*/
public void testFreeandMethodsAfterCallingFree()
- throws SQLException {
+ throws IllegalAccessException, InvocationTargetException, SQLException {
InputStream asciiStream = clob.getAsciiStream();
Reader charStream = clob.getCharacterStream();
clob.free();
@@ -224,7 +221,8 @@
* get the list of methods present in the interface
* @param LOB an instance of the Clob interface implementation
*/
- void buildMethodList(Object LOB) {
+ void buildMethodList(Object LOB)
+ throws IllegalAccessException, InvocationTargetException {
//If the given method throws the correct exception
//set this to true and add it to the
boolean valid = true;
@@ -271,30 +269,27 @@
}
/**
- *Checks if the method throws a SQLFeatureNotSupportedException
- *@param m The method object that needs to be verified to see if it
- * is exempted
- *@return true if the given method does not throw the required SQLException
+ * Checks if the method is to be exempted from testing or not.
*
+ * @param m the method to check for exemption
+ * @return <code>false</code> if the method shall be tested,
+ * <code>true</code> if the method is exempted and shall not be tested.
*/
boolean checkIfExempted(Method m) {
ExemptClobMD md = excludedMethodSet.get(m);
-
- if(md != null && usingDerbyNetClient()) {
- if(md.getIfClientFramework())
- return true;
- else
- return false;
- }
- if(md != null && usingEmbedded()) {
- if(md.getIfEmbeddedFramework())
- return true;
- else
- return false;
+ boolean isExempted = false;
+ if (md != null) {
+ if (usingDerbyNetClient()) {
+ isExempted = md.getIfClientFramework();
+ } else if (usingEmbedded()) {
+ isExempted = md.getIfEmbeddedFramework();
+ } else {
+ fail("Unknown test environment/framework");
+ }
}
- return false;
+ return isExempted;
}
-
+
/*
* Checks if the invocation of the method throws a SQLExceptio
* as expected.
@@ -306,27 +301,20 @@
* LOB object
*
*/
- boolean checkIfMethodThrowsSQLException(Object LOB,Method method) {
+ boolean checkIfMethodThrowsSQLException(Object LOB,Method method)
+ throws IllegalAccessException, InvocationTargetException {
try {
method.invoke(LOB,getNullValues(method.getParameterTypes()));
- } catch(Throwable e) {
- if(e instanceof InvocationTargetException) {
- Throwable cause = e.getCause();
- if (cause instanceof SQLException ) {
- SQLException sqle = (SQLException)cause;
- if(sqle.getSQLState().equals("XJ215"))
- return true;
- else
- return false;
- } else {
- return false;
- }
-
+ } catch (InvocationTargetException ite) {
+ Throwable cause = ite.getCause();
+ if (cause instanceof SQLException ) {
+ return ((SQLException)cause).getSQLState().equals("XJ215");
}
+ throw ite;
}
return false;
}
-
+
/*
* Return a array of objects containing the default values for
* the objects passed in as parameters
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java?view=diff&rev=544814&r1=544813&r2=544814
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java Wed Jun 6 04:46:43 2007
@@ -200,16 +200,8 @@
assertEquals(1, this.clob.setString(9, "c"));
assertEquals(1, this.clob.setString(5, "a"));
assertEquals(1, this.clob.setString(6, "b"));
- if (BaseJDBCTestCase.usingEmbedded()) {
- assertEquals("Clob content is incorrect",
- newContent, this.clob.getSubString(1, newContent.length()));
- } else {
- // Client currently truncates the Clob when inserting strings.
- // See DERBY-1286 and DERBY-2652.
- assertEquals("Clob content is incorrect",
- newContent.substring(0, 6),
- this.clob.getSubString(1, newContent.length()));
- }
+ assertEquals("Clob content is incorrect",
+ newContent, this.clob.getSubString(1, newContent.length()));
}
public void testPositionWithString_ASCII_SimplePartialRecurringPattern()
@@ -244,7 +236,7 @@
final long prefix = 11L;
final long postfix = 90L;
char[] tmpChar = new char[1];
- LoopingAlphabetReader tokenSrc =
+ LoopingAlphabetReader tokenSrc =
new LoopingAlphabetReader(1L, CharAlphabet.cjkSubset());
tokenSrc.read(tmpChar);
String token = String.copyValueOf(tmpChar);
@@ -253,7 +245,7 @@
executeTestPositionWithStringToken(token, prefix);
}
- /* Test ideas
+ /* Test ideas for more tests
*
* truncate:
* truncate both on in store and from createClob
@@ -262,6 +254,11 @@
* truncate with too big size
* truncate to 0
* truncate to current length
+ *
+ * setString:
+ * test with null string
+ * test with offset out of range
+ * test with length of string to insert out of range
*/
/**
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java?view=diff&rev=544814&r1=544813&r2=544814
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/_Suite.java Wed Jun 6 04:46:43 2007
@@ -75,7 +75,8 @@
suite.addTest(SetTransactionIsolationTest.suite());
suite.addTest(AuthenticationTest.suite());
suite.addTest(DriverTest.suite());
-
+ suite.addTest(ClobTest.suite());
+
// Old harness .java tests that run using the HarnessJavaTest
// adapter and continue to use a single master file.
suite.addTest(JDBCHarnessJavaTest.suite());
|