/* * Copyright 2013 Matt Sicker and Contributors * * Licensed 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 atg.tools.dynunit.adapter.gsa; import atg.adapter.gsa.GSARepository; import atg.core.util.StringUtils; import atg.dtm.TransactionDemarcation; import atg.dtm.TransactionDemarcationException; import atg.nucleus.GenericService; import atg.nucleus.ServiceException; import org.jetbrains.annotations.Nullable; import javax.sql.DataSource; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; /** * This class is designed to assist with database table manipulation such as * adding tables. Parts copied from atg.service.idgen.?? by mgk * * @author mf * @version 1.0 */ public class SQLProcessorEngine extends GenericService { // Vendor String for Apache Derby private static final String APACHE_DERBY = "Apache Derby"; /* =========== CONSTRUCTORS ============= */ /** * empty constructor */ public SQLProcessorEngine() { } /** * Construct a generator */ public SQLProcessorEngine(GSARepository pRep) { setRepository(pRep); mDataSource = getRepository().getDataSource(); } // ---------- Property: DataSource ---------- /** * DataSource from which to get DB connections this property is NOT a public * property because it is extracted from the repository property */ private DataSource mDataSource; private void setDataSource(DataSource pDataSource) { mDataSource = pDataSource; } private DataSource getDataSource() { return mDataSource; } /** * GSARepository from which to get the DataSource and TransactionManager */ private GSARepository mRepository; public void setRepository(GSARepository pRep) { mRepository = pRep; } public GSARepository getRepository() { return mRepository; } /** * String executed to determine whether a table exists. The table name is * appended to the end of the string before execution occurs. */ private String mDetermineTableExistsSQL = "SELECT count(*) from"; public void setDetermineTableExistsSQL(String pStr) { mDetermineTableExistsSQL = pStr; } public String getDetermineTableExistsSQL() { return mDetermineTableExistsSQL; } /** * String executed to drop a table. The table name is appended to the end of * the string before execution */ private String mDropTableSQL = "DROP TABLE"; public void setDropTableSQL(String pStr) { mDropTableSQL = pStr; } public String getDropTableSQL() { return mDropTableSQL; } /** * String delimiter used to separate the large String passed to createTables() * into an array of individual Create Table statements default value is * "CREATE TABLE" This delimiter _will_ be included in the final create * statements */ private String mCreateTableBeginDelimiter = "CREATE TABLE"; public void setCreateTableBeginDelimiter(String pStr) { mCreateTableBeginDelimiter = pStr; } public String getCreateTableBeginDelimiter() { return mCreateTableBeginDelimiter; } /** * String delimiter used to separate the large String passed to createTables() * into an array of individual Create Table statements default value is ";" * This delimiter _will not_ be included in the final create statements */ private String mCreateTableEndDelimiter = ";"; public void setCreateTableEndDelimiter(String pStr) { mCreateTableEndDelimiter = pStr; } public String getCreateTableEndDelimiter() { return mCreateTableEndDelimiter; } // ------------------------------------- /** * method to execute when starting this component */ public void doStartService() throws ServiceException { if ( getRepository() == null ) { throw new ServiceException("Repository property is null."); } setDataSource(getRepository().getDataSource()); } /** * Get a DB connection * * @return the connection * @throws SQLProcessorException if there is DB trouble or DataSource trouble */ Connection getConnection() throws SQLProcessorException { try { DataSource ds = getDataSource(); if ( ds == null ) { throw new SQLProcessorException("no DataSource"); } else { return ds.getConnection(); } } catch ( SQLException sqle ) { if ( isLoggingDebug() ) { SQLException next = sqle; while ( next != null ) { logDebug(next); next = next.getNextException(); } } throw new SQLProcessorException(sqle); } } // ------------------------------------- /** * Close a DB connection, logging any SQLExceptions. It is okay to pass a null * connection here * * @param pConnection connection to close, may be null */ private void close(@Nullable Connection pConnection) { if ( pConnection != null ) { try { pConnection.close(); } catch ( SQLException sqle ) { if ( isLoggingError() ) { logError(sqle); } } } } // ------------------------------------- /** * Close a result set, logging any SQLExceptions. It is okay to pass a null * here * * @param pResultSet * result set to close, may be null **/ // private final void close(ResultSet pResultSet) // { // if (pResultSet != null) // { // try // { // pResultSet.close(); // } // catch (SQLException sqle) // { // if (isLoggingError()) // logError(sqle); // } // } // } // ------------------------------------- /** * Close a statement, logging any SQLExceptions. It is okay to pass a null * here. * * @param pStatement statement to close, may be null */ private void close(Statement pStatement) { if ( pStatement != null ) { try { pStatement.close(); } catch ( SQLException sqle ) { if ( isLoggingError() ) { logError(sqle); } } } } // ------------------------------------- /** * Perform the specified SQL statement in a new transaction which is committed. * * @param pSQL SQL to execute * * @return the # of rows affected * @throws SQLProcessorException if there is DB or xact trouble */ private int performSQL(String pSQL) throws SQLProcessorException { TransactionDemarcation td = new TransactionDemarcation(); SQLProcessorException error = null; int rows = 0; try { td.begin( mRepository.getTransactionManager(), TransactionDemarcation.REQUIRES_NEW ); Connection c = null; Statement s = null; try { // get DB connection c = getConnection(); /* * * most of this method is annoying try/catch/finally blocks* inflicted * on us by JTA. the real work is here. */ s = c.createStatement(); // rows = s.executeUpdate(pSQL); s.execute(pSQL); } catch ( SQLException sqle ) { error = new SQLProcessorException(sqle); } finally { close(s); close(c); } } catch ( TransactionDemarcationException e1 ) { // FIXME: yeah this doesn't work the way one might think if ( error == null ) { error = new SQLProcessorException(e1); } else if ( isLoggingError() ) { logError(e1); } } finally { try { td.end(); } catch ( TransactionDemarcationException e2 ) { if ( error == null ) { error = new SQLProcessorException(e2); } else if ( isLoggingError() ) { logError(e2); } } } if ( error != null ) { throw error; } else { return rows; } } /** * This method is used to create tables in a database. It takes a String that * contains all of the table creation statements and is of the format: CREATE * TABLE foo ( <field specifications> ); ... CREATE TABLE bar ( <field * specifications> ); Specifically, this is the format output by the GSA when * a call is made to generateSQL(); Before making the tables, this large * String will be split apart into an array of individual CREATE TABLE * statements using the createTableBeginDelimiter and createTableEndDelimiter * properties. By default, createTableBeginDelimiter = "CREATE TABLE" and * createTableEndDelimiter = ";" * * @param pStatements the String containing the CREATE TABLE statements * @param pDrop indicates whether to drop tables and recreate them * if the tables already exist in the database * * @return true if any tables were created ( or dropped and created ) * @throws SQLProcessorException if an error occurs trying to create the tables */ public boolean createTables(List<String> pStatements, boolean pDrop) throws SQLProcessorException { boolean createdTables = false; // get the create statements to execute and make sure they are // in the proper order with regard to 'references' clauses if ( isLoggingDebug() ) { logDebug("Reordering CREATE TABLE statements so references don't fail..."); } List<String> statements = reorderCreateStatements(pStatements); // if dropping tables, do that before trying to create them // throws exception if all tables can't be dropped List<String> tableNames = getTableNames(statements); if ( pDrop ) { if ( isLoggingInfo() ) { logInfo("Dropping tables..."); } dropTables(tableNames); } // we can assume that if a table still exists it is because we // didn't try to drop it. If we did try to drop it but couldn't, // dropTables would throw an exception and this code would never // be executed if ( isLoggingInfo() ) { logInfo("Creating tables..."); } for ( String statement : statements ) { String name = getTableName(statement); boolean exists = tableExists(name); if ( name != null && !exists ) { if ( isLoggingDebug() ) { logDebug("Creating table: " + name); } if ( this.getRepository() instanceof InitializingGSA ) { if ( !isLoggingDebug() && ((InitializingGSA) this.getRepository()).isLoggingCreateTables() ) { logDebug(statement); } } if ( this.getRepository() instanceof InitializingVersionRepository ) { if ( !isLoggingDebug() && ((InitializingVersionRepository) this.getRepository()) .isLoggingCreateTables() ) { logDebug(statement); } } if ( isDerby() ) { statement = stripNull(statement); } createTable(statement); createdTables = true; } else if ( name != null && !pDrop ) { if ( isLoggingInfo() ) { logInfo( "Table already exists and dropTablesIfExist is false - not creating: " + name ); } // dropExistingTables must be false or else table would have been // dropped } else { // throw new SQLProcessorException("The table " + name + // " was not created because name was null or table couldn't be dropped."); logWarning( "The table " + name + " was not created because name was null or table couldn't be dropped." ); } } return createdTables; } /** * Removes any occurrence of the string "NULL" from a create statement if it * is not preceded by the word "NOT". * * @param statement * * @return */ private String stripNull(String statement) { // first make this all uppercase StringBuilder subStatements = new StringBuilder(); String tempStatement = statement.toUpperCase(); StringTokenizer st = new StringTokenizer(tempStatement, ","); while ( st.hasMoreTokens() ) { String tok = st.nextToken(); int notNullIndex = tok.indexOf("NOT NULL"); if ( notNullIndex > -1 ) { // safe to return this unmodified subStatements.append(tok).append(",\n"); } else if ( tok.contains("NULL") ) { // need to strip this one. // we assume that we can just remove the five characters above String temp = StringUtils.replace(tok, "NULL", ""); // we also have to remove all the trailing spaces subStatements.append(temp.trim()).append(",\n"); } else { // safe to return. no null at all. if ( st.hasMoreTokens() ) { subStatements.append(tok).append(",\n"); } else // End of statement, so no comma { subStatements.append(tok); } } } return subStatements.toString(); } private boolean mIsDerby = false; private boolean mIsDerbySet = false; /** * Returns true if the current database is Apache Derby. The first invocation * to this method will cache its answer. */ public boolean isDerby() throws SQLProcessorException { if ( !mIsDerbySet ) { mIsDerby = isDerbyUncached(); mIsDerbySet = true; } return mIsDerby; } /** * Returns true if the current database is Apache Derby This method call is * not cached and will make a database connection attempt on each invocation. * * @return * @throws SQLProcessorException */ private boolean isDerbyUncached() throws SQLProcessorException { boolean isDerby = false; Connection c = null; try { c = getConnection(); DatabaseMetaData meta = c.getMetaData(); if ( APACHE_DERBY.equals(meta.getDatabaseProductName()) ) { isDerby = true; } return isDerby; } catch ( SQLException e ) { throw new SQLProcessorException(e); } finally { if ( c != null ) { try { c.close(); } catch ( SQLException e ) { // eat it } } } } /** * This is a method that is used to execute a 'CREATE TABLE' call. The String * you pass in is expected to be of the format CREATE TABLE ( ..... ) * * @throws SQLProcessorException thrown if an error occurs creating the table */ private void createTable(String pStr) throws SQLProcessorException { try { performSQL(pStr); } catch ( SQLProcessorException spe ) { throw new SQLProcessorException( "Caught exception executing create table statement \"" + pStr + "\"", spe ); } } /** * This method is used to iteratively drop tables. The iterative effort is * necessary because tables may have references. ASSUMPTION: references only * exist for tables that are defined within this repository. If references * exist from tables outside this repository, this method will throw a * SQLProcessorException * * @param pCreateStatements List of CREATE TABLE statements indicating which tables to drop * * @throws SQLProcessorException thrown if all tables can not be dropped */ public void dropTablesFromCreateStatements(List<String> pCreateStatements) throws SQLProcessorException { List<String> names = getTableNames(pCreateStatements); dropTables(names); } /** * This method is used to iteratively drop tables. The iterative effort is * necessary because tables may have references. ASSUMPTION: references only * exist for tables that are defined within this repository. If references * exist from tables outside this repository, this method will throw a * SQLProcessorException * * @param pNames List of names of tables to be dropped * * @throws SQLProcessorException thrown if all tables can not be dropped */ private void dropTables(List<String> pNames) throws SQLProcessorException { // assuming only one table can be dropped each time, this should take // at most n iterations where n is the nbr of tables being dropped int maxIterations = pNames.size(); // every table is tried at least once List<String> tablesToDrop = pNames; List<String> remainingTables; int attempt = 0; do { remainingTables = new ArrayList<String>(); for ( String table : tablesToDrop ) { if ( tableExists(table) ) { try { logInfo("Attempting to drop table: " + table); dropTable(table); logInfo("Dropped table: " + table); } catch ( SQLProcessorException spe ) { // if this is the last iteration, throw an exception if ( attempt + 1 >= maxIterations ) { throw spe; } // otherwise track this table for the next try remainingTables.add(table); } } } tablesToDrop = remainingTables; } while ( (attempt++ < maxIterations) && (!remainingTables.isEmpty()) ); } /** * This is a method that is used to execute a 'Drop Table' call. The method * creates the drop table statement by appending the name passed as a method * with the SQL that has been set as the dropTableSQL property. By default, * this property is set to "Drop table" * * @param pName the name of the table to drop * * @throws SQLProcessorException thrown if an error occurs trying to drop the table */ private void dropTable(String pName) throws SQLProcessorException { String sql = getDropTableSQL() + " " + pName; try { logDebug("Attempting to drop table: " + pName); performSQL(sql); } catch ( SQLProcessorException spe ) { throw new SQLProcessorException( "Caught exception executing drop table statement \"" + sql + "\"", spe ); } } /** * This method is used to extract table names from a Vector of CREATE * statements returned by either a call to getCreateStatements() or * getOrderedCreateStatements() * * @return List of table names */ private List<String> getTableNames(final List<String> pStatements) { if ( isLoggingDebug() ) { logDebug("Getting table names..."); } List<String> names = new ArrayList<String>(); // split the big string into a bunch of create table statements List<String> createStatements = pStatements; // now get the table name from each statement for ( String createStatement : createStatements ) { String thisName = getTableName(createStatement); if ( thisName != null && !names.contains(thisName) ) { names.add(thisName); if ( isLoggingDebug() ) { logDebug("Found table name: " + thisName); } } } return names; } /** * This is a method used to extract the table name from a CREATE TABLE * statement. It operates by finding the createTableBeginDelimiter and * extracting the next word after the delimiter. * * @param pStr The create table statement * * @return The name of the table; null if name can't be found */ private String getTableName(String pStr) { String STATEMENT_BEGIN = getCreateTableBeginDelimiter(); if ( isLoggingDebug() && (this.getRepository().getDebugLevel() > 6) ) { logDebug("Extracting table name from create table statement: " + pStr); logDebug( "Name is taken as word after createTableBeginDelimiter. Delimiter is set to: " + getCreateTableBeginDelimiter() ); } int index = pStr.indexOf(STATEMENT_BEGIN); if ( index == -1 ) { if ( isLoggingWarning() ) { logWarning( "Could not extract name because start delimiter could not be found. Returning null." ); } return null; } pStr = pStr.substring(index + STATEMENT_BEGIN.length()); // loop to get rid of any spaces immediately after the // start delimiter while ( pStr.startsWith(" ") && (pStr.length() > 1) ) { pStr = pStr.substring(1); } int first_blank = pStr.indexOf(" "); if ( !(first_blank > 0) ) { if ( isLoggingDebug() ) { logDebug( "Could not extract name because no word was found after the start delimiter. Returning null." ); } return null; } String name = pStr.substring(0, first_blank); if ( isLoggingDebug() ) { logDebug("Extracted table name: " + name); } return name; } /** * This method is used to break the large string passed to createTables() into * an array of CREATE TABLE statements. The string is split apart using the * createTableBeginDelimiter and createTableEndDelimiter Strings. These can be * set as the createTableBeginDelimiter and createTableEndDelimiter * properties. * * @param String * - String containing all the Create Table statements * @return Vector of CREATE TABLE statements */ /* * private Vector getCreateStatements( String pStr ) { String STATEMENT_BEGIN * = getCreateTableBeginDelimiter(); String STATEMENT_END = * getCreateTableEndDelimiter(); * * Vector statements = new Vector(); * * // we need to make sure we strip off the potential 'missing tableinfos...' * // error, so we do that by initially recopying the string from the first // * CREATE TABLE. also with this check we catch the condition where the // * string being processed has no CREATE TABLE clauses int index = * pStr.indexOf( STATEMENT_BEGIN ); * * // now loop through and extract all of the CREATE statements String * remaining = pStr.substring( index ); while ( index != -1 ) { int stop = * remaining.indexOf( STATEMENT_END ); if ( stop == -1 ) { // error - this * string is malformed wrt what we expected because no end delimiter was found * if ( isLoggingError() ) * logError("malformed string passed to getCreateStatements - an end delimiter '" * + STATEMENT_END + * "' could not be found. Abandoning parsing of Create table statements."); * break; } * * String thisCreate = remaining.substring(0,stop); if ( isLoggingDebug() ) * logDebug("Parsed create statement: " + thisCreate ); statements.add( * thisCreate ); * * // now see if there are any more statements remaining = * remaining.substring( stop + 1 ); index = remaining.indexOf( STATEMENT_BEGIN * ); // need to put this here so that we skip everything between the end of * the previous // CREATE TABLE and the beginning of the next if ( index != -1 * ) remaining = remaining.substring( index ); } * * if ( isLoggingDebug() ) logDebug("Found " + statements.size() + * " create statements."); * * return statements; } */ /** * This method is used to order CREATE TABLE statements such that we do not try * to create a table before any tables that it references. NOTE: if a * reference exists for a table outside of this repository we will print a * warning, but will _not_ throw an exception. If the referenced table doesn't * exist, an exception will be thrown when the referencing table is created. * * @param statements List containing all of the CREATE TABLE statements as generated by a * call to GSARepository.generateSQL() * * @return List of individual CREATE statements that are in the proper order * to execute * @throws SQLProcessorException if we detect a bad loop trying to resolve references */ private List<String> reorderCreateStatements(final List<String> statements) throws SQLProcessorException { // XXX: another overly complicated method List<String> names = getTableNames(statements); List<String> orderedStatements = new ArrayList<String>(); // hashmap containing one entry for every table that references // another, and holds Vector of those tables it is waiting to be made HashMap<String, List<String>> refersTo = new HashMap<String, List<String>>(); // hashmap containing one entry for every table that is references by // another, and holds Vector of all the tables that reference it HashMap<String, List<String>> referencedBy = new HashMap<String, List<String>>(); // setup the tables so we know who makes which references Iterator<String> iter = statements.iterator(); while ( iter.hasNext() ) { String statement = iter.next(); String tableName = getTableName(statement); List<String> references = getTableReferences(statement, tableName); if ( references.size() < 1 ) { orderedStatements.add(statement); } else { // organize the references this table has if ( !checkReferencesInRepository(names, references) ) { if ( isLoggingWarning() ) { logWarning( "Table " + tableName + " references a table outside the repository." ); } } // create an entry in 'refersTo' for this table refersTo.put(tableName, references); // update referencedBy to include this table for ( String ref : references ) { List<String> v; if ( !referencedBy.containsKey(ref) ) { v = new ArrayList<String>(); v.add(tableName); referencedBy.put(ref, v); } else { v = referencedBy.get(ref); v.add(tableName); } } } } // removed all of the previously the ordered statements iter = orderedStatements.iterator(); while ( iter.hasNext() ) { String statement = iter.next(); statements.remove(statement); } // now that we know all the references, order them appropriately // assuming we add one table per loop, this should take at most // n iterations where n is the starting number of statements to add int maxTries = statements.size(); int attempt = 0; while ( statements.size() > 0 ) { Iterator<String> iterator = statements.iterator(); List<String> newlyAdded = new ArrayList<String>(); while ( iterator.hasNext() ) { String statement = iterator.next(); String tableName = getTableName(statement); // is this table isn't waiting for another table, add it if ( !refersTo.containsKey(tableName) ) { // this would be an error condition !! } else { List<String> waitingOnTables = refersTo.get(tableName); boolean okToAdd = true; for ( String waitingOn : waitingOnTables ) { if ( refersTo.containsKey(waitingOn) ) { okToAdd = false; } } if ( okToAdd ) { orderedStatements.add(statement); newlyAdded.add(statement); // let the other tables know this one is made if ( referencedBy.containsKey(tableName) ) { List<String> tablesWaiting = referencedBy.get(tableName); for ( String table : tablesWaiting ) { List<String> v = refersTo.get(table); v.remove(tableName); } } } } } // after each iteration, remove the newlyAdded statements from the list for ( String s : newlyAdded ) { statements.remove(s); } // make sure we aren't looping infinitely if ( attempt++ > maxTries ) { if ( isLoggingError() ) { logError("Still trying to resolve: "); for ( String table : statements ) { logError(table); } } throw new SQLProcessorException( "Could not order tables appropriately...failing. Turn on loggingDebug for more info." ); } } return orderedStatements; } /** * This method is used to extract the names of other tables that a table * references. expected format is: CREATE TABLE foo ( x int not null * references bar(id), y varchar null references doo(id), ... ) * * @param pStr the CREATE TABLE statement * @param tableName the name of the table * * @return Vector containing names of referenced tables */ private List<String> getTableReferences(String pStr, String tableName) { String REFERENCES = " references "; List<String> refs = new ArrayList<String>(); int start = pStr.toLowerCase().indexOf(REFERENCES); while ( start != -1 ) { pStr = pStr.substring(start + REFERENCES.length()); String ref = pStr; // stop at a '(' int stop = ref.indexOf("("); ref = ref.substring(0, stop); // remove spaces ref = ref.trim(); // bail if the table references itself - i think that is just wrong /* * actually, jeff and mike said this should be allowed, so i won't throw * an exception, i just won't add it to the list of references either... */ if ( ref.equalsIgnoreCase(tableName) ) { // do nothing // throw new SQLProcessorException("The create statement for table " + // tableName + // " contains a reference to itself."); } else if ( (ref.length() > 0) && !refs.contains(ref) ) { refs.add(ref); } start = pStr.toLowerCase().indexOf(REFERENCES); } if ( isLoggingDebug() ) { for ( String s : refs ) { logDebug("Found reference: " + s); } } return refs; } /** * This method is used to determine whether all the items in the second Vector * are contained in the first Vector. * * @param pRepositoryTables list of the names of all the tables in the repository * @param pCheckTables list of the names of all the tables to check for * * @return boolean true if all items are in the Vector; false otherwise */ private boolean checkReferencesInRepository(List<String> pRepositoryTables, List<String> pCheckTables) { for ( String name : pCheckTables ) { if ( !pRepositoryTables.contains(name) ) { return false; } } return true; } /** * Method to determine whether a table already exists in the database. The * method operates by appending the name passed as a parameter to the String * that has been set in the determineTableExistsSQL property * * @param pTableName name of table to check for existence of * * @return true if table exists; false otherwise */ private boolean tableExists(String pTableName) { // don't bother with query if name is invalid if ( pTableName == null || pTableName.length() == 0 ) { return false; } // create sql String sql = getDetermineTableExistsSQL() + " " + pTableName; // execute and check for an exception try { performSQL(sql); } catch ( SQLProcessorException spe ) { // we should only get an exception here if the table does NOT // exist. in that case, don't throw the exception - just return false if ( isLoggingDebug() ) { logDebug( "Table existence is determined by whether an exception is received when querying the table." ); logDebug("Caught exception checking whether table exists, so table doesn't exist."); logDebug("Checked for existence with this statement \"" + sql + "\""); logDebug("Set repository debugLevel > 6 to see full exception."); if ( this.getRepository().getDebugLevel() > 6 ) { logDebug(spe); } } return false; } return true; } /** * Returns true if there is at least one table in this schema * This is handy for Derby since it will throw an error if one * attempts to try a select statement to determine if a table * exists and the schema has not yet been created. * * @return */ private boolean hasAnyTables() { boolean foundTables = false; Connection c = null; try { c = getConnection(); DatabaseMetaData metadata = null; metadata = c.getMetaData(); String[] names = { "TABLE" }; ResultSet tableNames = metadata.getTables(null, null, null, names); while ( tableNames.next() ) { String tab = tableNames.getString("TABLE_NAME"); foundTables = true; break; } tableNames.close(); } catch ( SQLProcessorException e ) { e.printStackTrace(); } catch ( SQLException e ) { e.printStackTrace(); } finally { try { if ( c != null ) { c.close(); } } catch ( SQLException ignored ) { } } return foundTables; } /* These methods are really used - they were just part of mgk's original class */ // ---------- Property: (read-only) InsertSQL ---------- /** * SQL to insert a new id space into the DB table */ transient String mInsertSQL; /** * Get property <code>InsertSQL</code>. The SQL is lazily generated. * * @beaninfo description: SQL to insert a new id space into the DB table * @return InsertSQL **/ // private String getInsertSQL() // { // // build SQL string if needed // if (mInsertSQL == null) // { // StringBuffer buf = new StringBuffer(300); // buf.append("INSERT INTO "); // /* // buf.append(getTableName()); // buf.append('('); // buf.append(getNameColumn()).append(','); // buf.append(getSeedColumn()).append(','); // buf.append(getBatchSizeColumn()).append(','); // buf.append(getPrefixColumn()).append(','); // buf.append(getSuffixColumn()); // */ // // buf.append(')').append('\n'); // buf.append("VALUES (?, ?, ?, ?, ?)\n"); // // mInsertSQL = buf.toString(); // } // // return mInsertSQL; // } // ---------- Property: (read-only) UpdateSQL ---------- /** * SQL to execute to update a specific id space in the DB */ transient String mUpdateSQL; /** * Get property <code>UpdateSQL</code>. The SQL is lazily generated. * * @beaninfo description: SQL to execute to update a specific id space int the * D0B * @return UpdateSQL **/ // private String getUpdateSQL() // { // // generate SQL if needed // if (mUpdateSQL == null) // { // StringBuffer buf = new StringBuffer(300); // buf.append("UPDATE "); // /* // buf.append(getTableName()); // buf.append(" SET "); // buf.append(getSeedColumn()).append('='); // buf.append(getSeedColumn()).append('+'); // buf.append(getBatchSizeColumn()); // buf.append(" WHERE "); // buf.append(getNameColumn()).append(" = ?"); // // */ // mUpdateSQL = buf.toString(); // } // // return mUpdateSQL; // } // ---------- Property: (read-only) SelectSQL ---------- /** * SQL to execute to load a specific id space from the DB */ transient String mSelectSQL; /** * Get property <code>SelectSQL</code>. The SQL is lazily generated. * * @beaninfo description: SQL to execute to load a specific id space from the * DB * @return SelectSQL **/ // private String getSelectSQL() // { // // generate SQL if needed // if (mSelectSQL == null) // { // StringBuffer buf = new StringBuffer(300); // buf.append("SELECT "); // /* // buf.append(getSeedColumn()).append(','); // buf.append(getBatchSizeColumn()).append(','); // buf.append(getPrefixColumn()).append(','); // buf.append(getSuffixColumn()); // buf.append(" FROM "); // buf.append(getTableName()); // buf.append(" WHERE "); // buf.append(getNameColumn()).append(" = ?"); // */ // // mSelectSQL = buf.toString(); // } // // return mSelectSQL; // } }