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/10/14 16:17:12 UTC

svn commit: r704547 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/jdbc/ testing/org/apache/derby/impl/jdbc/

Author: kristwaa
Date: Tue Oct 14 07:17:11 2008
New Revision: 704547

URL: http://svn.apache.org/viewvc?rev=704547&view=rev
Log:
DERBY-3825: StoreStreamClob.getReader(charPos) performs poorly.
Added repositioning functionality to UTF8Reader - ordered after increasing cost:
 a) Reposition within current character buffer (small hops forwards and potentially backwards - in range 1 char to 8K chars)
 b) Forward stream from current position (hops forwards)
 c) Reset stream and skip data (hops backwards) 
In addition the new method getInternalReader was added to InternalClob. It takes advantage of the repositioning capability of UTF8Reader.
Clob.getSubString uses the new functionality when the Clob is represented by a StoreStreamClob.
Previously only mechanism c) was used.
Patch file: derby-3825-2b-internalReader_repositioning.diff

Added:
    db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/UTF8ReaderTest.java   (with props)
Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/InternalClob.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java
    db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/_Suite.java

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?rev=704547&r1=704546&r2=704547&view=diff
==============================================================================
--- 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 Tue Oct 14 07:17:11 2008
@@ -217,8 +217,14 @@
 
         String result;
         // An exception will be thrown if the position is larger than the Clob.
+        Reader reader;
         try {
-            Reader reader = this.clob.getReader(pos);
+            try {
+                reader = this.clob.getInternalReader(pos);
+            } catch (EOFException eofe) {
+                throw Util.generateCsSQLException(
+                        SQLState.BLOB_POSITION_TOO_LARGE, new Long(pos), eofe);
+            }
             char[] chars = new char[length];
             int charsRead = 0;
             // Read all the characters requested, or until EOF is reached.
@@ -236,9 +242,6 @@
             } 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);
         }
@@ -342,7 +345,7 @@
                 int matchCount = 0;
                 long pos = start;
                 long newStart = -1;
-                Reader reader = this.clob.getReader(start);
+                Reader reader = this.clob.getInternalReader(start);
                 char [] tmpClob = new char [4096];
                 boolean reset;
                 for (;;) {
@@ -381,7 +384,8 @@
                                 if (newStart < pos) {
                                     pos = newStart;
                                     reader.close();
-                                    reader = this.clob.getReader(newStart);
+                                    reader = this.clob.getInternalReader(
+                                                                    newStart);
                                     newStart = -1;
                                     reset = true;
                                     break;
@@ -398,6 +402,9 @@
                 }
 
             }
