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 ma...@apache.org on 2012/05/11 08:03:18 UTC
svn commit: r1337032 - in /db/derby/code/branches/10.5: ./ java/
java/engine/org/apache/derby/iapi/sql/dictionary/
java/testing/org/apache/derbyTesting/functionTests/tests/lang/
java/testing/org/apache/derbyTesting/junit/
Author: mamta
Date: Fri May 11 06:03:18 2012
New Revision: 1337032
URL: http://svn.apache.org/viewvc?rev=1337032&view=rev
Log:
Backporting 2 jiras to 10.5
DERBY-5681 When a foreign key constraint on a table is dropped, the associated statistics row for the conglomerate is not removed
DERBY-4834 Add helper class for working with index statistics in JUnit tests
Added:
db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/IndexStatsUtil.java
- copied, changed from r1005347, db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/IndexStatsUtil.java
Modified:
db/derby/code/branches/10.5/ (props changed)
db/derby/code/branches/10.5/java/ (props changed)
db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/dictionary/ConglomerateDescriptor.java
db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdateStatisticsTest.java
db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/Utilities.java
Propchange: db/derby/code/branches/10.5/
------------------------------------------------------------------------------
Merged /db/derby/code/branches/10.7:r1336809
Merged /db/derby/code/trunk:r1005347,1031559,1041374,1042537,1329359
Propchange: db/derby/code/branches/10.5/java/
------------------------------------------------------------------------------
Merged /db/derby/code/branches/10.7/java:r1336809
Merged /db/derby/code/trunk/java:r1005347,1031559,1041374,1042537
Modified: db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/dictionary/ConglomerateDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/dictionary/ConglomerateDescriptor.java?rev=1337032&r1=1337031&r2=1337032&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/dictionary/ConglomerateDescriptor.java (original)
+++ db/derby/code/branches/10.5/java/engine/org/apache/derby/iapi/sql/dictionary/ConglomerateDescriptor.java Fri May 11 06:03:18 2012
@@ -474,11 +474,11 @@ public final class ConglomerateDescripto
physicalCD = null;
}
+ /* DERBY-5681 Drop statistics */
+ dd.dropStatisticsDescriptors(td.getUUID(), getUUID(), tc);
+
if (dropConglom)
{
- /* Drop statistics */
- dd.dropStatisticsDescriptors(td.getUUID(), getUUID(), tc);
-
/* Drop the physical conglomerate */
tc.dropConglomerate(getConglomerateNumber());
}
Modified: db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdateStatisticsTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdateStatisticsTest.java?rev=1337032&r1=1337031&r2=1337032&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdateStatisticsTest.java (original)
+++ db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UpdateStatisticsTest.java Fri May 11 06:03:18 2012
@@ -32,6 +32,7 @@ import org.apache.derbyTesting.junit.JDB
import org.apache.derbyTesting.junit.TestConfiguration;
import org.apache.derbyTesting.junit.RuntimeStatisticsParser;
import org.apache.derbyTesting.junit.SQLUtilities;
+import org.apache.derbyTesting.junit.IndexStatsUtil;
/**
* Tests for updating the statistics of one index or all the indexes on a
@@ -199,4 +200,121 @@ public class UpdateStatisticsTest extend
s.execute("drop table t");
commit();
}
+
+ /**
+ * Fixed DERBY-5681(When a foreign key constraint on a table is dropped,
+ * the associated statistics row for the conglomerate is not removed.)
+ * @throws Exception
+ */
+ public void testDERBY5681() throws Exception {
+ // Helper object to obtain information about index statistics.
+ IndexStatsUtil stats = new IndexStatsUtil(openDefaultConnection());
+ Statement s = createStatement();
+
+ //Test - primary key constraint
+ s.executeUpdate("CREATE TABLE TEST_TAB_1 (c11 int not null,"+
+ "c12 int not null, c13 int)");
+ stats.assertNoStatsTable("TEST_TAB_1");
+ //Insert data into table with no constraint and there will be no stat
+ // for that table at this point
+ s.executeUpdate("INSERT INTO TEST_TAB_1 VALUES(1,1,1),(2,2,2)");
+ s.execute("CALL SYSCS_UTIL.SYSCS_UPDATE_STATISTICS('APP','TEST_TAB_1', null)");
+ stats.assertNoStatsTable("TEST_TAB_1");
+ //Add primary key constraint to the table and now we should find a
+ // statistics row for it
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "ADD CONSTRAINT TEST_TAB_1_PK_1 "+
+ "PRIMARY KEY (c11)");
+ stats.assertTableStats("TEST_TAB_1",1);
+ //Dropping primary key constraint will drop the corresponding
+ // statistics
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "DROP CONSTRAINT TEST_TAB_1_PK_1");
+ stats.assertNoStatsTable("TEST_TAB_1");
+ s.execute("CALL SYSCS_UTIL.SYSCS_UPDATE_STATISTICS('APP','TEST_TAB_1', null)");
+ stats.assertNoStatsTable("TEST_TAB_1");
+ //Add the primary key constraint back since it will be used by the next
+ // test to create foreign key constraint
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "ADD CONSTRAINT TEST_TAB_1_PK_1 "+
+ "PRIMARY KEY (c11)");
+ //The statistics for primary key constraint has been added
+ stats.assertTableStats("TEST_TAB_1",1);
+
+ //Test - unique key constraint
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "ADD CONSTRAINT TEST_TAB_1_UNQ_1 "+
+ "UNIQUE (c12)");
+ stats.assertTableStats("TEST_TAB_1",2);
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "DROP CONSTRAINT TEST_TAB_1_UNQ_1");
+ stats.assertTableStats("TEST_TAB_1",1);
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "DROP CONSTRAINT TEST_TAB_1_PK_1");
+ stats.assertNoStatsTable("TEST_TAB_1");
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "ADD CONSTRAINT TEST_TAB_1_PK_1 "+
+ "PRIMARY KEY (c11)");
+ stats.assertTableStats("TEST_TAB_1",1);
+
+ //Test - unique key constraint on nullable column & non-nullable column
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "ADD CONSTRAINT TEST_TAB_1_UNQ_2 "+
+ "UNIQUE (c12, c13)");
+ stats.assertTableStats("TEST_TAB_1",3);
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "DROP CONSTRAINT TEST_TAB_1_UNQ_2");
+ stats.assertTableStats("TEST_TAB_1",1);
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "DROP CONSTRAINT TEST_TAB_1_PK_1");
+ stats.assertNoStatsTable("TEST_TAB_1");
+ s.executeUpdate("ALTER TABLE TEST_TAB_1 "+
+ "ADD CONSTRAINT TEST_TAB_1_PK_1 "+
+ "PRIMARY KEY (c11)");
+ stats.assertTableStats("TEST_TAB_1",1);
+
+ //Test - foreign key but no primary key constraint
+ s.executeUpdate("CREATE TABLE TEST_TAB_3 (c31 int not null)");
+ s.executeUpdate("INSERT INTO TEST_TAB_3 VALUES(1),(2)");
+ s.executeUpdate("ALTER TABLE TEST_TAB_3 "+
+ "ADD CONSTRAINT TEST_TAB_3_FK_1 "+
+ "FOREIGN KEY(c31) REFERENCES TEST_TAB_1(c11)");
+ stats.assertTableStats("TEST_TAB_3",1);
+ s.executeUpdate("ALTER TABLE TEST_TAB_3 "+
+ "DROP CONSTRAINT TEST_TAB_3_FK_1");
+ stats.assertNoStatsTable("TEST_TAB_3");
+
+ //Test - foreign key and primary key constraint
+ s.executeUpdate("CREATE TABLE TEST_TAB_2 (c21 int not null)");
+ s.executeUpdate("INSERT INTO TEST_TAB_2 VALUES(1),(2)");
+ s.executeUpdate("ALTER TABLE TEST_TAB_2 "+
+ "ADD CONSTRAINT TEST_TAB_2_PK_1 "+
+ "PRIMARY KEY (c21)");
+ stats.assertTableStats("TEST_TAB_2",1);
+ //Add a foreign key constraint and now we should find 2 rows of
+ // statistics for TEST_TAB_2 - 1 for primary key and other for
+ // foreign key constraint
+ s.executeUpdate("ALTER TABLE TEST_TAB_2 "+
+ "ADD CONSTRAINT TEST_TAB_2_FK_1 "+
+ "FOREIGN KEY(c21) REFERENCES TEST_TAB_1(c11)");
+ //Like primary key earlier, adding foreign key constraint didn't
+ // automatically add a statistics row for it. Have to run update
+ // statistics manually to get a row added for it's stat
+ stats.assertTableStats("TEST_TAB_2",1);
+ s.execute("CALL SYSCS_UTIL.SYSCS_UPDATE_STATISTICS('APP','TEST_TAB_2', null)");
+ stats.assertTableStats("TEST_TAB_2",2);
+ //Number of statistics row for TEST_TAB_1 will remain unchanged since
+ // it has only primary key defined on it
+ stats.assertTableStats("TEST_TAB_1",1);
+ s.executeUpdate("ALTER TABLE TEST_TAB_2 "+
+ "DROP CONSTRAINT TEST_TAB_2_FK_1");
+ //Dropping the foreign key constraint should remove one of the
+ // statistics row for TEST_TAB_2.
+ stats.assertTableStats("TEST_TAB_2",1);
+ s.execute("CALL SYSCS_UTIL.SYSCS_UPDATE_STATISTICS('APP','TEST_TAB_2', null)");
+ stats.assertTableStats("TEST_TAB_2",1);
+ s.execute("drop table TEST_TAB_2");
+ s.execute("drop table TEST_TAB_1");
+ stats.release();
+ }
}
Copied: db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/IndexStatsUtil.java (from r1005347, db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/IndexStatsUtil.java)
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/IndexStatsUtil.java?p2=db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/IndexStatsUtil.java&p1=db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/IndexStatsUtil.java&r1=1005347&r2=1337032&rev=1337032&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/IndexStatsUtil.java (original)
+++ db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/IndexStatsUtil.java Fri May 11 06:03:18 2012
@@ -38,10 +38,24 @@ import junit.framework.Assert;
* Helper class for obtaining index statistics and doing asserts on them.
* <p>
* This implementation assumes all tables/indexes belong to the current schema.
+ * <p>
+ * The <em>timeout</em> value is used to make the utility more resilient to
+ * differences in timing due to varying scheduling decisions, processor speeds,
+ * etc. If the system table contains the wrong number of statistics objects for
+ * the query, it will be queried repeatedly until the right number of statistics
+ * objects is obtained or the query times out.
*/
public class IndexStatsUtil {
+ private static final boolean INDEX = false;
+ private static final boolean TABLE = true;
+ private static final int NO_EXPECTATION = -1;
+ private static final String SEP =
+ BaseJDBCTestCase.getSystemProperty("line.separator");
+
private final Connection con;
+ /** Timeout in milliseconds. */
+ private final long timeout;
private PreparedStatement psGetTableId;
private PreparedStatement psGetStatsForTable;
private PreparedStatement psGetIndexId;
@@ -50,11 +64,39 @@ public class IndexStatsUtil {
private PreparedStatement psGetIdToNameMapConglom;
private PreparedStatement psGetIdToNameMapTable;
- public IndexStatsUtil(Connection con)
- throws SQLException {
+ /**
+ * Creates an instance querying the given database with no timeout set.
+ * <p>
+ * Querying with no timeout means that if there are too few or too many
+ * statistics objects matching the query, a failure will be raised
+ * immediately.
+ *
+ * @param con connection to the database to query
+ */
+ public IndexStatsUtil(Connection con) {
+ this(con, 0L);
+ }
+
+ /**
+ * Creates an instance querying the given database with the specified
+ * timeout value.
+ *
+ * @param con connection to the database to query
+ * @param timeout the longest time to wait to see if the expectations for a
+ * query are met (milliseconds)
+ */
+ public IndexStatsUtil(Connection con, long timeout) {
// Rely on auto-commit to release locks.
- Assert.assertTrue(con.getAutoCommit());
+ try {
+ Assert.assertTrue(con.getAutoCommit());
+ } catch (SQLException sqle) {
+ Assert.fail("Failed to get auto commit: " + sqle.getMessage());
+ }
+ if (timeout < 0) {
+ throw new IllegalArgumentException("timeout cannot be negative");
+ }
this.con = con;
+ this.timeout = timeout;
}
/**
@@ -68,6 +110,16 @@ public class IndexStatsUtil {
}
/**
+ * Asserts that there are no existing statistics for the specified table.
+ *
+ * @throws SQLException if obtaining the statistics fails
+ */
+ public void assertNoStatsTable(String table)
+ throws SQLException {
+ assertTableStats(table, 0);
+ }
+
+ /**
* Asserts that the expected number of statistics exists.
*
* @param expectedCount expected number of statistics
@@ -75,7 +127,11 @@ public class IndexStatsUtil {
*/
public void assertStats(int expectedCount)
throws SQLException {
- assertStatCount(getStats(), "<ALL>", expectedCount, false);
+ IdxStats[] ret = getStats();
+ if (ret.length != expectedCount) {
+ Assert.assertEquals(buildStatString(ret, "<ALL TABLES>"),
+ expectedCount, ret.length);
+ }
}
/**
@@ -88,7 +144,7 @@ public class IndexStatsUtil {
*/
public void assertTableStats(String table, int expectedCount)
throws SQLException {
- assertStatCount(getStatsTable(table), table, expectedCount, false);
+ getStatsTable(table, expectedCount);
}
/**
@@ -101,24 +157,7 @@ public class IndexStatsUtil {
*/
public void assertIndexStats(String index, int expectedCount)
throws SQLException {
- assertStatCount(getStatsIndex(index), index, expectedCount, true);
- }
-
- /**
- * Asserts that the expected number of statistics exists.
- *
- * @param stats statistics
- * @param conglom conglomerate name
- * @param expectedCount expected number of statistics
- * @param isIndex {@code true} if the conglomerate is an index
- */
- private void assertStatCount(IdxStats[] stats, String conglom,
- int expectedCount, boolean isIndex) {
- if (stats.length != expectedCount) {
- String name = (isIndex ? "index " : "table ") + "'" + conglom + "'";
- Assert.assertEquals(buildStatString(stats, name),
- expectedCount, stats.length);
- }
+ getStatsIndex(index, expectedCount);
}
/**
@@ -129,8 +168,6 @@ public class IndexStatsUtil {
* @return A string representation of the statistics.
*/
private String buildStatString(IdxStats[] stats, String name) {
- String SEP =
- BaseJDBCTestCase.getSystemProperty("line.separator");
StringBuffer sb = new StringBuffer(
"Index statistics for " + name + SEP);
for (int i=0; i < stats.length; i++) {
@@ -153,7 +190,8 @@ public class IndexStatsUtil {
throws SQLException {
if (psGetStats == null) {
psGetStats = con.prepareStatement(
- "select * from SYS.SYSSTATISTICS");
+ "select * from SYS.SYSSTATISTICS " +
+ "order by TABLEID, REFERENCEID, COLCOUNT");
}
return buildStatisticsList(psGetStats.executeQuery(), getIdToNameMap());
}
@@ -167,23 +205,40 @@ public class IndexStatsUtil {
*/
public IdxStats[] getStatsTable(String table)
throws SQLException {
+ return getStatsTable(table, NO_EXPECTATION);
+ }
+
+ /**
+ * Obtains statistics for the specified table, fails if the number of
+ * statistics objects isn't as expected within the timeout.
+ *
+ * @param table table name
+ * @param expectedCount number of expected statistics objects
+ * @return A list of statistics entries (possibly empty).
+ * @throws SQLException if obtaining the statistics fail
+ */
+ public IdxStats[] getStatsTable(String table, int expectedCount)
+ throws SQLException {
if (psGetTableId == null) {
psGetTableId = con.prepareStatement(
"select TABLEID from SYS.SYSTABLES where TABLENAME = ?");
}
- if (psGetStatsForTable == null) {
- psGetStatsForTable = con.prepareStatement(
- "select * from SYS.SYSSTATISTICS where TABLEID = ?");
- }
psGetTableId.setString(1, table);
ResultSet rs = psGetTableId.executeQuery();
Assert.assertTrue("No such table: " + table, rs.next());
String tableId = rs.getString(1);
Assert.assertFalse("More than one table named " + table, rs.next());
rs.close();
- psGetStatsForTable.setString(1, tableId);
- return buildStatisticsList(
- psGetStatsForTable.executeQuery(), getIdToNameMap());
+
+ IdxStats[] ret = querySystemTable(tableId, TABLE, expectedCount);
+ // Avoid building the stat string if not necessary.
+ if (expectedCount != NO_EXPECTATION && ret.length != expectedCount) {
+ Assert.assertEquals("failed to get statistics for table " + table +
+ " (#expected=" + expectedCount + ", timeout=" + timeout +
+ ")" + SEP + buildStatString(ret, table),
+ expectedCount, ret.length);
+ }
+ return ret;
}
/**
@@ -195,25 +250,93 @@ public class IndexStatsUtil {
*/
public IdxStats[] getStatsIndex(String index)
throws SQLException {
+ return getStatsIndex(index, NO_EXPECTATION);
+ }
+
+ /**
+ * Obtains statistics for the specified index, fails if the number of
+ * statistics objects isn't as expected within the timeout.
+ *
+ * @param index index name
+ * @param expectedCount number of expected statistics objects
+ * @return A list of statistics entries (possibly empty).
+ * @throws SQLException if obtaining the statistics fail
+ */
+ public IdxStats[] getStatsIndex(String index, int expectedCount)
+ throws SQLException {
if (psGetIndexId == null) {
psGetIndexId = con.prepareStatement(
"select CONGLOMERATEID from SYS.SYSCONGLOMERATES where " +
"CONGLOMERATENAME = ? and " +
"CAST(ISINDEX as VARCHAR(5)) = 'true'");
}
- if (psGetStatsForIndex == null) {
- psGetStatsForIndex = con.prepareStatement(
- "select * from SYS.SYSSTATISTICS where REFERENCEID = ?");
- }
psGetIndexId.setString(1, index);
ResultSet rs = psGetIndexId.executeQuery();
Assert.assertTrue("No such index: " + index, rs.next());
String indexId = rs.getString(1);
Assert.assertFalse("More than one index named " + index, rs.next());
rs.close();
- psGetStatsForIndex.setString(1, indexId);
- return buildStatisticsList(
- psGetStatsForIndex.executeQuery(), getIdToNameMap());
+
+ IdxStats[] ret = querySystemTable(indexId, INDEX, expectedCount);
+ // Avoid building the stat string if not necessary.
+ if (expectedCount != NO_EXPECTATION && ret.length != expectedCount) {
+ Assert.assertEquals("failed to get statistics for index " + index +
+ " (#expected=" + expectedCount + ", timeout=" + timeout +
+ ")" + SEP + buildStatString(ret, index),
+ expectedCount, ret.length);
+ }
+ return ret;
+ }
+
+ /**
+ * Queries the system table {@code SYS.SYSSTATISTICS} for statistics
+ * associated with a specific table or index.
+ *
+ * @param conglomId conglomerate id (UUID)
+ * @param isTable tells if the conglomerate is a table or an index
+ * @param expectedCount the number of statistics objects expected, use
+ * {@code NO_EXPECTATION} to return whatever matches the query
+ * immediately
+ */
+ private IdxStats[] querySystemTable(String conglomId, boolean isTable,
+ int expectedCount)
+ throws SQLException {
+ // Assign the correct prepared statement.
+ PreparedStatement ps;
+ if (isTable) {
+ if (psGetStatsForTable == null) {
+ psGetStatsForTable = con.prepareStatement(
+ "select * from SYS.SYSSTATISTICS " +
+ "where TABLEID = ? " +
+ "order by REFERENCEID, COLCOUNT");
+ }
+ ps = psGetStatsForTable;
+ } else {
+ if (psGetStatsForIndex == null) {
+ psGetStatsForIndex = con.prepareStatement(
+ "select * from SYS.SYSSTATISTICS " +
+ "where REFERENCEID = ? " +
+ "order by COLCOUNT");
+ }
+ ps = psGetStatsForIndex;
+ }
+ ps.setString(1, conglomId);
+
+ long started = System.currentTimeMillis();
+ long waited = -1;
+ IdxStats[] ret = null;
+ while (waited < timeout) {
+ // Don't wait the first time.
+ if (ret != null) {
+ Utilities.sleep(Math.min(250L, timeout - waited));
+ }
+ ret = buildStatisticsList(ps.executeQuery(), getIdToNameMap());
+ if (expectedCount == NO_EXPECTATION || ret.length == expectedCount){
+ break;
+ }
+ waited = System.currentTimeMillis() - started;
+ }
+ return ret;
}
/**
@@ -383,10 +506,34 @@ public class IndexStatsUtil {
sb.append("{tableId=").append(tableId).
append(", tableName=").append(tableName).
append(", indexName=").append(indexName).
+ append(", lcols=").append(lcols).
append(", rows=").append(rows).
append(", unique/card=").append(card).
append(", created=").append(created).append('}');
return sb.toString();
}
+
+ /**
+ * Equality is based on the statistics entry UUID.
+ *
+ * @param obj other object
+ * @return {@code true} if the other object is considered equal to this
+ */
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final IdxStats other = (IdxStats) obj;
+ return this.id.equals(other.id);
+ }
+
+ public int hashCode() {
+ int hash = 7;
+ hash = 17 * hash + this.id.hashCode();
+ return hash;
+ }
}
}
Modified: db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/Utilities.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/Utilities.java?rev=1337032&r1=1337031&r2=1337032&view=diff
==============================================================================
--- db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/Utilities.java (original)
+++ db/derby/code/branches/10.5/java/testing/org/apache/derbyTesting/junit/Utilities.java Fri May 11 06:03:18 2012
@@ -1,6 +1,6 @@
/*
*
- * Derby - Class Utilities
+ * Derby - Class org.apache.derbyTesting.junit.Utilities
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -22,142 +22,130 @@ package org.apache.derbyTesting.junit;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
+import java.util.Arrays;
import java.util.StringTokenizer;
+import junit.framework.Assert;
/**
- * General non-JDBC related utilities relocated from TestUtil
- *
- *
+ * General non-JDBC related utilities.
+ * Some of these were relocated from TestUtil.
*/
public class Utilities {
- public Utilities() {
- // TODO Auto-generated constructor stub
- }
- /**
- * Just converts a string to a hex literal to assist in converting test
- * cases that used to insert strings into bit data tables
- * Converts using UTF-16BE just like the old casts used to.
- *
- * @param s String to convert (e.g
- * @return hex literal that can be inserted into a bit column.
- */
- public static String stringToHexLiteral(String s)
- {
- byte[] bytes;
- String hexLiteral = null;
- try {
- bytes = s.getBytes("UTF-16BE");
- hexLiteral = convertToHexString(bytes);
- }
- catch (UnsupportedEncodingException ue)
- {
- System.out.println("This shouldn't happen as UTF-16BE should be supported");
- ue.printStackTrace();
- }
+ private Utilities() { }
- return hexLiteral;
+ /**
+ * Converts a string to a hex literal to assist in converting test
+ * cases that used to insert strings into bit data tables.
+ * <p>
+ * Converts using UTF-16BE just like the old casts used to.
+ *
+ * @param s string to convert
+ * @return hex literal that can be inserted into a bit column.
+ */
+ public static String stringToHexLiteral(String s) {
+ byte[] bytes;
+ String hexLiteral = null;
+ try {
+ bytes = s.getBytes("UTF-16BE");
+ hexLiteral = convertToHexString(bytes);
+ } catch (UnsupportedEncodingException ue) {
+ Assert.fail("Encoding UTF-16BE unavailable: " + ue.getMessage());
}
- /**
- * Convert a byte array to a hex string suitable for insert
- * @param buf byte array to convert
- * @return formated string representing byte array
- */
- private static String convertToHexString(byte [] buf)
- {
- StringBuffer str = new StringBuffer();
- str.append("X'");
- String val;
- int byteVal;
- for (int i = 0; i < buf.length; i++)
- {
- byteVal = buf[i] & 0xff;
- val = Integer.toHexString(byteVal);
- if (val.length() < 2)
- str.append("0");
- str.append(val);
- }
- return str.toString() +"'";
+ return hexLiteral;
+ }
+
+ /**
+ * Convert a byte array to a hex string suitable for insert.
+ *
+ * @param buf byte array to convert
+ * @return formated string representing byte array
+ */
+ private static String convertToHexString(byte[] buf) {
+ StringBuffer str = new StringBuffer();
+ str.append("X'");
+ String val;
+ int byteVal;
+ for (int i = 0; i < buf.length; i++) {
+ byteVal = buf[i] & 0xff;
+ val = Integer.toHexString(byteVal);
+ if (val.length() < 2) {
+ str.append("0");
+ }
+ str.append(val);
}
+ return str.toString() + "'";
+ }
+
+ /**
+ * Creates a string with the specified length.
+ * <p>
+ * Called from various tests to test edge cases and such.
+ *
+ * @param c character to repeat
+ * @param repeatCount Number of times to repeat character
+ * @return String of repeatCount characters c
+ */
+ public static String repeatChar(String c, int repeatCount) {
+ char[] chArray = new char[repeatCount];
+ Arrays.fill(chArray, c.charAt(0));
+ return String.valueOf(chArray);
+ }
- /**
- * repeatChar is used to create strings of varying lengths.
- * called from various tests to test edge cases and such.
- *
- * @param c character to repeat
- * @param repeatCount Number of times to repeat character
- * @return String of repeatCount characters c
- */
- public static String repeatChar(String c, int repeatCount)
- {
- char ch = c.charAt(0);
-
- char[] chArray = new char[repeatCount];
- for (int i = 0; i < repeatCount; i++)
- {
- chArray[i] = ch;
- }
-
- return new String(chArray);
-
- }
-
- /**
- * Print out resultSet in two dimensional array format, for use by
- * JDBC.assertFullResultSet(rs,expectedRows) expectedRows argument.
- * Useful while converting tests to get output in correct format.
- *
- * @param rs
- * @throws SQLException
- */
- public static void showResultSet(ResultSet rs) throws SQLException {
+ /**
+ * Print out resultSet in two dimensional array format, for use by
+ * JDBC.assertFullResultSet(rs,expectedRows) expectedRows argument.
+ * Useful while converting tests to get output in correct format.
+ *
+ * @param rs result set to print
+ * @throws SQLException if accessing the result set fails
+ */
+ public static void showResultSet(ResultSet rs) throws SQLException {
+ System.out.print("{");
+ int row = 0;
+ boolean next = rs.next();
+ while (next) {
+ row++;
+ ResultSetMetaData rsmd = rs.getMetaData();
+ int nocols = rsmd.getColumnCount();
System.out.print("{");
- int row = 0;
- boolean next = rs.next();
- while (next) {
- row++;
- ResultSetMetaData rsmd = rs.getMetaData();
- int nocols = rsmd.getColumnCount();
- System.out.print("{");
-
- for (int i = 0; i < nocols; i++)
- {
- String val = rs.getString(i+1);
- if (val == null)
- System.out.print("null");
- else
- System.out.print("\"" + rs.getString(i+1) + "\"");
- if (i == (nocols -1))
- System.out.print("}");
- else
- System.out.print(",");
-
+
+ for (int i = 0; i < nocols; i++) {
+ String val = rs.getString(i + 1);
+ if (val == null) {
+ System.out.print("null");
+ } else {
+ System.out.print("\"" + rs.getString(i + 1) + "\"");
+ }
+ if (i == (nocols - 1)) {
+ System.out.print("}");
+ } else {
+ System.out.print(",");
}
- next = rs.next();
-
- if (next)
- System.out.println(",");
- else
- System.out.println("};\n");
+
+ }
+ next = rs.next();
+
+ if (next) {
+ System.out.println(",");
+ } else {
+ System.out.println("};\n");
}
}
-
+ }
+
/**
- * Calls the public method <code>getInfo</code> of the sysinfo tool within
- * this JVM and returns a <code>BufferedReader</code> for reading its
+ * Calls the public method {@code getInfo} of the sysinfo tool within
+ * this JVM and returns a {@code BufferedReader} for reading its
* output. This is useful for obtaining system information that could be
* used to verify, for example, values returned by Derby MBeans.
*
@@ -173,13 +161,13 @@ public class Utilities {
pw.close();
byte[] outBytes = byteStream.toByteArray();
BufferedReader sysinfoOutput = new BufferedReader(
- new InputStreamReader(
- new ByteArrayInputStream(outBytes)));
+ new InputStreamReader(
+ new ByteArrayInputStream(outBytes)));
return sysinfoOutput;
}
-
+
/**
- * <p>Calls the public method <code>getSysInfo()</code> of the Network
+ * <p>Calls the public method {@code getSysInfo} of the Network
* Server instance associated with the current test configuration and
* returns the result as a BufferedReader, making it easy to analyse the
* output line by line.</p>
@@ -192,29 +180,24 @@ public class Utilities {
* @see org.apache.derby.drda.NetworkServerControl#getSysinfo()
*/
public static BufferedReader getSysinfoFromServer() throws Exception {
-
+
return new BufferedReader(new StringReader(
NetworkServerTestSetup.getNetworkServerControl().getSysinfo()));
}
-
+
/**
* Splits a string around matches of the given delimiter character.
* Copied from org.apache.derby.iapi.util.StringUtil
*
* Where applicable, this method can be used as a substitute for
- * <code>String.split(String regex)</code>, which is not available
+ * {@code String.split(String regex)}, which is not available
* on a JSR169/Java ME platform.
*
* @param str the string to be split
* @param delim the delimiter
* @throws NullPointerException if str is null
*/
- static public String[] split(String str, char delim)
- {
- if (str == null) {
- throw new NullPointerException("str can't be null");
- }
-
+ public static String[] split(String str, char delim) {
// Note the javadoc on StringTokenizer:
// StringTokenizer is a legacy class that is retained for
// compatibility reasons although its use is discouraged in
@@ -231,4 +214,21 @@ public class Utilities {
return s;
}
+ /**
+ * Sleeps the specified number of milliseconds.
+ *
+ * @param millis sleep duration
+ */
+ public static void sleep(long millis) {
+ long started = System.currentTimeMillis();
+ long waited = 0;
+ while (waited < millis) {
+ try {
+ Thread.sleep(millis - waited);
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ }
+ waited = System.currentTimeMillis() - started;
+ }
+ }
}