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 dj...@apache.org on 2006/10/19 18:34:26 UTC
svn commit: r465673 - in
/db/derby/code/trunk/java/testing/org/apache/derbyTesting:
functionTests/tests/lang/PrepareExecuteDDL.java junit/BaseJDBCTestCase.java
junit/JDBC.java
Author: djd
Date: Thu Oct 19 09:34:22 2006
New Revision: 465673
URL: http://svn.apache.org/viewvc?view=rev&rev=465673
Log:
DERBY-1976 New & modified utility methods for JDBC JUnit tests to aid conversions of SQL script tests.
Modified:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/PrepareExecuteDDL.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/PrepareExecuteDDL.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/PrepareExecuteDDL.java?view=diff&rev=465673&r1=465672&r2=465673
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/PrepareExecuteDDL.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/PrepareExecuteDDL.java Thu Oct 19 09:34:22 2006
@@ -156,7 +156,7 @@
if (isSelectStar)
;
- JDBC.assertDrainResults(rs);
+ JDBC.assertDrainResults(rs, -1);
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java?view=diff&rev=465673&r1=465672&r2=465673
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java Thu Oct 19 09:34:22 2006
@@ -393,7 +393,10 @@
}
/**
- * Assert that SQLState is as expected.
+ * Assert that SQLState is as expected. If the SQLState for
+ * the top-level exception doesn't match, look for nested
+ * exceptions and, if there are any, see if they have the
+ * desired SQLState.
*
* @param message message to print on failure.
* @param expected the expected SQLState.
@@ -424,7 +427,46 @@
// Save the SQLException
// e.initCause(exception);
- throw e;
+ if (usingDerbyNetClient())
+ {
+ /* For chained exceptions the Derby Client just concatenates
+ * them into the exception message. So search the message
+ * for the desired SQLSTATE. This isn't ideal, but it
+ * should work...
+ */
+ if (exception.getMessage().
+ indexOf("SQLSTATE: " + expected) == -1)
+ {
+ throw e;
+ }
+ }
+ else if (usingDerbyNet())
+ {
+ /* For JCC the error message is a series of tokens representing
+ * different things like SQLSTATE, SQLCODE, nested SQL error
+ * message, and nested SQL state. Based on observation it
+ * appears that the last token in the message is the SQLSTATE
+ * of the nested exception, and it's preceded by a colon.
+ * So using that (hopefully consistent?) rule, try to find
+ * the target SQLSTATE.
+ */
+ String msg = exception.getMessage();
+ if (!msg.substring(msg.lastIndexOf(":")+1)
+ .trim().equals(expected))
+ {
+ throw e;
+ }
+ }
+ else
+ {
+ // Check nested exceptions to see if any of them is
+ // the one we're looking for.
+ exception = exception.getNextException();
+ if (exception != null)
+ assertSQLState(message, expected, exception);
+ else
+ throw e;
+ }
}
}
@@ -437,6 +479,7 @@
public static void assertSQLState(String expected, SQLException exception) {
assertSQLState("Unexpected SQL state.", expected, exception);
}
+
/**
* Assert that the query does not compile and throws
* a SQLException with the expected state.
@@ -447,10 +490,146 @@
public void assertCompileError(String sqlState, String query) {
try {
- prepareStatement(query).close();
+ PreparedStatement pSt = prepareStatement(query);
+ if (usingDerbyNet())
+ {
+ /* For JCC the prepares are deferred until execution,
+ * so we have to actually execute in order to see the
+ * expected error. Note that we don't need to worry
+ * about binding the parameters (if any); the compile
+ * error should occur before the execution-time error
+ * about unbound parameters.
+ */
+ pSt.execute();
+ }
fail("expected compile error: " + sqlState);
} catch (SQLException se) {
assertSQLState(sqlState, se);
+ }
+ }
+
+ /**
+ * Assert that the query fails (either in compilation,
+ * execution, or retrieval of results--doesn't matter)
+ * and throws a SQLException with the expected state.
+ *
+ * Assumption is that 'query' does *not* have parameters
+ * that need binding and thus can be executed using a
+ * simple Statement.execute() call.
+ *
+ * @param sqlstate expected sql state.
+ * @param st Statement object on which to execute.
+ * @param query the query to compile and execute.
+ */
+ public static void assertStatementError(String sqlState,
+ Statement st, String query)
+ {
+ try {
+ boolean haveRS = st.execute(query);
+ fetchAndDiscardAllResults(st, haveRS);
+ fail("Expected error '" + sqlState +
+ "' but no error was thrown.");
+ } catch (SQLException se) {
+ assertSQLState(sqlState, se);
+ }
+ }
+
+ /**
+ * Assert that execution of the received PreparedStatement
+ * object fails (either in execution or when retrieving
+ * results) and throws a SQLException with the expected
+ * state.
+ *
+ * Assumption is that "pSt" is either a PreparedStatement
+ * or a CallableStatement that has already been prepared
+ * and whose parameters (if any) have already been bound.
+ * Thus the only thing left to do is to call "execute()"
+ * and look for the expected SQLException.
+ *
+ * @param sqlstate expected sql state.
+ * @param pSt A PreparedStatement or CallableStatement on
+ * which to call "execute()".
+ */
+ public static void assertStatementError(String sqlState,
+ PreparedStatement pSt)
+ {
+ try {
+ boolean haveRS = pSt.execute();
+ fetchAndDiscardAllResults(pSt, haveRS);
+ fail("Expected error '" + sqlState +
+ "' but no error was thrown.");
+ } catch (SQLException se) {
+ assertSQLState(sqlState, se);
+ }
+ }
+
+ /**
+ * Take a Statement object and a SQL query, execute it
+ * via the "executeUpdate()" method, and assert that the
+ * resultant row count matches the received row count.
+ *
+ * Assumption is that 'query' does *not* have parameters
+ * that need binding and that it can be executed using a
+ * simple Statement.executeUpdate() call.
+ *
+ * @param st Statement object on which to execute.
+ * @param expectedRC Expected row count.
+ * @param query Query to execute.
+ */
+ public static void assertUpdateCount(Statement st,
+ int expectedRC, String query) throws SQLException
+ {
+ assertEquals("Update count does not match:",
+ expectedRC, st.executeUpdate(query));
+ }
+
+ /**
+ * Assert that a call to "executeUpdate()" on the received
+ * PreparedStatement object returns a row count that matches
+ * the received row count.
+ *
+ * Assumption is that "pSt" is either a PreparedStatement
+ * or a CallableStatement that has already been prepared
+ * and whose parameters (if any) have already been bound.
+ * Also assumes the statement's SQL is such that a call
+ * executeUpdate() is allowed. Thus the only thing left
+ * to do is to call the "executeUpdate" method.
+ *
+ * @param pSt The PreparedStatement on which to execute.
+ * @param expectedRC The expected row count.
+ */
+ public static void assertUpdateCount(PreparedStatement pSt,
+ int expectedRC) throws SQLException
+ {
+ assertEquals("Update count does not match:",
+ expectedRC, pSt.executeUpdate());
+ }
+
+ /**
+ * Take the received Statement--on which a query has been
+ * executed--and fetch all rows of all result sets (if any)
+ * returned from execution. The rows themselves are
+ * discarded. This is useful when we expect there to be
+ * an error when processing the results but do not know
+ * (or care) at what point the error occurs.
+ *
+ * @param st An already-executed statement from which
+ * we get the result set to process (if there is one).
+ * @param haveRS Whether or not the the statement's
+ * first result is a result set (as opposed to an
+ * update count).
+ */
+ private static void fetchAndDiscardAllResults(Statement st,
+ boolean haveRS) throws SQLException
+ {
+ ResultSet rs = null;
+ while (haveRS || (st.getUpdateCount() != -1))
+ {
+ // If we have a result set, iterate through all
+ // of the rows.
+ if (haveRS)
+ JDBC.assertDrainResults(st.getResultSet(), -1);
+ haveRS = st.getMoreResults();
}
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java?view=diff&rev=465673&r1=465672&r2=465673
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java Thu Oct 19 09:34:22 2006
@@ -316,27 +316,188 @@
* Drain a single ResultSet by reading all of its
* rows and columns. Each column is accessed using
* getString() and asserted that the returned value
- * matches the state of ResultSet.wasNull().
+ * matches the state of ResultSet.wasNull(). If
+ * the received row count is non-negative, this method
+ * also asserts that the number of rows in the result
+ * set matches the received row count.
* Provides simple testing of the ResultSet when the contents
* are not important.
* @param rs
+ * @param expectedRows If non-negative, indicates how
+ * many rows we expected to see in the result set.
* @throws SQLException
*/
- public static void assertDrainResults(ResultSet rs)
- throws SQLException
+ public static void assertDrainResults(ResultSet rs,
+ int expectedRows) throws SQLException
{
ResultSetMetaData rsmd = rs.getMetaData();
+ int rows = 0;
while (rs.next()) {
for (int col = 1; col <= rsmd.getColumnCount(); col++)
{
String s = rs.getString(col);
Assert.assertEquals(s == null, rs.wasNull());
}
+ rows++;
}
rs.close();
+
+ if (rows >= 0)
+ Assert.assertEquals("Unexpected row count:", expectedRows, rows);
}
+ /**
+ * Takes a result set and a two-dimensional array and asserts
+ * that the two have equivalent rows and columns. The first
+ * row in the 2-d array is expected to be the names of the
+ * columns and thus is compared to the metadata column names.
+ * Subsequent rows in the array are then compared with the
+ * corresponding rows in the result set.
+ *
+ * Will throw an assertion failure if any of the following
+ * is true:
+ *
+ * 1. Expected vs actual number of columns doesn't match
+ * 2. Expected vs actual number of rows doesn't match
+ * 3. Any column in any row of the result set does not "equal"
+ * the corresponding column in the expected 2-d array. If
+ * "allAsStrings" is true then the result set value will be
+ * retrieved as a String and compared, via the ".equals()"
+ * method, to the corresponding object in the array (with
+ * the assumption being that the objects in the array are all
+ * Strings). Otherwise the result set value will be retrieved
+ * and compared as an Object, which is useful when asserting
+ * the JDBC types of the columns in addition to their values.
+ *
+ * @param rs The actual result set.
+ * @param expectedRows 2-Dimensional array of objects representing
+ * the expected result set.
+ * @param allAsStrings Whether or not to fetch (and compare) all
+ * values from the actual result set as Strings; if false the
+ * values will be fetched and compared as Objects.
+ */
+ public static void assertFullResultSet(ResultSet rs,
+ Object [][] expectedRows, boolean allAsStrings)
+ throws SQLException
+ {
+ int rows;
+ boolean firstRow = true;
+ ResultSetMetaData rsmd = rs.getMetaData();
+
+ // Assert that we have the right number of columns.
+ Assert.assertEquals("Unexpected column count:",
+ expectedRows[0].length, rsmd.getColumnCount());
+
+ /* Assert each row of the result set. First row of the result
+ * result set is the column names, so we have to make sure we
+ * don't call rs.next() in that case.
+ */
+ for (rows = 0; firstRow || rs.next(); rows++)
+ {
+ /* If we have more actual rows than expected rows, don't
+ * try to assert the row. Instead just keep iterating
+ * to see exactly how many rows the actual result set has.
+ */
+ if (rows < expectedRows.length)
+ {
+ assertRowInResultSet(rs, rsmd, rows,
+ expectedRows[rows], allAsStrings);
+ }
+
+ firstRow = false;
+ }
+
+ // And finally, assert the row count.
+ Assert.assertEquals("Unexpected row count:", expectedRows.length, rows);
+ }
+
+ /**
+ * Assert that every column in the current row of the received
+ * result set matches the corresponding column in the received
+ * array. If rowNum is zero then instead of using the current
+ * row of "rs", use the column names as retrieved from the result
+ * set metadata.
+ *
+ * @param rs Result set whose current row we'll check (if rowNum
+ * is greater than zero).
+ * @param rsmd Metadata object for "rs". Used for fetching column
+ * names (if rowNum == 0).
+ * @param rowNum Row number (w.r.t expected rows) that we're
+ * checking.
+ * @param expectedRow Array of objects representing the expected
+ * values for the current row (if rowNum > 0) or else the expected
+ * column names (if rowNum == 0).
+ * @param asStrings Whether or not to fetch and compare all values
+ * from "rs" as Strings.
+ */
+ private static void assertRowInResultSet(ResultSet rs,
+ ResultSetMetaData rsmd, int rowNum, Object [] expectedRow,
+ boolean asStrings) throws SQLException
+ {
+ String s;
+ boolean ok;
+ Object obj = null;
+ for (int i = 0; i < expectedRow.length; i++)
+ {
+ /* First row is column names. We didn't call rs.next()
+ * in this case, so we have to be sure we don't call
+ * "wasNull" either. Otherwise we'll see errors in client-
+ * server mode (though embedded doesn't seem to mind).
+ */
+ if (rowNum == 0)
+ {
+ obj = rsmd.getColumnName(i+1);
+ ok = ((expectedRow[i] != null) && obj.equals(expectedRow[i]));
+ }
+ else
+ {
+ if (asStrings)
+ {
+ /* Different clients can return different values for
+ * boolean columns--namely, 0/1 vs false/true. So in
+ * order to keep things uniform, take boolean columns
+ * and get the JDBC string version. Note: since
+ * Derby doesn't have a BOOLEAN type, we assume that
+ * if the column's type is SMALLINT and the expected
+ * value's string form is "true" or "false", then the
+ * column is intended to be a mock boolean column.
+ */
+ if ((expectedRow[i] != null)
+ && (rsmd.getColumnType(i+1) == Types.SMALLINT))
+ {
+ s = expectedRow[i].toString();
+ if (s.equals("true") || s.equals("false"))
+ obj = (rs.getShort(i+1) == 0) ? "false" : "true";
+ }
+ else
+ {
+ obj = rs.getString(i+1);
+
+ // Trim the string before comparing.
+ if (obj != null)
+ obj = ((String)obj).trim();
+ }
+ }
+ else
+ obj = rs.getObject(i+1);
+
+ ok = (rs.wasNull() && (expectedRow[i] == null))
+ || (!rs.wasNull()
+ && (expectedRow[i] != null)
+ && obj.equals(expectedRow[i]));
+ }
+
+ if (!ok)
+ {
+ Assert.fail("Column value mismatch @ column '" +
+ rsmd.getColumnName(i+1) + "', row " + rowNum +
+ ":\n Expected: " + expectedRow[i] +
+ "\n Found: " + obj);
+ }
+ }
+ }
+
/**
* Escape a non-qualified name so that it is suitable
* for use in a SQL query executed by JDBC.