+        } catch (EOFException eofe) {
+            throw Util.generateCsSQLException(
+                                        SQLState.BLOB_POSITION_TOO_LARGE, eofe);
         } catch (IOException ioe) {
             throw Util.setStreamFailure(ioe);
         } finally {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/InternalClob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/InternalClob.java?rev=704547&r1=704546&r2=704547&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/InternalClob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/InternalClob.java Tue Oct 14 07:17:11 2008
@@ -91,6 +91,25 @@
     Reader getReader(long characterPosition) throws IOException, SQLException;
 
     /**
+     * Returns an internal reader for the Clob content, initialized at the
+     * specified character position.
+     * <p>
+     * This method can return a shared reader object, avoiding instantiation and
+     * repositioning costs for internal operations where the stream itself is
+     * not published to the end-user. One such example is
+     * {@code Clob.getSubString}.
+     *
+     * @param characterPosition character position. The first character is at
+     *      position {@code 1}.
+     * @return A {@code Reader} serving the content of the Clob.
+     * @throws EOFException if the position is larger then the Clob
+     * @throws IOException if accessing underlying I/O resources fail
+     * @throws SQLException if accessing underlying resources fail
+     */
+    Reader getInternalReader(long characterPosition)
+            throws IOException, SQLException;
+
+    /**
      * Returns a writer to write data into the Clob.
      * <p>
      * The semantics of the writer is the same as for {@link #insertString}.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java?rev=704547&r1=704546&r2=704547&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/StoreStreamClob.java Tue Oct 14 07:17:11 2008
@@ -24,6 +24,7 @@
 
 import java.io.BufferedInputStream;
 import java.io.EOFException;
+import java.io.FilterReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
@@ -68,7 +69,18 @@
     private final ConnectionChild conChild;
     /** Object used for synchronizing access to the store stream. */
     private final Object synchronizationObject;
-
+    /**
+     * Shared internal reader, closed when the Clob is released.
+     * This is a performance optimization, and the stream is shared between
+     * "one time" operations, for instance {@code getSubString} calls. Often a
+     * subset, or the whole, of the Clob is read subsequently and then this
+     * optimization avoids repositioning costs (the store does not support
+     * random access for LOBs).
+     * <b>NOTE</b>: Do not publish this reader to the end-user.
+     */
+    private UTF8Reader internalReader;
+    /** The internal reader wrapped so that it cannot be closed. */
+    private FilterReader unclosableInternalReader;
 
     /**
      * Creates a new Clob based on a stream from store.
@@ -104,6 +116,9 @@
      */
     public void release() {
         if (!released) {
+            if (this.internalReader != null) {
+                this.internalReader.close();
+            }
             this.positionedStoreStream.closeStream();
             this.released = true;
         }
@@ -192,6 +207,37 @@
     }
 
     /**
+     * Returns an internal reader for the Clob, initialized at the specified
+     * character position.
+     *
+     * @param characterPosition 1-based character position.
+     * @return A reader initialized at the specified position.
+     * @throws EOFException if the positions is larger than the Clob
+     * @throws IOException if accessing the I/O resources fail
+     * @throws SQLException if accessing the store resources fail
+     */
+    public Reader getInternalReader(long characterPosition)
+            throws IOException, SQLException {
+        if (this.internalReader == null) {
+            this.internalReader = new UTF8Reader(positionedStoreStream,
+                    TypeId.CLOB_MAXWIDTH, conChild, synchronizationObject);
+            this.unclosableInternalReader =
+                    new FilterReader(this.internalReader) {
+                        public void close() {
+                            // Do nothing.
+                            // Stream will be closed when the Clob is released.
+                        }
+                    };
+        }
+        try {
+            this.internalReader.reposition(characterPosition);
+        } catch (StandardException se) {
+            throw Util.generateCsSQLException(se);
+        }
+        return this.unclosableInternalReader;
+    }
+
+    /**
      * Not supported.
      *
      * @see InternalClob#getWriter

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java?rev=704547&r1=704546&r2=704547&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/TemporaryClob.java Tue Oct 14 07:17:11 2008
@@ -249,6 +249,15 @@
     }
 
     /**
+     * @see #getReader
+     */
+    public Reader getInternalReader(long characterPosition)
+            throws IOException, SQLException {
+        // TODO: See if we can optimize for a shared internal reader.
+        return getReader(characterPosition);
+    }
+
+    /**
      * Returns number of characters in the Clob.
      *
      * @return The length of the Clob in number of characters.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java?rev=704547&r1=704546&r2=704547&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java Tue Oct 14 07:17:11 2008
@@ -581,6 +581,69 @@
     }
 
     /**
+     * Resets the reader.
+     * <p>
+     * This method is used internally to achieve better performance.
+     * @see #reposition(long)
+     *
+     * @throws IOException if resetting or reading from the stream fails
+     * @throws StandardException if resetting the stream fails
+     */
+    private void resetUTF8Reader()
+            throws IOException, StandardException {
+        // 2L to skip the length encoding bytes.
+        this.positionedIn.reposition(2L);
+        this.rawStreamPos = this.positionedIn.getPosition();
+        this.in = this.positionedIn;
+        this.readerCharCount = this.utfCount = 0L;
+        this.charactersInBuffer = this.readPositionInBuffer = 0;
+    }
+
+    /**
+     * Repositions the stream so that the next character read will be the
+     * character at the requested position.
+     * <p>
+     * There are three types of repositioning, ordered after increasing cost:
+     * <ol> <li>Reposition within current character buffer (small hops forwards
+     *          and potentially backwards - in range 1 char to
+     *          {@code MAXIMUM_BUFFER_SIZE} chars)</li>
+     *      <li>Forward stream from current position (hops forwards)</li>
+     *      <li>Reset stream and skip data (hops backwards)</li>
+     * </ol>
+     *
+     * @param requestedCharPos 1-based requested character position
+     * @throws IOException if resetting or reading from the stream fails
+     * @throws StandardException if resetting the stream fails
+     */
+    void reposition(long requestedCharPos)
+            throws IOException, StandardException {
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(this.positionedIn != null);
+            SanityManager.ASSERT(requestedCharPos > 0);
+        }
+        // See if we can continue reading, or do nothing at all, to get to the
+        // right position.
+        if (requestedCharPos > readerCharCount) {
+            // The second part corrects for the internal buffer position.
+            long toSkip = (requestedCharPos - readerCharCount) +
+                    (charactersInBuffer - readPositionInBuffer) -1;
+            persistentSkip(toSkip);
+        } else {
+            // See if the requested position is within the current buffer.
+            long lowerBufferBorder = readerCharCount - charactersInBuffer;
+            if (requestedCharPos <= lowerBufferBorder) {
+                // Have to reset and start from scratch.
+                resetUTF8Reader();
+                persistentSkip(requestedCharPos -1);
+            } else {
+                // We have the requested position in the buffer already.
+                readPositionInBuffer =
+                        (int)(requestedCharPos - lowerBufferBorder -1);
+            }
+        }
+    }
+
+    /**
      * Decode the length encoded in the stream.
      * 
      * This method came from {@link java.io.DataInputStream}
@@ -619,4 +682,29 @@
         }
         return bufferSize;
     }
+
+    /**
+     * Skips the requested number of characters.
+     *
+     * @param toSkip number of characters to skip
+     * @throws EOFException if there are too few characters in the stream
+     * @throws IOException if reading from the stream fails
+     */
+    private final void persistentSkip(long toSkip)
+            throws IOException {
+        long remaining = toSkip;
+        while (remaining > 0) {
+            long skipped = skip(remaining);
+            if (skipped == 0) {
+                if (SanityManager.DEBUG) {
+                    // Add details to the exception in sane builds.
+                    throw new EOFException("Reached end-of-stream after " +
+                        readerCharCount + " characters, " + remaining +
+                        " remaining to skip");
+                }
+                throw new EOFException();
+            }
+            remaining -= skipped;
+        }
+    }
 }

