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 2009/06/16 09:52:31 UTC

svn commit: r785104 - /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/LobSortTest.java

Author: kristwaa
Date: Tue Jun 16 07:52:30 2009
New Revision: 785104

URL: http://svn.apache.org/viewvc?rev=785104&view=rev
Log:
DERBY-4245: Sorting a table containing a CLOB fails after upgrade to 10.5.
A regression test using LOBs in a sort. The sort should be external, but if the
test is run with a large enough JVM heap it won't be. There are two options to
fix that: reduce the heap size or increase the number of rows in the test table.

Patch file: derby-4245-1c-test.diff


Added:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/LobSortTest.java   (with props)

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/LobSortTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/LobSortTest.java?rev=785104&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/LobSortTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/LobSortTest.java Tue Jun 16 07:52:30 2009
@@ -0,0 +1,270 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.tests.jdbc4.LobSortTest
+
+   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.jdbc4;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Random;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+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.CleanDatabaseTestSetup;
+
+/**
+ * Executes sorting of LOB values based on the length of the LOB or a random
+ * value. The intention is to test code determining the length of the LOBs and
+ * also the code materializing the LOB values. The tests don't verify that the
+ * sort order is actually correct. This test is a good candidate for being run
+ * with hard or soft upgraded databases.
+ * <p>
+ * Note that the seed used for the random number generator is included in the
+ * name of the test methods. Knowing the seed enables debugging by being able
+ * to rerun a specific test sequence that failed. The random number generator
+ * is only used during data insertion.
+ * <p>
+ * See DERBY-4245.
+ * <p>
+ * <em>NOTE</em>: This test is sensitive to the JVM heap size, which is one of
+ * the factors determining whether the sort is done internally or externally.
+ * The bug for a clean database would only occur with the external sort.
+ */
+public class LobSortTest
+        extends BaseJDBCTestCase {
+
+    /** The seed used for the random number generator. */
+    private static final long SEED = System.currentTimeMillis();
+
+    public LobSortTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Overridden naming method which includes the seed used for the random
+     * generator.
+     * <p>
+     * The seed is required if one wants to replay a specific sequence for
+     * debugging purposes.
+     *
+     * @return The name of the test.
+     */
+    public String getName() {
+        return (super.getName() + "-" + SEED);
+    }
+
+    public void testBlobMixed()
+            throws SQLException {
+        fetchIterateGetLengthBlob(
+                "select blen, b from MIXED_LOBS order by length(b)");
+    }
+
+    public void testBlobSmall()
+            throws SQLException {
+        fetchIterateGetLengthBlob("select blen, b from MIXED_LOBS " +
+                                  "where blen < 2000 order by length(b)");
+    }
+
+    public void testBlobLarge()
+            throws SQLException {
+        fetchIterateGetLengthBlob("select blen, b from MIXED_LOBS " +
+                    "where blen > 34000 order by length(b)");
+    }
+
+    public void testBlobClob()
+            throws SQLException {
+        fetchIterateGetLengthBlob(
+                "select blen, b from MIXED_LOBS order by length(c), length(b)");
+    }
+
+    public void testBlobRandom()
+            throws SQLException {
+        fetchIterateGetLengthBlob(
+                "select blen, b from MIXED_LOBS order by rnd");
+    }
+
+    public void testClobMixed()
+            throws SQLException {
+        fetchIterateGetLengthClob(
+                "select clen, c from MIXED_LOBS order by length(c)");
+    }
+
+    public void testClobSmall()
+            throws SQLException {
+        fetchIterateGetLengthClob("select clen, c from MIXED_LOBS " +
+                                  "where clen < 2000 order by length(c)");
+    }
+
+    public void testClobLarge()
+            throws SQLException {
+        fetchIterateGetLengthClob("select clen, c from MIXED_LOBS " +
+                    "where clen > 34000 order by length(c)");
+    }
+
+    public void testClobBlob()
+            throws SQLException {
+        fetchIterateGetLengthClob(
+                "select clen, c from MIXED_LOBS order by length(b), length(c)");
+    }
+
+    public void testClobRandom()
+            throws SQLException {
+        fetchIterateGetLengthClob(
+                "select clen, c from MIXED_LOBS order by rnd");
+    }
+
+    /**
+     * Executes the specified query two times, materializes the Blob on the
+     * first run and gets the length through {@code Blob.length} on the second.
+     * <p>
+     * Note that the query must select a Blob column at index one and the length
+     * at index two.
+     *
+     * @param sql query to execute
+     * @throws SQLException if the test fails for some reason
+     */
+    private void fetchIterateGetLengthBlob(String sql)
+            throws SQLException {
+        Statement stmt = createStatement();
+        ResultSet rs = stmt.executeQuery(sql);
+        // Materialize the BLOB value.
+        while (rs.next()) {
+            assertEquals(rs.getInt(1), rs.getBytes(2).length);
+        }
+        rs.close();
+        rs = stmt.executeQuery(sql);
+        // Get the BLOB value length though Blob.length
+        while (rs.next()) {
+            assertEquals(rs.getInt(1), (int)rs.getBlob(2).length());
+        }
+        rs.close();
+        stmt.close();
+    }
+
+    /**
+     * Executes the specified query two times, materializes the Clob on the
+     * first run and gets the length through {@code Clob.length} on the second.
+     * <p>
+     * Note that the query must select a Clob column at index one and the length
+     * at index two.
+     *
+     * @param sql query to execute
+     * @throws SQLException if the test fails for some reason
+     */
+    private void fetchIterateGetLengthClob(String sql)
+            throws SQLException {
+        Statement stmt = createStatement();
+        ResultSet rs = stmt.executeQuery(sql);
+        // Materialize the CLOB value.
+        while (rs.next()) {
+            assertEquals(rs.getInt(1), rs.getString(2).length());
+        }
+        rs.close();
+        rs = stmt.executeQuery(sql);
+        // Get the CLOB value length though Clob.length
+        while (rs.next()) {
+            assertEquals(rs.getInt(1), (int)rs.getClob(2).length());
+        }
+        rs.close();
+        stmt.close();
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite(LobSortTest.class,
+                                        "LobSortTestEmbedded");
+        return new CleanDatabaseTestSetup(suite) {
+            /**
+             * Generates a table with Blob and Clobs of mixed size.
+             */
+            protected void decorateSQL(Statement s)
+                    throws SQLException {
+                Random rnd = new Random(SEED);
+                Connection con = s.getConnection();
+                con.setAutoCommit(false);
+                s.executeUpdate("create table MIXED_LOBS (" +
+                        "c clob, clen int, b blob, blen int, rnd int)");
+                PreparedStatement ps = con.prepareStatement(
+                        "insert into MIXED_LOBS values (?,?,?,?,?)");
+                // Make sure we get at least one zero-length CLOB and BLOB.
+                ps.setString(1, "");
+                ps.setInt(2, 0);
+                ps.setBytes(3, new byte[0]);
+                ps.setInt(4, 0);
+                ps.setInt(5, rnd.nextInt());
+                ps.executeUpdate();
+                for (int i=0; i < 600; i++) {
+                    CharAlphabet ca = getCharAlphabet(1 + rnd.nextInt(3));
+                    int length = (int)(rnd.nextDouble() * 64.0 * 1024.0);
+                    if (rnd.nextInt(1000) < 500) {
+                        // Specify the length.
+                        ps.setCharacterStream( 1,
+                                new LoopingAlphabetReader(length, ca), length);
+                    } else {
+                        // Don't specify the length.
+                        ps.setCharacterStream(1,
+                                new LoopingAlphabetReader(length, ca));
+                    }
+                    ps.setInt(2, length);
+                    length = (int)(rnd.nextDouble() * 64.0 * 1024.0);
+                    if (rnd.nextInt(1000) < 500) {
+                        // Specify the length.
+                        ps.setBinaryStream(3,
+                                new LoopingAlphabetStream(length), length);
+                    } else {
+                        // Don't specify the length.
+                        ps.setBinaryStream(3,
+                                new LoopingAlphabetStream(length));
+                    }
+                    ps.setInt(4, length);
+                    ps.setInt(5, rnd.nextInt());
+                    ps.executeUpdate();
+                }
+                con.commit();
+                ps.close();
+            }
+
+            /**
+             * Returns a character alphabet.
+             */
+            private CharAlphabet getCharAlphabet(int i) {
+                switch (i) {
+                    case 1:
+                        return CharAlphabet.modernLatinLowercase();
+                    case 2:
+                        return CharAlphabet.tamil();
+                    case 3:
+                        return CharAlphabet.cjkSubset();
+                    default:
+                        fail("Unknown alphabet identifier: " + i);
+                }
+                // Will never be reached.
+                return null;
+            }
+        };
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/LobSortTest.java
------------------------------------------------------------------------------
    svn:eol-style = native