Author: kristwaa Date: Fri Oct 31 03:29:46 2008 New Revision: 709375 URL: http://svn.apache.org/viewvc?rev=709375&view=rev Log: DERBY-3793: Remove unnecessary methods from InternalClob interface. Backported revisions 678724 (1b) and 691608 (2b) to 10.4. Had to do one minor manual change, because TestConfiguration.setAutoCommit(boolean) doesn't exist in 10.4. Modified: 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/InternalClob.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/StoreStreamClob.java db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java db/derby/code/branches/10.4/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java 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=709375&r1=709374&r2=709375&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 Fri Oct 31 03:29:46 2008 @@ -114,7 +114,6 @@ InternalClob internalClob = clob.getInternalClob(); materialized = internalClob.isWritable(); if (materialized) { - long byteLength = internalClob.getByteLength(); this.stream = internalClob.getRawByteStream(); // Position the stream on pos using the init method. init ((LOBInputStream)stream, pos); Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/InternalClob.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/InternalClob.java?rev=709375&r1=709374&r2=709375&view=diff ============================================================================== --- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/InternalClob.java (original) +++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/InternalClob.java Fri Oct 31 03:29:46 2008 @@ -40,31 +40,6 @@ interface InternalClob { /** - * Gets the number of bytes contained in the Clob. - * - * @return Number of bytes in the Clob. - * @throws IOException if accessing underlying I/O resources fail - * @throws SQLException if accessing underlying resources fail - */ - long getByteLength() throws IOException, SQLException; - - /** - * Obtains the byte position for the given character position. - *
- * The range of valid character positions is
- * 1 - Clob.getCharLength() +1, inclusive. The upper bound is
- * used when appending to the Clob. Note that specifying a character
- * position that is more than one longer than the Clob raises an exception.
- *
- * @param charPos character position. The first position is 1.
- * @return A 0-based byte position.
- * @throws EOFException if the position is bigger than the Clob
- * @throws IOException if accessing the underlying I/O resources fail
- * @throws SQLException if the specified character position is invalid
- */
- long getBytePosition(long charPos) throws IOException, SQLException;
-
- /**
* Gets the number of characters in the Clob.
*
* @return Number of characters in the Clob.
@@ -81,10 +56,15 @@
* stream, it is up to the Clob representation which one it uses.
*
* This stream may be an internal store stream, and should not be directly - * published to the end user (returned through the JDBC API). There are two - * motivations for this; the stream may be closed by the end user when it is - * not supposed to, and operations on the stream might throw exceptions we - * do not want to present to the end user unwrapped. + * published to the end user (returned through the JDBC API). There are + * three reasons for this: + *
* The primary use of this method is to clone the Clob contents without * going via char (or String). Make sure the clone uses the same encoding 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=709375&r1=709374&r2=709375&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 Fri Oct 31 03:29:46 2008 @@ -357,8 +357,14 @@ /** * Copies bytes from stream to local storage. - * @param inStream - * @param length length to be copied + *
+ * Note that specifying the length as {@code Long.MAX_VALUE} results in + * reading data from the stream until EOF is reached, but no length checking + * will be performed. + * + * @param inStream the stream to copy from + * @param length number of bytes to be copied, or {@code Long.MAX_VALUE} to + * copy everything until EOF is reached * @throws IOException, StandardException */ synchronized void copyData(InputStream inStream, long length) @@ -368,12 +374,31 @@ while (sz < length) { int len = (int) Math.min (length - sz, bufferSize); len = inStream.read(data, 0, len); - if (len < 0) - throw new EOFException("Reached end-of-stream " + - "prematurely at " + sz); + if (len == -1) { + if (length != Long.MAX_VALUE) { + // We reached EOF before all the requested bytes are read. + throw new EOFException("Reached end-of-stream " + + "prematurely at " + sz + ", expected " + length); + } else { + // End of data, but no length checking. + break; + } + } write(data, 0, len, sz); sz += len; } + // If we copied until EOF, see if we have a Derby end-of-stream marker. + if (length == Long.MAX_VALUE) { + long curLength = getLength(); + byte[] eos = new byte[3]; + // Read the three last bytes, marker is 0xE0 0x00 0x00. + read(eos, 0, 3, curLength -3); + if ((eos[0] & 0xFF) == 0xE0 && (eos[1] & 0xFF) == 0x00 && + (eos[2] & 0xFF) == 0x00) { + // Remove Derby end-of-stream-marker. + truncate(curLength -3); + } + } } protected void finalize() throws Throwable { Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java?rev=709375&r1=709374&r2=709375&view=diff ============================================================================== --- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java (original) +++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java Fri Oct 31 03:29:46 2008 @@ -53,9 +53,6 @@ final class StoreStreamClob implements InternalClob { - /** Maximum value used when requesting bytes/chars to be skipped. */ - private static final long SKIP_BUFFER_SIZE = 8*1024; // 8 KB - /** Tells whether this Clob has been released or not. */ private volatile boolean released = false; @@ -113,45 +110,6 @@ } /** - * Returns the number of bytes in the Clob. - * - * @return The number of bytes in the Clob. - * @throws IOException if accessing the I/O resources fail - * @throws SQLException if accessing the store resources fail - */ - public long getByteLength() - throws IOException, SQLException { - checkIfValid(); - // Read through the whole stream to get the length. - long byteLength = 0; - try { - this.conChild.setupContextStack(); - this.positionedStoreStream.reposition(0L); - // See if length is encoded in the stream. - int us1 = this.positionedStoreStream.read(); - int us2 = this.positionedStoreStream.read(); - byteLength = (us1 << 8) + (us2 << 0); - if (byteLength == 0) { - while (true) { - long skipped = - this.positionedStoreStream.skip(SKIP_BUFFER_SIZE); - if (skipped <= 0) { - break; - } - byteLength += skipped; - } - // Subtract 3 bytes for the end-of-stream marker. - byteLength -= 3; - } - return byteLength; - } catch (StandardException se) { - throw Util.generateCsSQLException(se); - } finally { - this.conChild.restoreContextStack(); - } - } - - /** * Returns the number of characters in the Clob. * * @return Number of characters in the Clob. @@ -234,20 +192,6 @@ } /** - * Returns the byte position for the specified character position. - * - * @param charPos character position. First character is at position 1. - * @return Corresponding byte position. First byte is at position 0. - * @throws EOFException if the position is bigger then the Clob - * @throws IOException if accessing the underlying I/O resources fail - * @throws SQLException if accessing the underlying store resources fail - */ - public long getBytePosition(long charPos) - throws IOException, SQLException { - return UTF8Util.skipFully(getRawByteStream(), charPos -1); - } - - /** * Not supported. * * @see InternalClob#getWriter Modified: db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java?rev=709375&r1=709374&r2=709375&view=diff ============================================================================== --- db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java (original) +++ db/derby/code/branches/10.4/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java Fri Oct 31 03:29:46 2008 @@ -170,9 +170,9 @@ * the Clob length +1 * @throws IOException if accessing underlying I/O resources fail */ - public synchronized long getBytePosition (final long charPos) + //@GuardedBy(this) + private long getBytePosition (final long charPos) throws IOException { - checkIfValid(); long bytePos; if (charPos == this.posCache.getCharPos()) { // We already know the position. @@ -395,8 +395,8 @@ private void copyClobContent(InternalClob clob) throws IOException, SQLException { try { - long byteLength = clob.getByteLength(); - this.bytes.copyData(clob.getRawByteStream(), byteLength); + // Specify LONG.MAX_VALUE to copy data until EOF. + this.bytes.copyData(clob.getRawByteStream(), Long.MAX_VALUE); } catch (StandardException se) { throw Util.generateCsSQLException(se); } Modified: db/derby/code/branches/10.4/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java?rev=709375&r1=709374&r2=709375&view=diff ============================================================================== --- db/derby/code/branches/10.4/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java (original) +++ db/derby/code/branches/10.4/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java Fri Oct 31 03:29:46 2008 @@ -125,27 +125,6 @@ * UnsupportedOperationException is allowed for read-only Clobs. */ - public void testGetByteLengthAfterRelease() - throws IOException, SQLException { - iClob.release(); - try { - iClob.getByteLength(); - fail("Exception should have been raised, but was not"); - } catch (IllegalStateException ise) { - // This is as expected. - } - } - - public void testGetBytePositionAfterRelease() - throws IOException, SQLException { - iClob.release(); - try { - iClob.getBytePosition(1L); - fail("Exception should have been raised, but was not"); - } catch (IllegalStateException ise) { - // This is as expected. - } - } public void testGetCharLengthAfterRelease() throws IOException, SQLException { iClob.release(); @@ -230,53 +209,6 @@ /* End of XXXAfterRelease tests. */ - public void testGetByteLength() - throws IOException, SQLException { - assertEquals(this.initialByteLength, iClob.getByteLength()); - } - - public void testGetBytePosition_first() - throws IOException, SQLException { - assertEquals(0L, iClob.getBytePosition(1L)); - } - - public void testGetBytePosition_second() - throws IOException, SQLException { - assertEquals(bytesPerChar, iClob.getBytePosition(2L)); - } - - public void testGetBytePosition_last() - throws IOException, SQLException { - assertEquals(initialByteLength - bytesPerChar, - iClob.getBytePosition(this.initialCharLength)); - } - - public void testGetBytePosition_lastPlussOne() - throws IOException, SQLException { - assertEquals(initialByteLength, - iClob.getBytePosition(this.initialCharLength +1)); - } - - public void testGetBytePosition_lastPlussTwo() - throws IOException, SQLException { - try { - long pos = iClob.getBytePosition(this.initialCharLength +2); - fail("Length +2 should have no valid byte position, got " + pos); - } catch (EOFException ioe) { - // As expected for Derby. - } - } - - public void testGetBytePosition_lastPlussThousand() - throws IOException, SQLException { - try { - long pos = iClob.getBytePosition(this.initialCharLength +1000); - fail("Length +1000 should have no valid byte position, got " + pos); - } catch (EOFException ioe) { - // As expected for Derby. - } - } - public void testGetCharLength() throws IOException, SQLException { assertEquals(this.initialCharLength, iClob.getCharLength()); Modified: db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java?rev=709375&r1=709374&r2=709375&view=diff ============================================================================== --- db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java (original) +++ db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java Fri Oct 31 03:29:46 2008 @@ -35,6 +35,7 @@ import java.sql.Connection; import java.sql.Clob; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -204,6 +205,63 @@ newContent, this.clob.getSubString(1, newContent.length())); } + /** + * Tests that Derby specific end-of-stream markers aren't passed over to + * the temporary Clob, which doesn't use such markers. + *
+ * Passing the marker over will normally result in a UTF encoding exception. + *
+ * ID USAGE: reads id 2, writes id 10002 + */ + public void testInsertCharacter_ReadOnlyToTemporary() + throws IOException, SQLException { + getConnection().setAutoCommit(false); + // Insert data, a medium sized Clob to store it as a stream. + Statement stmt = createStatement(); + PreparedStatement ps = prepareStatement( + "insert into ClobTestData values (?,?)"); + int initalSize = 128*1024; + ps.setInt(1, 2); + ps.setCharacterStream( + 2, new LoopingAlphabetReader(initalSize), initalSize); + ps.executeUpdate(); + + // Select the Clob, and change one character. + PreparedStatement psSelect = prepareStatement( + "select dClob from ClobTestData where id = ?"); + psSelect.setInt(1, 2); + ResultSet lRs = psSelect.executeQuery(); + lRs.next(); + Clob lClob = lRs.getClob(1); + lClob.setString(1, "K"); + Reader r = lClob.getCharacterStream(); + assertEquals('K', r.read()); + long length = 1; + while (true) { + // Since we're skipping characters, the bytes have to be decoded + // and we will detect any encoding errors. + long skipped = r.skip(4096); + if (skipped > 0) { + length += skipped; + } else { + break; + } + } + lRs.close(); + assertEquals("Wrong length!", initalSize, length); + // Reports the correct length, now try to insert it. + ps.setInt(1, 10003); + ps.setClob(2, lClob); + ps.executeUpdate(); + // Fetch it back. + psSelect.setInt(1, 10003); + lRs = psSelect.executeQuery(); + lRs.next(); + Clob lClob2 = lRs.getClob(1); + assertEquals(lClob.getCharacterStream(), lClob2.getCharacterStream()); + assertEquals(initalSize, lClob2.length()); + } + public void testPositionWithString_ASCII_SimplePartialRecurringPattern() throws IOException, SQLException { String token = "xxSPOTxx"; @@ -289,7 +347,8 @@ // Obtain a Clob containing the empty string (""). Statement stmt = createStatement(); // Keep reference to the result set to be able to close it. - this.rs = stmt.executeQuery("select * from ClobTestData"); + this.rs = stmt.executeQuery( + "select dClob from ClobTestData where id = 1"); assertTrue(this.rs.next()); this.clob = this.rs.getClob(1); } @@ -441,8 +500,8 @@ Connection con = getConnection(); Statement stmt = con.createStatement(); stmt.execute("create table ClobTestData (" + - "dClob CLOB)"); - stmt.executeUpdate("insert into ClobTestData values ('')"); + "id int unique, dClob CLOB)"); + stmt.executeUpdate("insert into ClobTestData values (1, '')"); stmt.close(); }