Added: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/UTF8ReaderTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/UTF8ReaderTest.java?rev=704547&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/UTF8ReaderTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/UTF8ReaderTest.java Tue Oct 14 07:17:11 2008
@@ -0,0 +1,269 @@
+/*
+
+   Derby - Class org.apache.derby.impl.jdbc.UTF8ReaderTest
+
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+
+ */
+package org.apache.derby.impl.jdbc;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.Reader;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.types.DataValueDescriptor;
+import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetReader;
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
+
+/**
+ * Tests {@code UTF8Reader} using package-private classes/methods.
+ */
+public class UTF8ReaderTest
+    extends BaseJDBCTestCase {
+
+    public UTF8ReaderTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Tests simple repositioning.
+     */
+    public void testRepositioningSimple()
+            throws IOException, SQLException, StandardException {
+        setAutoCommit(false);
+        Statement stmt = createStatement();
+        ResultSet rs = stmt.executeQuery(
+                "select * from Utf8ReaderTest where id = 101");
+        rs.next();
+        final int size = rs.getInt(2);
+        DataValueDescriptor dvd = ((EmbedResultSet)rs).getColumn(3);
+        StoreStreamClob ssClob = new StoreStreamClob(
+                dvd.getStream(), (EmbedResultSet)rs);
+        Reader reader = ssClob.getInternalReader(1);
+        assertEquals('a', reader.read());
+        // Get internal readers and do stuff.
+        checkInternalStream(1, ssClob); // Get first character.
+        checkInternalStream(26, ssClob); // Skip forwards inside buffer.
+        checkInternalStream(17003, ssClob); // Skip forwards, refill buffer.
+        checkInternalStream(size, ssClob); // Skip until end.
+        assertEquals(-1, reader.read());
+        checkInternalStream(10, ssClob); // Rewind and refill buffer.
+        try {
+            checkInternalStream(size*2, ssClob); // Should fail, invalid pos.
+            fail("Should have failed due to invalid position");
+        } catch (EOFException eofe) {
+            // As expected, do nothing.
+        }
+    }
+
+    /**
+     * Tests repositioning withing the buffer.
+     */
+    public void testRepositioningWithinBuffer()
+            throws IOException, SQLException, StandardException {
+        setAutoCommit(false);
+        Statement stmt = createStatement();
+        ResultSet rs = stmt.executeQuery(
+                "select * from Utf8ReaderTest where id = 100");
+        rs.next();
+        DataValueDescriptor dvd = ((EmbedResultSet)rs).getColumn(3);
+        StoreStreamClob ssClob = new StoreStreamClob(
+                dvd.getStream(), (EmbedResultSet)rs);
+        Reader reader = ssClob.getInternalReader(1);
+        assertEquals('a', reader.read());
+        int bufSize = 26000;
+        char[] buf = new char[bufSize];
+        int count = 0;
+        while (count < bufSize) {
+            count += reader.read(buf, count, bufSize - count);
+        }
+        // We have now read 26001 chars. Next char should be 'b'.
+        // Internal buffer size after the singel read below should be:
+        // 26002 % 8192 = 1426
+        assertEquals('b', reader.read());
+        reader.close();
+        // Get internal readers and do stuff.
+        checkInternalStream(26002, ssClob);
+        checkInternalStream(26001, ssClob);
+        checkInternalStream(26002-1426+1, ssClob); // First char in buffer
+        checkInternalStream(26001+(8192-1426+1), ssClob); // Last char in buffer
+        checkInternalStream(26002-1426, ssClob); // Requires reset
+        checkInternalStream(26002-1426+1, ssClob); // Requires refilling buffer
+        checkInternalStream(26002, ssClob);
+        checkInternalStream(1, ssClob);
+    }
+
+    /**
+     * Tests repositioning withing buffer with a "real text" to make sure the
+     * correct values are returned.
+     */
+    public void testRepositioningWithinBufferRealText()
+            throws IOException, SQLException, StandardException {
+        setAutoCommit(false);
+        Statement stmt = createStatement();
+        ResultSet rs = stmt.executeQuery(
+                // See insertTestData
+                "select * from Utf8ReaderTest where id = 1");
+        rs.next();
+        DataValueDescriptor dvd = ((EmbedResultSet)rs).getColumn(3);
+        StoreStreamClob ssClob = new StoreStreamClob(
+                dvd.getStream(), (EmbedResultSet)rs);
+        Reader reader = ssClob.getInternalReader(1);
+        assertEquals('B', reader.read());
+        reader = ssClob.getInternalReader(24);
+        assertEquals('\'', reader.read());
+        reader = ssClob.getInternalReader(42);
+        assertEquals('H', reader.read());
+        reader = ssClob.getInternalReader(70);
+        assertEquals('M', reader.read());
+        reader = ssClob.getInternalReader(102);
+        assertEquals('M', reader.read());
+        reader = ssClob.getInternalReader(128);
+        assertEquals('B', reader.read());
+        reader = ssClob.getInternalReader(155);
+        assertEquals('A', reader.read());
+        reader = ssClob.getInternalReader(184);
+        assertEquals('S', reader.read());
+        reader = ssClob.getInternalReader(207);
+        assertEquals('H', reader.read());
+        reader = ssClob.getInternalReader(224);
+        assertEquals('O', reader.read());
+        reader = ssClob.getInternalReader(128);
+        char[] buf = new char[4];
+        assertEquals(4, reader.read(buf));
+        assertEquals("But ", new String(buf));
+        reader = ssClob.getInternalReader(70);
+        buf = new char[32];
+        assertEquals(32, reader.read(buf));
+        assertEquals("Men the grocer and butcher sent\n", new String(buf));
+    }
+
+    /**
+     * Makes sure the data returned from the internal Clob matches the data
+     * returned by a fresh looping alphabet stream.
+     *
+     * @param pos 1-based Clob position
+     * @param clob internal store stream Clob representation
+     */
+    private static void checkInternalStream(long pos, StoreStreamClob clob)
+            throws IOException, SQLException {
+        Reader canonStream = new LoopingAlphabetReader(pos + 100);
+        long toSkip = pos -1; // Convert to 0-based index.
+        while (toSkip > 0) {
+            long skipped = canonStream.skip(toSkip);
+            if (skipped > 0) {
+                toSkip -= skipped;
+            }
+        }
+        Reader clobStream = clob.getInternalReader(pos);
+        assertEquals("Data mismatch", canonStream.read(), clobStream.read());
+        clobStream.close();
+    }
+
+    /**
+     * Returns a simple test suite, using the embedded driver only.
+     *
+     * @return A test suite.
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite(UTF8ReaderTest.class);
+        return new CleanDatabaseTestSetup(suite) {
+            public void decorateSQL(Statement stmt)
+                    throws SQLException {
+                insertTestData(stmt);
+            }
+        };
+    }
+
+    /**
+     * Inserts data used by the tests.
+     * <p>
+     * Use the id to select a Clob with specific contents.
+     */
+    private static void insertTestData(Statement stmt)
+            throws SQLException {
+        int[][] sizes = new int[][] {
+                            {100, 1*1024*1024},        // 1M chars
+                            {101, 32*1024},            // 32K chars
+            };
+        stmt.executeUpdate(
+                "create table Utf8ReaderTest" +
+                "(id int primary key, size int, dClob clob)");
+        PreparedStatement ps = stmt.getConnection().prepareStatement(
+                "insert into Utf8ReaderTest values (?,?,?)");
+        for (int i=0; i < sizes.length; i++) {
+            ps.setInt(1, sizes[i][0]);
+            int size = sizes[i][1];
+            ps.setInt(2, size);
+            ps.setCharacterStream(3, new LoopingAlphabetReader(size), size);
+            ps.executeUpdate();
+        }
+        
+        // Insert some special pieces of text, repeat to get it represented as
+        // a stream.
+        ps.setInt(1, 1);
+        int size = aintWeGotFun.length();
+        ps.setInt(2, size);
+        StringBuffer str = new StringBuffer(32*1024 + aintWeGotFun.length());
+        while (str.length() < 32*1024) {
+            str.append(aintWeGotFun);
+        }
+        ps.setString(3, str.toString());
+        ps.executeUpdate();
+    }
+
+    /**
+     * Test data, first part of "Ain't We Got Fun?" (public domain).
+     * See http://en.wikipedia.org/wiki/Ain%27t_We_Got_Fun%3F
+     */
+    public static final String aintWeGotFun =
+            // 1-based positions for the first and the last character on line.
+            "Bill collectors gather\n" + // 1
+            "'Round and rather\n" + // 24
+            "Haunt the cottage next door\n" + // 42
+            "Men the grocer and butcher sent\n" + // 70
+            "Men who call for the rent\n" + // 102
+            "But with in a happy chappy\n" + // 128
+            "And his bride of only a year\n" + // 155
+            "Seem to be so cheerful\n" + // 184
+            "Here's an earful\n" + // 207
+            "Of the chatter you hear\n"; // 224
+
+    /*
+        // Code that can be used to check the positions in the text.
+        String[] firstWords = new String[] {"Bill", "'Round", "Haunt", "Men th",
+            "Men wh", "But", "And", "Seem", "Here's", "Of"};
+        for (int i=0; i < firstWords.length; i++) {
+            System.out.println("> " + firstWords[i]);
+            int clobPos = (int)clob.position(firstWords[i], 1);
+            int strPos = aintWeGotFun.indexOf(firstWords[i]);
+            System.out.println("\tClob: " + clobPos);
+            System.out.println("\tString: " + strPos);
+            assertTrue(clobPos == strPos +1);
+        }
+    */
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/UTF8ReaderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/_Suite.java?rev=704547&r1=704546&r2=704547&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/_Suite.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/_Suite.java Tue Oct 14 07:17:11 2008
@@ -46,6 +46,7 @@
         suite.addTest(BiggerTemporaryClobTest.suite());
         suite.addTest(SmallStoreStreamClobTest.suite());
         suite.addTest(BiggerStoreStreamClobTest.suite());
+        suite.addTest(UTF8ReaderTest.suite());
 
         return suite;
     }