Author: kristwaa Date: Tue Jun 5 04:08:37 2007 New Revision: 544445 URL: http://svn.apache.org/viewvc?view=rev&rev=544445 Log: DERBY-2646: Cleanup of Clob control/support structures. Added more tests. Patch file: derby-2646-05b-tests.diff Added: db/derby/code/trunk/java/testing/org/apache/derby/impl/ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerStoreStreamClobTest.java (with props) db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerTemporaryClobTest.java (with props) db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java (with props) db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallStoreStreamClobTest.java (with props) db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallTemporaryClobTest.java (with props) db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/_Suite.java (with props) db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java (with props) Added: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerStoreStreamClobTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerStoreStreamClobTest.java?view=auto&rev=544445 ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerStoreStreamClobTest.java (added) +++ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerStoreStreamClobTest.java Tue Jun 5 04:08:37 2007 @@ -0,0 +1,63 @@ +/* + + Derby - Class org.apache.derby.impl.jdbc.BiggerStoreStreamTest + + 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 junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Tests basic operations on a bigger read-only Clob from the store module. + */ +public class BiggerStoreStreamClobTest + extends InternalClobTest { + + private static final long CLOBLENGTH = 67*1024+19; // ~97 KB + private static final long BYTES_PER_CHAR = 1; // All modern Latin + + public BiggerStoreStreamClobTest(String name) { + super(name); + } + + public void setUp() + throws Exception { + super.initialCharLength = CLOBLENGTH; + super.initialByteLength = CLOBLENGTH; // The fake stream uses ascii. + super.bytesPerChar = BYTES_PER_CHAR; + EmbedStatement embStmt = (EmbedStatement)createStatement(); + iClob = new StoreStreamClob(new FakeStoreStream(CLOBLENGTH), embStmt); + assertEquals(CLOBLENGTH, iClob.getCharLength()); + } + + public void tearDown() + throws Exception { + this.iClob.release(); + this.iClob = null; + super.tearDown(); + } + + public static Test suite() { + TestSuite suite = new TestSuite(BiggerStoreStreamClobTest.class, + "BiggerStoreStreamClobTest suite"); + return suite; + } +} // End class BiggerStoreStreamClobTest Propchange: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerStoreStreamClobTest.java ------------------------------------------------------------------------------ svn:eol-style = native Added: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerTemporaryClobTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerTemporaryClobTest.java?view=auto&rev=544445 ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerTemporaryClobTest.java (added) +++ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerTemporaryClobTest.java Tue Jun 5 04:08:37 2007 @@ -0,0 +1,77 @@ +/* + + Derby - Class org.apache.derby.impl.jdbc.BiggerTemporaryClobTest + + 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 org.apache.derbyTesting.functionTests.util.streams.CharAlphabet; +import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetReader; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Test basic operations on a read-wrote Clob that is kept on disk. + */ +public class BiggerTemporaryClobTest + extends InternalClobTest { + + private static final long CLOBLENGTH = 287*1024-115; //~287 KB + private static final long BYTES_PER_CHAR = 3; // Only Tamil characters. + + public BiggerTemporaryClobTest(String name) { + super(name); + } + + /** + * Creates a bigger read-write Clob that is being kept on disk due to its + * size. + */ + public void setUp() + throws Exception { + super.initialCharLength = CLOBLENGTH; + super.initialByteLength = CLOBLENGTH *3; // Only Tamil characters. + super.bytesPerChar = BYTES_PER_CHAR; + EmbedStatement embStmt = (EmbedStatement)createStatement(); + EmbedConnection embCon =(EmbedConnection)getConnection(); + iClob = new ClobStreamControl(embCon.getDBName(), embStmt); + transferData( + new LoopingAlphabetReader(CLOBLENGTH, CharAlphabet.cjkSubset()), + iClob.getWriter(1L), + CLOBLENGTH); + assertEquals(CLOBLENGTH, iClob.getCharLength()); + } + + public void tearDown() + throws Exception { + this.iClob.release(); + this.iClob = null; + super.tearDown(); + } + + public static Test suite() + throws Exception { + Class theClass = BiggerTemporaryClobTest.class; + TestSuite suite = new TestSuite(theClass, "BiggerTemporaryClobTest suite"); + suite.addTest(addModifyingTests(theClass)); + return suite; + } +} // End class BiggerTemporaryClobTest Propchange: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/BiggerTemporaryClobTest.java ------------------------------------------------------------------------------ svn:eol-style = native Added: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java?view=auto&rev=544445 ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java (added) +++ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java Tue Jun 5 04:08:37 2007 @@ -0,0 +1,479 @@ +package org.apache.derby.impl.jdbc; + +import java.io.EOFException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.sql.Blob; +import java.util.ArrayList; +import java.util.List; +import org.apache.derby.iapi.error.StandardException; +import org.apache.derby.iapi.types.Resetable; +import org.apache.derbyTesting.functionTests.util.streams.ByteAlphabet; +import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetStream; +import org.apache.derbyTesting.junit.BaseJDBCTestCase; + +import java.io.IOException; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.InputStream; +import java.io.Reader; +import java.io.Writer; + +import java.sql.SQLException; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * A set of tests for the {@link org.apache.derby.impl.jdbc.InternalClob} + * interface. + *
+ * The tests are split into two categories; read-only and modifying tests. The + * latter should only be run if @{link InternalClob#isWritable} is true. + *
+ * Implementation notes: To implement a test by subclassing, a few + * things must be done. First of all, many of the tests require that the number + * of bytes per character is fixed. The following variables must be initialized + * by the subclass: + *
count characters long.
+ */
+ protected static String subString(InternalClob clob, long pos, int count)
+ throws IOException, SQLException {
+ Reader reader = clob.getReader(pos);
+ char[] sub = new char[count];
+ int offset = 0;
+ while (offset < count) {
+ long read = reader.read(sub, offset, count - offset);
+ if (read == -1) {
+ break;
+ }
+ offset += read;
+ }
+ return String.copyValueOf(sub);
+ }
+
+ /**
+ * Transfers data from the source to the destination.
+ */
+ public static long transferData(Reader src, Writer dest, long charsToCopy)
+ throws IOException {
+ BufferedReader in = new BufferedReader(src);
+ BufferedWriter out = new BufferedWriter(dest, BUFFER_SIZE);
+ char[] bridge = new char[BUFFER_SIZE];
+ long charsLeft = charsToCopy;
+ int read;
+ while ((read = in.read(bridge, 0, (int)Math.min(charsLeft, BUFFER_SIZE))) > 0) {
+ out.write(bridge, 0, read);
+ charsLeft -= read;
+ }
+ in.close();
+ // Don't close the stream, in case it will be written to again.
+ out.flush();
+ return charsToCopy - charsLeft;
+ }
+
+ /**
+ * Attemps to read the specified number of characters from the stream.
+ */
+ public static final long readFromStream(Reader in, long characterCount)
+ throws IOException {
+ char[] buf = new char[BUFFER_SIZE];
+ long leftToRead = characterCount;
+ while (leftToRead > 0) {
+ long read =
+ in.read(buf, 0,(int)Math.min(leftToRead, (long)BUFFER_SIZE));
+ if (read == 0) {
+ break;
+ }
+ leftToRead -= read;
+ }
+ return characterCount - leftToRead;
+ }
+
+ /**
+ * A fake store stream passed in to StoreStreamClob.
+ * + * Note that it is made such that init must be called before using the + * stream, or after close, or else a NPE will be thrown. + */ + static class FakeStoreStream + extends InputStream + implements Resetable { + + private static final ByteAlphabet ALPHABET = + ByteAlphabet.modernLatinLowercase(); + private LoopingAlphabetStream stream = null; + private final long length; + private int encodedLengthRemaining = 2; + private int eofMarkerRemaining = 3; + + public FakeStoreStream(long length) { + super(); + this.length = length; + } + + public int read(byte[] b, int off, int len) + throws IOException { + int count = 0; + while (count < len) { + int ret = read(); + if (ret == -1) { + if (count == 0) { + // Inform about EOF. + return -1; + } else { + // Return what we got. + break; + } + } + b[off+count++] = (byte)ret; + } + return count; + } + + public int read() throws IOException { + if (this.encodedLengthRemaining > 0) { + this.encodedLengthRemaining--; + return 0; + } + int b = this.stream.read(); + if (b == -1 && this.eofMarkerRemaining > 0) { + if (this.eofMarkerRemaining == 3) { + b = 0xe0; + } else { + b = 0x00; + } + this.eofMarkerRemaining--; + } + return b; + } + + public void resetStream() throws IOException, StandardException { + this.stream = new LoopingAlphabetStream(length, ALPHABET); + this.encodedLengthRemaining = 2; + this.eofMarkerRemaining = 3; + } + + public void initStream() throws StandardException { + this.stream = new LoopingAlphabetStream(length, ALPHABET); + this.encodedLengthRemaining = 2; + this.eofMarkerRemaining = 3; + } + + public void closeStream() { + this.stream = null; + } + + } // End private static class FakeStoreStream +} // End abstract class InternalClobTest Propchange: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/InternalClobTest.java ------------------------------------------------------------------------------ svn:eol-style = native Added: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallStoreStreamClobTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallStoreStreamClobTest.java?view=auto&rev=544445 ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallStoreStreamClobTest.java (added) +++ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallStoreStreamClobTest.java Tue Jun 5 04:08:37 2007 @@ -0,0 +1,63 @@ +/* + + Derby - Class org.apache.derby.impl.jdbc.SmallStoreStreamTest + + 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 junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Tests basic operations on a small read-only Clob from the store module. + */ +public class SmallStoreStreamClobTest + extends InternalClobTest { + + private static final long CLOBLENGTH = 1197; + private static final long BYTES_PER_CHAR = 1; // All modern Latin + + public SmallStoreStreamClobTest(String name) { + super(name); + } + + public void setUp() + throws Exception { + super.initialCharLength = CLOBLENGTH; + super.initialByteLength = CLOBLENGTH; // The fake stream uses ascii. + super.bytesPerChar = BYTES_PER_CHAR; + EmbedStatement embStmt = (EmbedStatement)createStatement(); + iClob = new StoreStreamClob(new FakeStoreStream(CLOBLENGTH), embStmt); + assertEquals(CLOBLENGTH, iClob.getCharLength()); + } + + public void tearDown() + throws Exception { + this.iClob.release(); + this.iClob = null; + super.tearDown(); + } + + public static Test suite() { + TestSuite suite = new TestSuite(SmallStoreStreamClobTest.class, + "SmallStoreStreamClobTest suite"); + return suite; + } +} // End class SmallStoreStreamClobTest Propchange: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallStoreStreamClobTest.java ------------------------------------------------------------------------------ svn:eol-style = native Added: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallTemporaryClobTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallTemporaryClobTest.java?view=auto&rev=544445 ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallTemporaryClobTest.java (added) +++ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallTemporaryClobTest.java Tue Jun 5 04:08:37 2007 @@ -0,0 +1,80 @@ +/* + + Derby - Class org.apache.derby.impl.jdbc.SmallTemporaryClobTest + + 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 org.apache.derbyTesting.functionTests.util.streams.CharAlphabet; +import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetReader; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Test basic operations on a small temporary Clob. + *
+ * The test is intended to use sizes that makes the Clob stay in memory (i.e. + * it is not being pushed to disk due to size). + */ +public class SmallTemporaryClobTest + extends InternalClobTest { + + private static final long CLOBLENGTH = 1027; + private static final long BYTES_PER_CHAR = 3; + + public SmallTemporaryClobTest(String name) { + super(name); + } + + /** + * Creates a small read-write Clob that is kept in memory. + */ + public void setUp() + throws Exception { + super.initialCharLength = CLOBLENGTH; + super.initialByteLength = CLOBLENGTH *3; // All tamil letters. + super.bytesPerChar = BYTES_PER_CHAR; + EmbedStatement embStmt = (EmbedStatement)createStatement(); + EmbedConnection embCon =(EmbedConnection)getConnection(); + iClob = new ClobStreamControl(embCon.getDBName(), embStmt); + transferData( + new LoopingAlphabetReader(CLOBLENGTH, CharAlphabet.tamil()), + iClob.getWriter(1L), + CLOBLENGTH); + assertEquals(CLOBLENGTH, iClob.getCharLength()); + } + + public void tearDown() + throws Exception { + this.iClob.release(); + this.iClob = null; + super.tearDown(); + } + + public static Test suite() + throws Exception { + Class theClass = SmallTemporaryClobTest.class; + TestSuite suite = new TestSuite(theClass, "SmallTemporaryClobTest suite"); + suite.addTest(addModifyingTests(theClass)); + return suite; + } + +} // End class SmallTemporaryClobTest Propchange: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/SmallTemporaryClobTest.java ------------------------------------------------------------------------------ svn:eol-style = native Added: 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?view=auto&rev=544445 ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/_Suite.java (added) +++ db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/_Suite.java Tue Jun 5 04:08:37 2007 @@ -0,0 +1,52 @@ +/* + + Derby - Class org.apache.derby.impl.jdbc._Suite + + 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 org.apache.derbyTesting.junit.BaseTestCase; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class _Suite + extends BaseTestCase { + + /** + * Use suite method instead. + */ + private _Suite(String name) { + super(name); + } + + public static Test suite() + throws Exception { + + TestSuite suite = new TestSuite("jdbc.impl package-private"); + + suite.addTest(SmallTemporaryClobTest.suite()); + suite.addTest(BiggerTemporaryClobTest.suite()); + suite.addTest(SmallStoreStreamClobTest.suite()); + suite.addTest(BiggerStoreStreamClobTest.suite()); + + return suite; + } +} // End class _Suite Propchange: db/derby/code/trunk/java/testing/org/apache/derby/impl/jdbc/_Suite.java ------------------------------------------------------------------------------ svn:eol-style = native Added: 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=auto&rev=544445 ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java (added) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java Tue Jun 5 04:08:37 2007 @@ -0,0 +1,461 @@ +/* + + Derby - Class org.apache.derbyTesting.functionTests.tests.jdbcapi.ClobTest + + 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.derbyTesting.functionTests.tests.jdbcapi; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +import java.sql.Connection; +import java.sql.Clob; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import junit.framework.Test; + +import org.apache.derbyTesting.functionTests.util.streams.CharAlphabet; +import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetReader; +import org.apache.derbyTesting.functionTests.util.streams.LoopingAlphabetStream; + +import org.apache.derbyTesting.junit.BaseJDBCTestCase; +import org.apache.derbyTesting.junit.BaseJDBCTestSetup; +import org.apache.derbyTesting.junit.TestConfiguration; + + + +/** + * Test the methods defined by the {@link java.sql.Clob} interface. + *
+ * Only methods defined by JDBC 3 or earlier are tested here, and the focus of + * the test is the interface methods. Less attention is given to inserting + * Clobs and fetching Clobs from the database. + */ +public class ClobTest + extends BaseJDBCTestCase { + + /** Buffer size to use when transferring data between streams. */ + private static final int TRANSFER_BUFFER_SIZE = 4*1024; // 4 KB + + /** Constant for Clob.setString method. */ + private static final int SET_STRING = 1; + /** Constant for Clob.setAsciiStream method. */ + private static final int SET_ASCII_STREAM = 2; + /** Constant for Clob.setCharacterStream method. */ + private static final int SET_CHARACTER_STREAM = 4; + + /** Test data, 18 characters long, containing only Norwegian letters. */ + private static final String NORWEGIAN_LETTERS = + "\u00e6\u00f8\u00e5\u00e6\u00f8\u00e5\u00e6\u00f8\u00e5" + + "\u00e6\u00f8\u00e5\u00e6\u00f8\u00e5\u00e6\u00f8\u00e5"; + + /** Result set used to obtain Clob. */ + private ResultSet rs = null; + /** + * The Clob used for testing. + * It is reinitialized to a Clob containing the empty string for each test. + */ + private Clob clob = null; + + public ClobTest(String testName) { + super(testName); + } + + public void testGetSubString_PosOneTooBig() + throws SQLException { + long length = this.clob.length(); + assertEquals("", this.clob.getSubString(length +1, 10)); + } + + public void testGetSubString_PosTooBig() { + try { + this.clob.getSubString(999, 10); + fail("getSubString with pos larger than clob length must fail"); + } catch (SQLException sqle) { + assertSQLState("XJ076", sqle); + } + } + + public void testGetSubString_PosNegative() + throws SQLException { + try { + this.clob.getSubString(-123, 10); + fail("getSubString with negative position should fail"); + } catch (SQLException sqle) { + assertSQLState("XJ070", sqle); + } + } + + public void testGetSubString_RequestZeroLength_PosValid() + throws SQLException { + // Tests if an exception is thrown or not. + // According to the JDBC spec, 0 is a valid length. + assertEquals("", this.clob.getSubString(1L, 0)); + } + + public void testGetSubString_RequestZeroLength_PosTooBig() + throws SQLException { + try { + this.clob.getSubString(999L, 0); + } catch (SQLException sqle) { + assertSQLState("XJ076", sqle); + } + } + + /** + * Tests if big strings can be handled. + *
+ * The motivation for the test is to make sure big buffers are filled with + * the call to read inside a loop. Big in this sense means bigger than some + * internal buffer. This is typically around 8 KB or so, but we try + * something considerably bigger. If a char/byte array is attempted filled + * with a single call to read, the resulting string wil typically contain + * \u0000 at positions after the size of the internal buffer. + */ + public void testGetSubString_BiggerThanInternalBuffer() + throws IOException, SQLException { + int stringLength = 1*1024*1024; // 1 M characters + transferData(new LoopingAlphabetReader(stringLength), + this.clob.setCharacterStream(1L), + TRANSFER_BUFFER_SIZE); + String obtained = this.clob.getSubString(1, stringLength); + assertEquals("Incorrect string length", + stringLength, obtained.length()); + // Obtain the string we inserted for comparison. + CharArrayWriter charWriter = new CharArrayWriter(); + transferData(new LoopingAlphabetReader(stringLength), charWriter, + TRANSFER_BUFFER_SIZE); + assertEquals("String do not match", + charWriter.toString(), obtained); + } + + public void testLengthOnEmptyClob() + throws SQLException { + assertEquals(0, this.clob.length()); + } + + public void testInsertStringOnEmptyClob_Singlebyte() + throws SQLException { + String content = "This is the new Clob content."; + this.clob.setString(1, content); + assertEquals("Incorrect length reported", + content.length(), this.clob.length()); + assertEquals("Clob content is incorrect", + content, this.clob.getSubString(1, content.length())); + } + + public void testInsertStringOnEmptyClob_Multibyte() + throws SQLException { + String content = "A few Norwegian letters: \u00e6, \u00e5, \u00f8."; + this.clob.setString(1, content); + assertEquals("Incorrect length reported", + content.length(), this.clob.length()); + assertEquals("Clob content is incorrect", + content, this.clob.getSubString(1, content.length())); + } + + public void testInsertStringInMiddle_Multibyte() + throws SQLException { + // Add some content to work on first. + this.clob.setString(1, NORWEGIAN_LETTERS); + assertEquals(NORWEGIAN_LETTERS, + this.clob.getSubString(1, NORWEGIAN_LETTERS.length())); + + // Replace a portion with single byte characters. + char[] modifiedContent = NORWEGIAN_LETTERS.toCharArray(); + // Replace chars at 0-based indexes 4,5 and 8 + modifiedContent[4] = 'a'; + modifiedContent[5] = 'b'; + modifiedContent[8] = 'c'; + String newContent = String.copyValueOf(modifiedContent); + // Do this in a "funny" order, or else it currently fails when running + // with the client driver. + 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())); + } + } + + public void testPositionWithString_ASCII_SimplePartialRecurringPattern() + throws IOException, SQLException { + String token = "xxSPOTxx"; + String inserted ="abcdexxSPxabcdexabxxSPxxxSPOTxabcxxSPOTxxabc"; + this.clob.setString(1L, inserted); + assertEquals("Invalid match position", + inserted.indexOf(token, 0) +1, this.clob.position(token, 1L)); + } + + public void testPositionWithString_USASCII() + throws IOException, SQLException { + String token = "xxSPOTxx"; + final long prefix = 91*1024 +7; + final long postfix = 12*1024; + insertDataWithToken(token, prefix, postfix, SET_ASCII_STREAM); + executeTestPositionWithStringToken(token, prefix); + } + + public void testPositionWithString_IOS88591() + throws IOException, SQLException { + String token = "xx\u00c6\u00c6\u00c6xx"; + final long prefix = 67*1024; + final long postfix = 1*1024-2; + insertDataWithToken(token, prefix, postfix, SET_ASCII_STREAM); + executeTestPositionWithStringToken(token, prefix); + } + + public void testPositionWithString_CJK() + throws IOException, SQLException { + final long prefix = 11L; + final long postfix = 90L; + char[] tmpChar = new char[1]; + LoopingAlphabetReader tokenSrc = + new LoopingAlphabetReader(1L, CharAlphabet.cjkSubset()); + tokenSrc.read(tmpChar); + String token = String.copyValueOf(tmpChar); + insertDataWithToken(token, prefix, postfix, SET_CHARACTER_STREAM); + //insertDataWithToken(token, prefix, 2*1024-7, SET_CHARACTER_STREAM); + executeTestPositionWithStringToken(token, prefix); + } + + /* Test ideas + * + * truncate: + * truncate both on in store and from createClob + * truncate multiple times, check length and compare content + * truncate with negative size + * truncate with too big size + * truncate to 0 + * truncate to current length + */ + + /** + * Insert text into a Clob using {@link java.sql.Clob#setAsciiStream} and + * then search for the specified token. + *
+ * Some data is inserted before and after the token, and the specified token + * is converted to bytes by using the ISO-8859-1 encoding. + * Note that ascii in JDBC is equivalent to ISO-8859-1, not US-ASCII. + */ + private void executeTestPositionWithStringToken(String token, long prefixLength) + throws IOException, SQLException { + + final long TOKEN_POS = prefixLength +1; + // Start searching behind the token. + assertEquals(-1, this.clob.position(token, TOKEN_POS+1)); + // Start searching exactly at the right position. + assertEquals(TOKEN_POS, this.clob.position(token, TOKEN_POS)); + // Start searching at the start of the Clob. + assertEquals(TOKEN_POS, this.clob.position(token, 1L)); + } + + /** + * Obtain a Clob containing the empty string. + */ + protected void setUp() + throws Exception { + // 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"); + assertTrue(this.rs.next()); + this.clob = this.rs.getClob(1); + } + + /** + * Nullify reference to Clob, close the parent result set. + */ + protected void tearDown() + throws Exception { + this.clob = null; + this.rs.close(); + super.tearDown(); + } + + public static Test suite() { + return new ClobTestSetup( + TestConfiguration.defaultSuite(ClobTest.class, false)); + } + + /** + * Transfer data from an input stream to an output stream. + * + * @param source source data + * @param dest destination to write to + * @param tz buffer size in number of bytes. Must be 1 or greater. + * @return Number of bytes read from the source data. This should equal the + * number of bytes written to the destination. + */ + private int transferData(InputStream source, OutputStream dest, int tz) + throws IOException { + if (tz < 1) { + throw new IllegalArgumentException( + "Buffer size must be 1 or greater: " + tz); + } + BufferedInputStream in = new BufferedInputStream(source); + BufferedOutputStream out = new BufferedOutputStream(dest, tz); + byte[] bridge = new byte[tz]; + int total = 0; + int read; + while ((read = in.read(bridge, 0, tz)) != -1) { + out.write(bridge, 0, read); + total += read; + } + in.close(); + // Don't close the stream, in case it will be written to again. + out.flush(); + return total; + } + + /** + * Transfer data from a source Reader to a destination Writer. + * + * @param source source data + * @param dest destination to write to + * @param tz buffer size in number of characters. Must be 1 or greater. + * @return Number of characters read from the source data. This should equal the + * number of characters written to the destination. + */ + private int transferData(Reader source, Writer dest, int tz) + throws IOException { + if (tz < 1) { + throw new IllegalArgumentException( + "Buffer size must be 1 or greater: " + tz); + } + BufferedReader in = new BufferedReader(source); + BufferedWriter out = new BufferedWriter(dest, tz); + char[] bridge = new char[tz]; + int total = 0; + int read; + while ((read = in.read(bridge, 0, tz)) != -1) { + out.write(bridge, 0, read); + total += read; + } + in.close(); + // Don't close the stream, in case it will be written to again. + out.flush(); + return total; + } + + private int transferData(Reader source, int tz) + throws IOException, SQLException { + if (tz < 1) { + throw new IllegalArgumentException( + "Buffer size must be 1 or greater: " + tz); + } + BufferedReader in = new BufferedReader(source); + char[] bridge = new char[tz]; + int total = 0; + int read; + while ((read = in.read(bridge, 0, tz)) != -1) { + this.clob.setString(total +1L, String.copyValueOf(bridge, 0, read)); + total += read; + } + in.close(); + return total; + } + + private void insertDataWithToken(String token, + long pre, long post, int mode) + throws IOException, SQLException { + int TRANSFER_BUFFER_SIZE = 4*1024; // Byte and char array size. + long total = 0; + switch (mode) { + case SET_STRING: { + Reader charIn = new LoopingAlphabetReader(pre); + total += transferData(charIn, TRANSFER_BUFFER_SIZE); + this.clob.setString(pre +1, token); + total += token.length(); + charIn = new LoopingAlphabetReader(post); + total += transferData(charIn, TRANSFER_BUFFER_SIZE); + break; + } case SET_ASCII_STREAM: { + OutputStream asciiOut = this.clob.setAsciiStream(1L); + InputStream asciiIn = new LoopingAlphabetStream(pre); + total += transferData(asciiIn, asciiOut, TRANSFER_BUFFER_SIZE); + byte[] tokenBytes = token.getBytes("ISO-8859-1"); + asciiOut.write(tokenBytes, 0, tokenBytes.length); + total += tokenBytes.length; + asciiIn = new LoopingAlphabetStream(post); + total += transferData(asciiIn, asciiOut, TRANSFER_BUFFER_SIZE); + break; + } case SET_CHARACTER_STREAM: { + Writer charOut = this.clob.setCharacterStream(1L); + Reader charIn = new LoopingAlphabetReader(pre); + total += transferData(charIn, charOut, TRANSFER_BUFFER_SIZE); + charOut.write(token); + total += token.length(); + charIn = new LoopingAlphabetReader(post); + total += transferData(charIn, charOut, TRANSFER_BUFFER_SIZE); + break; + } default: + throw new IllegalArgumentException( + "Unknown insertion mode: " + mode); + } + assertEquals("Invalid length after insertion", + pre + post + token.length(), this.clob.length()); + } + + /** + * Decorator creating the neccessary test data. + */ + private static class ClobTestSetup extends BaseJDBCTestSetup { + + ClobTestSetup(Test test) { + super(test); + } + + protected void setUp() throws SQLException { + Connection con = getConnection(); + Statement stmt = con.createStatement(); + stmt.execute("create table ClobTestData (" + + "dClob CLOB)"); + stmt.executeUpdate("insert into ClobTestData values ('')"); + stmt.close(); + } + + protected void tearDown() + throws Exception { + Connection con = getConnection(); + Statement stmt = con.createStatement(); + stmt.execute("drop table ClobTestData"); + stmt.close(); + super.tearDown(); + } + } // End inner class ClobTestSetup +} Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/ClobTest.java ------------------------------------------------------------------------------ svn:eol-style = native