|
From: <mwl...@us...> - 2010-01-13 17:13:54
|
Revision: 1018
http://cishell.svn.sourceforge.net/cishell/?rev=1018&view=rev
Author: mwlinnem
Date: 2010-01-13 17:13:46 +0000 (Wed, 13 Jan 2010)
Log Message:
-----------
Changed to use database cleaning code from an open source apache derby test suite.
Modified Paths:
--------------
trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/DerbyDatabaseService.java
Added Paths:
-----------
trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/utility/
trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/utility/DatabaseCleaner.java
trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/utility/JDBC.java
Modified: trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/DerbyDatabaseService.java
===================================================================
--- trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/DerbyDatabaseService.java 2010-01-13 16:55:34 UTC (rev 1017)
+++ trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/DerbyDatabaseService.java 2010-01-13 17:13:46 UTC (rev 1018)
@@ -18,6 +18,7 @@
import org.apache.commons.pool.KeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
+import org.cishell.reference.service.database.utility.DatabaseCleaner;
import org.cishell.service.database.Database;
import org.cishell.service.database.DatabaseCreationException;
import org.cishell.service.database.DatabaseService;
@@ -68,7 +69,7 @@
try {
for (InternalDerbyDatabase internalDatabase : internalDatabases) {
Connection internalDatabaseConnection = internalDatabase.getConnection();
- removeAllNonSystemDatabaseTables(internalDatabaseConnection);
+ //DatabaseCleaner.cleanDatabase(internalDatabaseConnection, false);
internalDatabase.shutdown();
}
} catch (Exception e) {
@@ -94,7 +95,7 @@
//if this database existed on disk from a previous session, clean it to be like new
- removeAllNonSystemDatabaseTables(db.getConnection());
+ DatabaseCleaner.cleanDatabase(db.getConnection(), false);
//keep track of our new database for this CIShell session
internalDatabases.add(db);
@@ -167,31 +168,31 @@
private static final int TABLE_NAME_INDEX = 3;
private static final String NONSYSTEM_SCHEMA_NAME = "APP";
- //(removes all non-system tables from the provided databases)
- private void removeAllNonSystemDatabaseTables(Connection dbConnection) throws SQLException {
- DatabaseMetaData dbMetadata = dbConnection.getMetaData();
- //using the TABLE type means we get no system tables.
- ResultSet allTableNames = dbMetadata.getTables(null, null, null, new String[]{"TABLE"});
-
- Statement removeTables = dbConnection.createStatement();
-
- while (allTableNames.next()) {
- String dropTableQuery = formDropTableQuery(allTableNames.getString(SCHEMA_NAME_INDEX),
- allTableNames.getString(TABLE_NAME_INDEX));
- removeTables.addBatch(dropTableQuery);
- }
-
- removeTables.executeBatch();
+// //(removes all non-system tables from the provided databases)
+// private void removeAllNonSystemDatabaseTables(Connection dbConnection) throws SQLException {
+// DatabaseMetaData dbMetadata = dbConnection.getMetaData();
+// ResultSet allTableNames = dbMetadata.getTables(null, null, null, null);
+//
+// Statement removeTables = dbConnection.createStatement();
+//
+// while (allTableNames.next()) {
+// if (!hasSystemSchema(allTableNames.getString(SCHEMA_NAME_INDEX))) {
+// String dropTableQuery = formDropTableQuery(allTableNames.getString(TABLE_NAME_INDEX));
+// removeTables.addBatch(dropTableQuery);
+// }
+// }
+//
+// removeTables.executeBatch();
+// }
+
+ private boolean hasSystemSchema(String tableSchemaName) {
+ return tableSchemaName.indexOf(NONSYSTEM_SCHEMA_NAME) == -1;
}
- private String formDropTableQuery(String schema, String tableName) {
- String schemaPrefix = "";
- if(schema != null && !"".equals(schema)) {
- schemaPrefix = schema + ".";
- }
+ private String formDropTableQuery(String tableName) {
String removeTableSQL =
"DROP TABLE "
- + schemaPrefix + "." + tableName;
+ + NONSYSTEM_SCHEMA_NAME + "." + tableName;
return removeTableSQL;
}
}
Added: trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/utility/DatabaseCleaner.java
===================================================================
--- trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/utility/DatabaseCleaner.java (rev 0)
+++ trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/utility/DatabaseCleaner.java 2010-01-13 17:13:46 UTC (rev 1018)
@@ -0,0 +1,179 @@
+package org.cishell.reference.service.database.utility;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+//taken from http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/CleanDatabaseTestSetup.java?view=markup
+/*
+ *
+ * Derby - Class org.apache.derbyTesting.functionTests.util.CleanDatabase
+ *
+ * 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.
+ */
+
+public class DatabaseCleaner {
+
+
+ /**
+ * Clean a complete database
+ * @param conn Connection to be used, must not be in auto-commit mode.
+ * @param compress True if selected system tables are to be compressed
+ * to avoid potential ordering differences in test output.
+ * @throws SQLException database error
+ */
+ public static void cleanDatabase(Connection conn, boolean compress) throws SQLException {
+ clearProperties(conn);
+ removeObjects(conn);
+ if (compress)
+ compressObjects(conn);
+ //removeRoles(conn);
+ }
+
+ /**
+ * Set of database properties that will be set to NULL (unset)
+ * as part of cleaning a database.
+ */
+ private static final String[] CLEAR_DB_PROPERTIES =
+ {
+ "derby.database.classpath",
+ };
+
+ /**
+ * Clear all database properties.
+ */
+ private static void clearProperties(Connection conn) throws SQLException {
+
+ PreparedStatement ps = conn.prepareCall(
+ "CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(?, NULL)");
+
+ for (int i = 0; i < CLEAR_DB_PROPERTIES.length; i++)
+ {
+ ps.setString(1, CLEAR_DB_PROPERTIES[i]);
+ ps.executeUpdate();
+ }
+ ps.close();
+ conn.commit();
+ }
+
+
+ /**
+ * Remove all objects in all schemas from the database.
+ */
+ private static void removeObjects(Connection conn) throws SQLException {
+
+ DatabaseMetaData dmd = conn.getMetaData();
+
+ SQLException sqle = null;
+ // Loop a number of arbitary times to catch cases
+ // where objects are dependent on objects in
+ // different schemas.
+ for (int count = 0; count < 5; count++) {
+ // Fetch all the user schemas into a list
+ List schemas = new ArrayList();
+ ResultSet rs = dmd.getSchemas();
+ while (rs.next()) {
+
+ String schema = rs.getString("TABLE_SCHEM");
+ if (schema.startsWith("SYS"))
+ continue;
+ if (schema.equals("SQLJ"))
+ continue;
+ if (schema.equals("NULLID"))
+ continue;
+
+ schemas.add(schema);
+ }
+ rs.close();
+
+ // DROP all the user schemas.
+ sqle = null;
+ for (Iterator i = schemas.iterator(); i.hasNext();) {
+ String schema = (String) i.next();
+ try {
+ JDBC.dropSchema(dmd, schema);
+ } catch (SQLException e) {
+ sqle = e;
+ }
+ }
+ // No errors means all the schemas we wanted to
+ // drop were dropped, so nothing more to do.
+ if (sqle == null)
+ return;
+ }
+ throw sqle;
+ }
+
+ private static void removeRoles(Connection conn) throws SQLException {
+ // No metadata for roles, so do a query against SYSROLES
+ Statement stm = conn.createStatement();
+ Statement dropStm = conn.createStatement();
+
+ // cast to overcome territory differences in some cases:
+ ResultSet rs = stm.executeQuery(
+ "select roleid from sys.sysroles where " +
+ "cast(isdef as char(1)) = 'Y'");
+
+ while (rs.next()) {
+ dropStm.executeUpdate("DROP ROLE " + JDBC.escape(rs.getString(1)));
+ }
+
+ stm.close();
+ dropStm.close();
+ conn.commit();
+ }
+
+ /**
+ * Set of objects that will be compressed as part of cleaning a database.
+ */
+ private static final String[] COMPRESS_DB_OBJECTS =
+ {
+ "SYS.SYSDEPENDS",
+ };
+
+ /**
+ * Compress the objects in the database.
+ *
+ * @param conn the db connection
+ * @throws SQLException database error
+ */
+ private static void compressObjects(Connection conn) throws SQLException {
+
+ CallableStatement cs = conn.prepareCall
+ ("CALL SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE(?, ?, 1, 1, 1)");
+
+ for (int i = 0; i < COMPRESS_DB_OBJECTS.length; i++)
+ {
+ int delim = COMPRESS_DB_OBJECTS[i].indexOf(".");
+ cs.setString(1, COMPRESS_DB_OBJECTS[i].substring(0, delim) );
+ cs.setString(2, COMPRESS_DB_OBJECTS[i].substring(delim+1) );
+ cs.execute();
+ }
+
+ cs.close();
+ conn.commit();
+ }
+
+
+
+}
\ No newline at end of file
Added: trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/utility/JDBC.java
===================================================================
--- trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/utility/JDBC.java (rev 0)
+++ trunk/core/org.cishell.reference.service.database/src/org/cishell/reference/service/database/utility/JDBC.java 2010-01-13 17:13:46 UTC (rev 1018)
@@ -0,0 +1,625 @@
+package org.cishell.reference.service.database.utility;
+
+//taken from http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/CleanDatabaseTestSetup.java?view=markup
+
+/*
+ *
+ * Derby - Class org.apache.derbyTesting.junit.JDBC
+ *
+ * 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.
+ */
+
+import java.io.IOException;
+import java.sql.BatchUpdateException;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ParameterMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Locale;
+
+
+/**
+ * JDBC utility methods for the JUnit tests.
+ * Note that JSR 169 is a subset of JDBC 3 and
+ * JDBC 3 is a subset of JDBC 4.
+ * The base level for the Derby tests is JSR 169.
+ */
+public class JDBC {
+
+ /**
+ * Helper class whose <code>equals()</code> method returns
+ * <code>true</code> for all strings on this format: SQL061021105830900
+ */
+ public static class GeneratedId {
+ public boolean equals(Object o) {
+ // unless JSR169, use String.matches...
+ if (JDBC.vmSupportsJDBC3())
+ {
+ return o instanceof String &&
+ ((String) o).matches("SQL[0-9]{15}");
+ }
+ else
+ {
+ String tmpstr = (String)o;
+ boolean b = true;
+ if (!(o instanceof String))
+ b = false;
+ if (!(tmpstr.startsWith("SQL")))
+ b = false;
+ if (tmpstr.length() != 18)
+ b = false;
+ for (int i=3 ; i<18 ; i++)
+ {
+ if (Character.isDigit(tmpstr.charAt(i)))
+ continue;
+ else
+ {
+ b = false;
+ break;
+ }
+ }
+ return b;
+ }
+ }
+ public String toString() {
+ return "xxxxGENERATED-IDxxxx";
+ }
+ }
+
+ /**
+ * Constant to pass to DatabaseMetaData.getTables() to fetch
+ * just tables.
+ */
+ public static final String[] GET_TABLES_TABLE = new String[] {"TABLE"};
+ /**
+ * Constant to pass to DatabaseMetaData.getTables() to fetch
+ * just views.
+ */
+ public static final String[] GET_TABLES_VIEW = new String[] {"VIEW"};
+ /**
+ * Constant to pass to DatabaseMetaData.getTables() to fetch
+ * just synonyms.
+ */
+ public static final String[] GET_TABLES_SYNONYM =
+ new String[] {"SYNONYM"};
+
+ /**
+ * Types.SQLXML value without having to compile with JDBC4.
+ */
+ public static final int SQLXML = 2009;
+
+ /**
+ * Tell if we are allowed to use DriverManager to create database
+ * connections.
+ */
+ private static final boolean HAVE_DRIVER
+ = haveClass("java.sql.Driver");
+
+ /**
+ * Does the Savepoint class exist, indicates
+ * JDBC 3 (or JSR 169).
+ */
+ private static final boolean HAVE_SAVEPOINT
+ = haveClass("java.sql.Savepoint");
+
+ /**
+ * Does the java.sql.SQLXML class exist, indicates JDBC 4.
+ */
+ private static final boolean HAVE_SQLXML
+ = haveClass("java.sql.SQLXML");
+
+ /**
+ * Can we load a specific class, use this to determine JDBC level.
+ * @param className Class to attempt load on.
+ * @return true if class can be loaded, false otherwise.
+ */
+ static boolean haveClass(String className)
+ {
+ try {
+ Class.forName(className);
+ return true;
+ } catch (Throwable e) {
+ return false;
+ }
+ }
+ /**
+ * Return true if the virtual machine environment
+ * supports JDBC4 or later. JDBC 4 is a superset
+ * of JDBC 3 and of JSR169.
+ * <BR>
+ * This method returns true in a JDBC 4 environment
+ * and false in a JDBC 3 or JSR 169 environment.
+ */
+ public static boolean vmSupportsJDBC4()
+ {
+ return HAVE_DRIVER
+ && HAVE_SQLXML;
+ }
+ /**
+ * Return true if the virtual machine environment
+ * supports JDBC3 or later. JDBC 3 is a super-set of JSR169
+ * and a subset of JDBC 4.
+ * <BR>
+ * This method will return true in a JDBC 3 or JDBC 4
+ * environment, but false in a JSR169 environment.
+ */
+ public static boolean vmSupportsJDBC3()
+ {
+ return HAVE_DRIVER
+ && HAVE_SAVEPOINT;
+ }
+
+ /**
+ * Return true if the virtual machine environment
+ * supports JSR169. JSR169 is a subset of JDBC 3
+ * and hence a subset of JDBC 4 as well.
+ * <BR>
+ * This method returns true only in a JSR 169
+ * environment.
+ */
+ public static boolean vmSupportsJSR169()
+ {
+ return !HAVE_DRIVER
+ && HAVE_SAVEPOINT;
+ }
+
+ /**
+ * Rollback and close a connection for cleanup.
+ * Test code that is expecting Connection.close to succeed
+ * normally should just call conn.close().
+ *
+ * <P>
+ * If conn is not-null and isClosed() returns false
+ * then both rollback and close will be called.
+ * If both methods throw exceptions
+ * then they will be chained together and thrown.
+ * @throws SQLException Error closing connection.
+ */
+ public static void cleanup(Connection conn) throws SQLException
+ {
+ if (conn == null)
+ return;
+ if (conn.isClosed())
+ return;
+
+ SQLException sqle = null;
+ try {
+ conn.rollback();
+ } catch (SQLException e) {
+ sqle = e;
+ }
+
+ try {
+ conn.close();
+ } catch (SQLException e) {
+ if (sqle == null)
+ sqle = e;
+ else
+ sqle.setNextException(e);
+ throw sqle;
+ }
+ }
+
+ /**
+ * Drop a database schema by dropping all objects in it
+ * and then executing DROP SCHEMA. If the schema is
+ * APP it is cleaned but DROP SCHEMA is not executed.
+ *
+ * TODO: Handle dependencies by looping in some intelligent
+ * way until everything can be dropped.
+ *
+
+ *
+ * @param dmd DatabaseMetaData object for database
+ * @param schema Name of the schema
+ * @throws SQLException database error
+ */
+ public static void dropSchema(DatabaseMetaData dmd, String schema) throws SQLException
+ {
+ Connection conn = dmd.getConnection();
+ Statement s = dmd.getConnection().createStatement();
+
+ // Functions - not supported by JDBC meta data until JDBC 4
+ // Need to use the CHAR() function on A.ALIASTYPE
+ // so that the compare will work in any schema.
+ PreparedStatement psf = conn.prepareStatement(
+ "SELECT ALIAS FROM SYS.SYSALIASES A, SYS.SYSSCHEMAS S" +
+ " WHERE A.SCHEMAID = S.SCHEMAID " +
+ " AND CHAR(A.ALIASTYPE) = ? " +
+ " AND S.SCHEMANAME = ?");
+ psf.setString(1, "F" );
+ psf.setString(2, schema);
+ ResultSet rs = psf.executeQuery();
+ dropUsingDMD(s, rs, schema, "ALIAS", "FUNCTION");
+
+ // Procedures
+ rs = dmd.getProcedures((String) null,
+ schema, (String) null);
+
+ dropUsingDMD(s, rs, schema, "PROCEDURE_NAME", "PROCEDURE");
+
+ // Views
+ rs = dmd.getTables((String) null, schema, (String) null,
+ GET_TABLES_VIEW);
+
+ dropUsingDMD(s, rs, schema, "TABLE_NAME", "VIEW");
+
+ // Tables
+ rs = dmd.getTables((String) null, schema, (String) null,
+ GET_TABLES_TABLE);
+
+ dropUsingDMD(s, rs, schema, "TABLE_NAME", "TABLE");
+
+ // At this point there may be tables left due to
+ // foreign key constraints leading to a dependency loop.
+ // Drop any constraints that remain and then drop the tables.
+ // If there are no tables then this should be a quick no-op.
+ ResultSet table_rs = dmd.getTables((String) null, schema, (String) null,
+ GET_TABLES_TABLE);
+
+ while (table_rs.next()) {
+ String tablename = table_rs.getString("TABLE_NAME");
+ rs = dmd.getExportedKeys((String) null, schema, tablename);
+ while (rs.next()) {
+ short keyPosition = rs.getShort("KEY_SEQ");
+ if (keyPosition != 1)
+ continue;
+ String fkName = rs.getString("FK_NAME");
+ // No name, probably can't happen but couldn't drop it anyway.
+ if (fkName == null)
+ continue;
+ String fkSchema = rs.getString("FKTABLE_SCHEM");
+ String fkTable = rs.getString("FKTABLE_NAME");
+
+ String ddl = "ALTER TABLE " +
+ JDBC.escape(fkSchema, fkTable) +
+ " DROP FOREIGN KEY " +
+ JDBC.escape(fkName);
+ s.executeUpdate(ddl);
+ }
+ rs.close();
+ }
+ table_rs.close();
+ conn.commit();
+
+ // Tables (again)
+ rs = dmd.getTables((String) null, schema, (String) null,
+ GET_TABLES_TABLE);
+ dropUsingDMD(s, rs, schema, "TABLE_NAME", "TABLE");
+
+ // drop UDTs
+ psf.setString(1, "A" );
+ psf.setString(2, schema);
+ rs = psf.executeQuery();
+ dropUsingDMD(s, rs, schema, "ALIAS", "TYPE");
+ psf.close();
+
+ // Synonyms - need work around for DERBY-1790 where
+ // passing a table type of SYNONYM fails.
+ rs = dmd.getTables((String) null, schema, (String) null,
+ GET_TABLES_SYNONYM);
+
+ dropUsingDMD(s, rs, schema, "TABLE_NAME", "SYNONYM");
+
+ // sequences
+ if ( sysSequencesExists( conn ) )
+ {
+ psf = conn.prepareStatement
+ (
+ "SELECT SEQUENCENAME FROM SYS.SYSSEQUENCES A, SYS.SYSSCHEMAS S" +
+ " WHERE A.SCHEMAID = S.SCHEMAID " +
+ " AND S.SCHEMANAME = ?");
+ psf.setString(1, schema);
+ rs = psf.executeQuery();
+ dropUsingDMD(s, rs, schema, "SEQUENCENAME", "SEQUENCE");
+ psf.close();
+ }
+
+ // Finally drop the schema if it is not APP
+ if (!schema.equals("APP")) {
+ s.executeUpdate("DROP SCHEMA " + JDBC.escape(schema) + " RESTRICT");
+ }
+ conn.commit();
+ s.close();
+ }
+
+ /**
+ * Return true if the SYSSEQUENCES table exists.
+ */
+ private static boolean sysSequencesExists( Connection conn ) throws SQLException
+ {
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ try {
+ ps = conn.prepareStatement
+ (
+ "select count(*) from sys.systables t, sys.sysschemas s\n" +
+ "where t.schemaid = s.schemaid\n" +
+ "and ( cast(s.schemaname as varchar(128)))= 'SYS'\n" +
+ "and ( cast(t.tablename as varchar(128))) = 'SYSSEQUENCES'" );
+ rs = ps.executeQuery();
+ rs.next();
+ return ( rs.getInt( 1 ) > 0 );
+ }
+ finally
+ {
+ if ( rs != null ) { rs.close(); }
+ if ( ps != null ) { ps.close(); }
+ }
+ }
+
+ /**
+ * DROP a set of objects based upon a ResultSet from a
+ * DatabaseMetaData call.
+ *
+ * TODO: Handle errors to ensure all objects are dropped,
+ * probably requires interaction with its caller.
+ *
+ * @param s Statement object used to execute the DROP commands.
+ * @param rs DatabaseMetaData ResultSet
+ * @param schema Schema the objects are contained in
+ * @param mdColumn The column name used to extract the object's
+ * name from rs
+ * @param dropType The keyword to use after DROP in the SQL statement
+ * @throws SQLException database errors.
+ */
+ private static void dropUsingDMD(
+ Statement s, ResultSet rs, String schema,
+ String mdColumn,
+ String dropType) throws SQLException
+ {
+ String dropLeadIn = "DROP " + dropType + " ";
+
+ // First collect the set of DROP SQL statements.
+ ArrayList ddl = new ArrayList();
+ while (rs.next())
+ {
+ String objectName = rs.getString(mdColumn);
+ String raw = dropLeadIn + JDBC.escape(schema, objectName);
+ if ( "TYPE".equals( dropType ) ) { raw = raw + " restrict "; }
+ ddl.add( raw );
+ }
+ rs.close();
+ if (ddl.isEmpty())
+ return;
+
+ // Execute them as a complete batch, hoping they will all succeed.
+ s.clearBatch();
+ int batchCount = 0;
+ for (Iterator i = ddl.iterator(); i.hasNext(); )
+ {
+ Object sql = i.next();
+ if (sql != null) {
+ s.addBatch(sql.toString());
+ batchCount++;
+ }
+ }
+
+ int[] results;
+ boolean hadError;
+ try {
+ results = s.executeBatch();
+ hadError = false;
+ } catch (BatchUpdateException batchException) {
+ results = batchException.getUpdateCounts();
+ hadError = true;
+ }
+
+ // Remove any statements from the list that succeeded.
+ boolean didDrop = false;
+ for (int i = 0; i < results.length; i++)
+ {
+ int result = results[i];
+ if (result == Statement.EXECUTE_FAILED)
+ hadError = true;
+ else if (result == Statement.SUCCESS_NO_INFO || result >= 0) {
+ didDrop = true;
+ ddl.set(i, null);
+ }
+ }
+ s.clearBatch();
+ if (didDrop) {
+ // Commit any work we did do.
+ s.getConnection().commit();
+ }
+
+ // If we had failures drop them as individual statements
+ // until there are none left or none succeed. We need to
+ // do this because the batch processing stops at the first
+ // error. This copes with the simple case where there
+ // are objects of the same type that depend on each other
+ // and a different drop order will allow all or most
+ // to be dropped.
+ if (hadError) {
+ do {
+ hadError = false;
+ didDrop = false;
+ for (ListIterator i = ddl.listIterator(); i.hasNext();) {
+ Object sql = i.next();
+ if (sql != null) {
+ try {
+ s.executeUpdate(sql.toString());
+ i.set(null);
+ didDrop = true;
+ } catch (SQLException e) {
+ hadError = true;
+ }
+ }
+ }
+ if (didDrop)
+ s.getConnection().commit();
+ } while (hadError && didDrop);
+ }
+ }
+ /**
+ * Convert byte array to String.
+ * Each byte is converted to a hexadecimal string representation.
+ *
+ * @param ba Byte array to be converted.
+ * @return Hexadecimal string representation. Returns null on null input.
+ */
+ private static String bytesToString(byte[] ba)
+ {
+ if (ba == null) return null;
+ StringBuffer s = new StringBuffer();
+ for (int i = 0; i < ba.length; ++i) {
+ s.append(Integer.toHexString(ba[i] & 0x00ff));
+ }
+ return s.toString();
+ }
+
+ /**
+ * Escape a non-qualified name so that it is suitable
+ * for use in a SQL query executed by JDBC.
+ */
+ public static String escape(String name)
+ {
+ StringBuffer buffer = new StringBuffer(name.length() + 2);
+ buffer.append('"');
+ for (int i = 0; i < name.length(); i++) {
+ char c = name.charAt(i);
+ // escape double quote characters with an extra double quote
+ if (c == '"') buffer.append('"');
+ buffer.append(c);
+ }
+ buffer.append('"');
+ return buffer.toString();
+ }
+
+
+ /**
+ * Compress 2 adjacent (single or double) quotes into a single (s or d)
+ * quote when found in the middle of a String.
+ *
+ * NOTE: """" or '''' will be compressed into "" or ''.
+ * This function assumes that the leading and trailing quote from a
+ * string or delimited identifier have already been removed.
+ * @param source string to be compressed
+ * @param quotes string containing two single or double quotes.
+ * @return String where quotes have been compressed
+ */
+ private static String compressQuotes(String source, String quotes)
+ {
+ String result = source;
+ int index;
+
+ /* Find the first occurrence of adjacent quotes. */
+ index = result.indexOf(quotes);
+
+ /* Replace each occurrence with a single quote and begin the
+ * search for the next occurrence from where we left off.
+ */
+ while (index != -1) {
+ result = result.substring(0, index + 1) +
+ result.substring(index + 2);
+ index = result.indexOf(quotes, index + 1);
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Convert a SQL identifier to case normal form.
+ *
+ * Normalize a SQL identifer, up-casing if <regular identifer>,
+ * and handling of <delimited identifer> (SQL 2003, section 5.2).
+ * The normal form is used internally in Derby.
+ */
+ public static String identifierToCNF(String id)
+ {
+ if (id == null || id.length() == 0) {
+ return id;
+ }
+
+ if (id.charAt(0) == '"' &&
+ id.length() >= 3 &&
+ id.charAt(id.length() - 1) == '"') {
+ // assume syntax is OK, thats is, any quotes inside are doubled:
+
+ return compressQuotes(
+ id.substring(1, id.length() - 1), "\"\"");
+
+ } else {
+ return id.toUpperCase(Locale.ENGLISH);
+ }
+ }
+
+
+ /**
+ * Escape a schama-qualified name so that it is suitable
+ * for use in a SQL query executed by JDBC.
+ */
+ public static String escape(String schema, String name)
+ {
+ return escape(schema) + "." + escape(name);
+ }
+
+ /**
+ * Return Type name from jdbc type
+ *
+ * @param jdbcType jdbc type to translate
+ */
+ public static String sqlNameFromJdbc(int jdbcType) {
+ switch (jdbcType) {
+ case Types.BIT : return "Types.BIT";
+ case Types.BOOLEAN : return "Types.BOOLEAN";
+ case Types.TINYINT : return "Types.TINYINT";
+ case Types.SMALLINT : return "SMALLINT";
+ case Types.INTEGER : return "INTEGER";
+ case Types.BIGINT : return "BIGINT";
+
+ case Types.FLOAT : return "Types.FLOAT";
+ case Types.REAL : return "REAL";
+ case Types.DOUBLE : return "DOUBLE";
+
+ case Types.NUMERIC : return "Types.NUMERIC";
+ case Types.DECIMAL : return "DECIMAL";
+
+ case Types.CHAR : return "CHAR";
+ case Types.VARCHAR : return "VARCHAR";
+ case Types.LONGVARCHAR : return "LONG VARCHAR";
+ case Types.CLOB : return "CLOB";
+
+ case Types.DATE : return "DATE";
+ case Types.TIME : return "TIME";
+ case Types.TIMESTAMP : return "TIMESTAMP";
+
+ case Types.BINARY : return "CHAR () FOR BIT DATA";
+ case Types.VARBINARY : return "VARCHAR () FOR BIT DATA";
+ case Types.LONGVARBINARY: return "LONG VARCHAR FOR BIT DATA";
+ case Types.BLOB : return "BLOB";
+
+ case Types.OTHER : return "Types.OTHER";
+ case Types.NULL : return "Types.NULL";
+ default : return String.valueOf(jdbcType);
+ }
+ }
+
+
+}
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|