package org.jumpmind.db.platform; /* * 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 static org.apache.commons.lang.StringUtils.isNotBlank; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.InputStreamReader; import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Array; import java.sql.Timestamp; import java.sql.Types; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateUtils; import org.jumpmind.db.io.DatabaseXmlUtil; import org.jumpmind.db.model.Column; import org.jumpmind.db.model.ColumnTypes; import org.jumpmind.db.model.Database; import org.jumpmind.db.model.ForeignKey; import org.jumpmind.db.model.IIndex; import org.jumpmind.db.model.IndexColumn; import org.jumpmind.db.model.Reference; import org.jumpmind.db.model.Table; import org.jumpmind.db.model.TypeMap; import org.jumpmind.db.sql.DmlStatement; import org.jumpmind.db.sql.DmlStatement.DmlType; import org.jumpmind.db.sql.ISqlTemplate; import org.jumpmind.db.sql.Row; import org.jumpmind.db.sql.SqlScript; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.exception.IoException; import org.jumpmind.util.FormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* * Base class for platform implementations. */ public abstract class AbstractDatabasePlatform implements IDatabasePlatform { /* The log for this platform. */ protected final Logger log = LoggerFactory.getLogger(getClass()); public static final String REQUIRED_FIELD_NULL_SUBSTITUTE = " "; /* The default name for models read from the database, if no name as given. */ protected static final String MODEL_DEFAULT_NAME = "default"; /* The model reader for this platform. */ protected IDdlReader ddlReader; protected IDdlBuilder ddlBuilder; protected Map<String, Table> tableCache = new HashMap<String, Table>(); private long lastTimeCachedModelClearedInMs = System.currentTimeMillis(); protected long clearCacheModelTimeoutInMs = DateUtils.MILLIS_PER_HOUR; protected String defaultSchema; protected String defaultCatalog; protected Boolean storesUpperCaseIdentifiers; protected Boolean storesLowerCaseIdentifiers; protected Boolean storesMixedCaseIdentifiers; protected boolean metadataIgnoreCase = true; public AbstractDatabasePlatform() { } public DatabaseInfo getDatabaseInfo() { return getDdlBuilder().getDatabaseInfo(); } abstract public ISqlTemplate getSqlTemplate(); public DmlStatement createDmlStatement(DmlType dmlType, Table table, String textColumnExpression) { return createDmlStatement(dmlType, table.getCatalog(), table.getSchema(), table.getName(), table.getPrimaryKeyColumns(), table.getColumns(), null, textColumnExpression); } public DmlStatement createDmlStatement(DmlType dmlType, String catalogName, String schemaName, String tableName, Column[] keys, Column[] columns, boolean[] nullKeyValues, String textColumnExpression) { return DmlStatementFactory.createDmlStatement(getName(), dmlType, catalogName, schemaName, tableName, keys, columns, nullKeyValues, getDdlBuilder(), textColumnExpression); } public IDdlReader getDdlReader() { return ddlReader; } public IDdlBuilder getDdlBuilder() { return ddlBuilder; } public void setClearCacheModelTimeoutInMs(long clearCacheModelTimeoutInMs) { this.clearCacheModelTimeoutInMs = clearCacheModelTimeoutInMs; } public long getClearCacheModelTimeoutInMs() { return clearCacheModelTimeoutInMs; } public void dropTables(boolean continueOnError, Table...tables) { Database db = new Database(); for (Table table : tables) { db.addTable(table); } dropDatabase(db, continueOnError); } public void dropDatabase(Database database, boolean continueOnError) { String sql = ddlBuilder.dropTables(database); new SqlScript(sql, getSqlTemplate(), !continueOnError, null).execute(getDatabaseInfo().isRequiresAutoCommitForDdl()); } public void createTables(boolean dropTablesFirst, boolean continueOnError, Table... tables) { Database database = new Database(); database.addTables(tables); createDatabase(database, dropTablesFirst, continueOnError); } public void createDatabase(Database targetDatabase, boolean dropTablesFirst, boolean continueOnError) { if (dropTablesFirst) { dropDatabase(targetDatabase, true); } String createSql = ddlBuilder.createTables(targetDatabase, false); if (log.isDebugEnabled()) { log.debug("Generated create sql: \n{}", createSql); } String delimiter = getDdlBuilder().getDatabaseInfo().getSqlCommandDelimiter(); new SqlScript(createSql, getSqlTemplate(), !continueOnError, false, false, delimiter, null).execute(getDatabaseInfo().isRequiresAutoCommitForDdl()); } public void alterDatabase(Database desiredDatabase, boolean continueOnError) { alterTables(continueOnError, desiredDatabase.getTables()); } public void alterTables(boolean continueOnError, Table... desiredTables) { Database currentDatabase = new Database(); Database desiredDatabase = new Database(); StringBuilder tablesProcessed = new StringBuilder(); for (Table table : desiredTables) { tablesProcessed.append(table.getFullyQualifiedTableName()); tablesProcessed.append(", "); desiredDatabase.addTable(table); Table currentTable = ddlReader.readTable(table.getCatalog(), table.getSchema(), table.getName()); if (currentTable != null) { currentDatabase.addTable(currentTable); } } if (tablesProcessed.length() > 1) { tablesProcessed.replace(tablesProcessed.length() - 2, tablesProcessed.length(), ""); } String alterSql = ddlBuilder.alterDatabase(currentDatabase, desiredDatabase); if (StringUtils.isNotBlank(alterSql.trim())) { log.info("Running alter sql:\n{}", alterSql); String delimiter = getDdlBuilder().getDatabaseInfo().getSqlCommandDelimiter(); new SqlScript(alterSql, getSqlTemplate(), !continueOnError, false, false, delimiter, null).execute(getDatabaseInfo().isRequiresAutoCommitForDdl()); } else { log.info("Tables up to date. No alters found for {}", tablesProcessed); } } public Database readDatabase(String catalog, String schema, String[] tableTypes) { Database model = ddlReader.readTables(catalog, schema, tableTypes); if ((model.getName() == null) || (model.getName().length() == 0)) { model.setName(MODEL_DEFAULT_NAME); } return model; } public Database readFromDatabase(Table... tables) { Database fromDb = new Database(); for (Table tableFromXml : tables) { Table tableFromDatabase = getTableFromCache(tableFromXml.getCatalog(), tableFromXml.getSchema(), tableFromXml.getName(), true); if (tableFromDatabase != null) { fromDb.addTable(tableFromDatabase); } } fromDb.initialize(); return fromDb; } public Table readTableFromDatabase(String catalogName, String schemaName, String tableName) { String originalFullyQualifiedName = Table.getFullyQualifiedTableName(catalogName, schemaName, tableName); String defaultedCatalogName = catalogName == null ? getDefaultCatalog() : catalogName; String defaultedSchemaName = schemaName == null ? getDefaultSchema() : schemaName; Table table = ddlReader.readTable(defaultedCatalogName, defaultedSchemaName, tableName); if (table == null && metadataIgnoreCase) { IDdlReader reader = getDdlReader(); if (isNotBlank(catalogName)) { List<String> catalogNames = reader.getCatalogNames(); if (catalogNames != null) { for (String name : catalogNames) { if (name != null && name.equalsIgnoreCase(catalogName)) { defaultedCatalogName = name; break; } } } } if (isNotBlank(schemaName)) { List<String> schemaNames = reader.getSchemaNames(catalogName); if (schemaNames != null) { for (String name : schemaNames) { if (name != null && name.equalsIgnoreCase(schemaName)) { defaultedSchemaName = name; break; } } } } List<String> tableNames = reader.getTableNames(defaultedCatalogName, defaultedSchemaName, null); if (tableNames != null) { for (String name : tableNames) { if (name != null && name.equalsIgnoreCase(tableName)) { tableName = name; break; } } } if (!originalFullyQualifiedName.equals(Table.getFullyQualifiedTableName( defaultedCatalogName, defaultedSchemaName, tableName))) { table = ddlReader.readTable(defaultedCatalogName, defaultedSchemaName, tableName); } } if (table != null && log.isDebugEnabled()) { log.debug("Just read table: \n{}", table.toVerboseString()); } return table; } public void resetCachedTableModel() { synchronized (this.getClass()) { this.tableCache = new HashMap<String, Table>(); lastTimeCachedModelClearedInMs = System.currentTimeMillis(); } } public Table getTableFromCache(String tableName, boolean forceReread) { return getTableFromCache(getDefaultCatalog(), getDefaultSchema(), tableName, forceReread); } public Table getTableFromCache(String catalogName, String schemaName, String tableName, boolean forceReread) { if (System.currentTimeMillis() - lastTimeCachedModelClearedInMs > clearCacheModelTimeoutInMs) { resetCachedTableModel(); } Map<String, Table> model = tableCache; String key = Table.getFullyQualifiedTableName(catalogName, schemaName, tableName); Table retTable = model != null ? model.get(key) : null; if (retTable == null || forceReread) { synchronized (this.getClass()) { try { Table table = readTableFromDatabase(catalogName, schemaName, tableName); tableCache.put(key, table); retTable = table; } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { throw new RuntimeException(ex); } } } return retTable; } public Object[] getObjectValues(BinaryEncoding encoding, Table table, String[] columnNames, String[] values) { Column[] metaData = Table.orderColumns(columnNames, table); return getObjectValues(encoding, values, metaData); } public Object[] getObjectValues(BinaryEncoding encoding, Table table, String[] columnNames, String[] values, boolean useVariableDates, boolean fitToColumn) { Column[] metaData = Table.orderColumns(columnNames, table); return getObjectValues(encoding, values, metaData, useVariableDates, fitToColumn); } public Object[] getObjectValues(BinaryEncoding encoding, String[] values, Column[] orderedMetaData) { return getObjectValues(encoding, values, orderedMetaData, false, false); } public Object[] getObjectValues(BinaryEncoding encoding, String[] values, Column[] orderedMetaData, boolean useVariableDates, boolean fitToColumn) { if (values != null) { List<Object> list = new ArrayList<Object>(values.length); for (int i = 0; i < values.length; i++) { String value = values[i]; Column column = orderedMetaData.length > i ? orderedMetaData[i] : null; try { if (column != null) { list.add(getObjectValue(value, column, encoding, useVariableDates, fitToColumn)); } } catch (Exception ex) { String valueTrimmed = FormatUtils.abbreviateForLogging(value); log.error("Could not convert a value of {} for column {} of type {}", new Object[] { valueTrimmed, column.getName(), column.getMappedType() }); log.error("", ex); throw new RuntimeException(ex); } } return list.toArray(); } else { return null; } } protected Object getObjectValue(String value, Column column, BinaryEncoding encoding, boolean useVariableDates, boolean fitToColumn) throws DecoderException { Object objectValue = value; int type = column.getMappedTypeCode(); if ((value == null || (getDdlBuilder().getDatabaseInfo().isEmptyStringNulled() && value .equals(""))) && column.isRequired() && column.isOfTextType()) { objectValue = REQUIRED_FIELD_NULL_SUBSTITUTE; } if (value != null) { if (type == Types.DATE || type == Types.TIMESTAMP || type == Types.TIME) { objectValue = parseDate(type, value, useVariableDates); } else if (type == Types.CHAR) { String charValue = value.toString(); if ((StringUtils.isBlank(charValue) && getDdlBuilder().getDatabaseInfo() .isBlankCharColumnSpacePadded()) || (StringUtils.isNotBlank(charValue) && getDdlBuilder().getDatabaseInfo() .isNonBlankCharColumnSpacePadded())) { objectValue = StringUtils .rightPad(value.toString(), column.getSizeAsInt(), ' '); } } else if (type == Types.BIGINT) { objectValue = parseBigInteger(value); } else if (type == Types.INTEGER || type == Types.SMALLINT || type == Types.BIT || type == Types.TINYINT) { objectValue = parseInteger(value); } else if (type == Types.NUMERIC || type == Types.DECIMAL || type == Types.FLOAT || type == Types.DOUBLE || type == Types.REAL) { objectValue = parseBigDecimal(value); } else if (type == Types.BOOLEAN) { objectValue = value.equals("1") ? Boolean.TRUE : Boolean.FALSE; } else if (!(column.getJdbcTypeName() != null && column.getJdbcTypeName().toUpperCase() .contains(TypeMap.GEOMETRY)) && !(column.getJdbcTypeName() != null && column.getJdbcTypeName().toUpperCase() .contains(TypeMap.GEOGRAPHY)) && (type == Types.BLOB || type == Types.LONGVARBINARY || type == Types.BINARY || type == Types.VARBINARY || // SQLServer ntext type type == -10)) { if (encoding == BinaryEncoding.NONE) { objectValue = value.getBytes(); } else if (encoding == BinaryEncoding.BASE64) { objectValue = Base64.decodeBase64(value.getBytes()); } else if (encoding == BinaryEncoding.HEX) { objectValue = Hex.decodeHex(value.toCharArray()); } } else if (type == Types.ARRAY) { objectValue = createArray(column, value); } } if (objectValue instanceof String) { String stringValue = cleanTextForTextBasedColumns((String) objectValue); int size = column.getSizeAsInt(); if (fitToColumn && size > 0 && stringValue.length() > size) { stringValue = stringValue.substring(0, size); } objectValue = stringValue; } return objectValue; } protected Object parseBigDecimal(String value) { /* * The number will have either one period or one comma for the decimal * point, but we need a period */ value = cleanNumber(value); return new BigDecimal(value.replace(',', '.')); } protected Object parseBigInteger(String value) { try { value = cleanNumber(value); return new Long(value.trim()); } catch (NumberFormatException ex) { return new BigDecimal(value.replace(',', '.')).toBigInteger(); } } protected Object parseInteger(String value) { try { value = cleanNumber(value); return Integer.parseInt(value); } catch (NumberFormatException ex) { return new BigInteger(value); } } protected String cleanNumber(String value) { value = value.trim(); if (value.equalsIgnoreCase("true")) { return "1"; } else if (value.equalsIgnoreCase("false")) { return "0"; } else { return value; } } // TODO: this should be AbstractDdlBuilder.getInsertSql(Table table, // Map<String, Object> columnValues, boolean genPlaceholders) public String[] getStringValues(BinaryEncoding encoding, Column[] metaData, Row row, boolean useVariableDates, boolean indexByPosition) { String[] values = new String[metaData.length]; Set<String> keys = row.keySet(); int i = 0; for (String key : keys) { Column column = metaData[i]; String name = indexByPosition ? key : column.getName(); int type = column.getJdbcTypeCode(); if (row.get(name) != null) { if (type == Types.BOOLEAN || type == Types.BIT) { values[i] = row.getBoolean(name) ? "1" : "0"; } else if (column.isOfNumericType()) { values[i] = row.getString(name); } else if (!column.isTimestampWithTimezone() && (type == Types.DATE || type == Types.TIMESTAMP || type == Types.TIME)) { values[i] = getDateTimeStringValue(name, type, row, useVariableDates); } else if (column.isOfBinaryType()) { byte[] bytes = row.getBytes(name); if (encoding == BinaryEncoding.NONE) { values[i] = row.getString(name); } else if (encoding == BinaryEncoding.BASE64) { values[i] = new String(Base64.encodeBase64(bytes)); } else if (encoding == BinaryEncoding.HEX) { values[i] = new String(Hex.encodeHex(bytes)); } } else { values[i] = row.getString(name); } } i++; } return values; } protected String getDateTimeStringValue(String name, int type, Row row, boolean useVariableDates) { Object dateObj = row.get(name); if (dateObj instanceof String) { return (String) dateObj; } else { Date date = row.getDateTime(name); if (useVariableDates) { long diff = date.getTime() - System.currentTimeMillis(); return "${curdate" + diff + "}"; } else { return FormatUtils.TIMESTAMP_FORMATTER.format(date); } } } public Map<String, String> getSqlScriptReplacementTokens() { return null; } public String scrubSql(String sql) { Map<String, String> replacementTokens = getSqlScriptReplacementTokens(); if (replacementTokens != null) { return FormatUtils.replaceTokens(sql, replacementTokens, false).trim(); } else { return sql; } } protected Array createArray(Column column, final String value) { return null; } protected String cleanTextForTextBasedColumns(String text) { return text; } public java.util.Date parseDate(int type, String value, boolean useVariableDates) { if (StringUtils.isNotBlank(value)) { try { boolean useTimestamp = (type == Types.TIMESTAMP) || (type == Types.DATE && getDdlBuilder().getDatabaseInfo() .isDateOverridesToTimestamp()); if (useVariableDates && value.startsWith("${curdate")) { long time = Long.parseLong(value.substring(10, value.length() - 1)); if (value.substring(9, 10).equals("-")) { time *= -1L; } time += System.currentTimeMillis(); if (useTimestamp) { return new Timestamp(time); } return new Date(time); } else { if (useTimestamp) { return parseTimestamp(type, value); } else if (type == Types.TIME) { if (value.indexOf(".") == 8) { /* * Firebird (at least) captures fractional seconds * in time fields which need to be parsed by * Timestamp.valueOf */ return Timestamp.valueOf("1970-01-01 " + value); } else { return FormatUtils.parseDate(value, FormatUtils.TIME_PATTERNS); } } else { return FormatUtils.parseDate(value, FormatUtils.TIMESTAMP_PATTERNS); } } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } else { return null; } } public Table makeAllColumnsPrimaryKeys(Table table) { Table result = table.copy(); for (Column column : result.getColumns()) { if (!isLob(column.getMappedTypeCode())) { column.setPrimaryKey(true); } } return result; } public boolean isLob(int type) { return isClob(type) || isBlob(type); } public boolean isClob(int type) { return type == Types.CLOB || type == Types.LONGVARCHAR || type == ColumnTypes.LONGNVARCHAR; } public boolean isBlob(int type) { return type == Types.BLOB || type == Types.LONGVARBINARY || type == -10; } public List<Column> getLobColumns(Table table) { List<Column> lobColumns = new ArrayList<Column>(1); Column[] allColumns = table.getColumns(); for (Column column : allColumns) { if (isLob(column.getMappedTypeCode())) { lobColumns.add(column); } } return lobColumns; } public void setMetadataIgnoreCase(boolean metadataIgnoreCase) { this.metadataIgnoreCase = metadataIgnoreCase; } public boolean isMetadataIgnoreCase() { return metadataIgnoreCase; } public boolean isStoresLowerCaseIdentifiers() { if (storesLowerCaseIdentifiers == null) { storesLowerCaseIdentifiers = getSqlTemplate().isStoresLowerCaseIdentifiers(); } return storesLowerCaseIdentifiers; } public boolean isStoresMixedCaseQuotedIdentifiers() { if (storesMixedCaseIdentifiers == null) { storesMixedCaseIdentifiers = getSqlTemplate().isStoresMixedCaseQuotedIdentifiers(); } return storesMixedCaseIdentifiers; } public boolean isStoresUpperCaseIdentifiers() { if (storesUpperCaseIdentifiers == null) { storesUpperCaseIdentifiers = getSqlTemplate().isStoresUpperCaseIdentifiers(); } return storesUpperCaseIdentifiers; } public Database readDatabaseFromXml(String filePath, boolean alterCaseToMatchDatabaseDefaultCase) { InputStream is = null; try { File file = new File(filePath); if (file.exists()) { try { is = new FileInputStream(file); } catch (FileNotFoundException e) { throw new IoException(e); } } else { is = AbstractDatabasePlatform.class.getResourceAsStream(filePath); } if (is != null) { return readDatabaseFromXml(is, alterCaseToMatchDatabaseDefaultCase); } else { throw new IoException("Could not find the file: %s", filePath); } } finally { IOUtils.closeQuietly(is); } } public void prefixDatabase(String prefix, Database targetTables) { try { if (StringUtils.isNotBlank(prefix) && !prefix.endsWith("_")) { prefix = prefix + "_"; } Table[] tables = targetTables.getTables(); boolean storesUpperCaseIdentifiers = isStoresUpperCaseIdentifiers(); for (Table table : tables) { String name = String.format("%s%s", prefix, table.getName()); table.setName(storesUpperCaseIdentifiers ? name.toUpperCase() : name.toLowerCase()); prefixForeignKeys(table, prefix, storesUpperCaseIdentifiers); prefixIndexes(table, prefix, storesUpperCaseIdentifiers); prefixColumnNames(table, storesUpperCaseIdentifiers); } } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } protected void prefixColumnNames(Table table, boolean storesUpperCaseIdentifiers) { Column[] columns = table.getColumns(); for (Column column : columns) { column.setName(storesUpperCaseIdentifiers ? column.getName().toUpperCase() : column .getName().toLowerCase()); } } protected void prefixForeignKeys(Table table, String tablePrefix, boolean storesUpperCaseIdentifiers) throws CloneNotSupportedException { ForeignKey[] keys = table.getForeignKeys(); for (ForeignKey key : keys) { String prefixedName = tablePrefix + key.getForeignTableName(); prefixedName = storesUpperCaseIdentifiers ? prefixedName.toUpperCase() : prefixedName .toLowerCase(); key.setForeignTableName(prefixedName); String keyName = tablePrefix + key.getName(); keyName = storesUpperCaseIdentifiers ? keyName.toUpperCase() : keyName.toLowerCase(); key.setName(keyName); Reference[] refs = key.getReferences(); for (Reference reference : refs) { reference.setForeignColumnName(storesUpperCaseIdentifiers ? reference .getForeignColumnName().toUpperCase() : reference.getForeignColumnName() .toLowerCase()); reference.setLocalColumnName(storesUpperCaseIdentifiers ? reference .getLocalColumnName().toUpperCase() : reference.getLocalColumnName() .toLowerCase()); } } } protected void prefixIndexes(Table table, String tablePrefix, boolean storesUpperCaseIdentifiers) throws CloneNotSupportedException { IIndex[] indexes = table.getIndices(); if (indexes != null) { for (IIndex index : indexes) { String prefixedName = tablePrefix + index.getName(); prefixedName = storesUpperCaseIdentifiers ? prefixedName.toUpperCase() : prefixedName.toLowerCase(); index.setName(prefixedName); } } } public void alterCaseToMatchDatabaseDefaultCase(Database database) { Table[] tables = database.getTables(); for (Table table : tables) { alterCaseToMatchDatabaseDefaultCase(table); } } public String[] alterCaseToMatchDatabaseDefaultCase(String[] values) { String[] newValues = new String[values.length]; for (int i = 0; i < values.length; i++) { newValues[i] = alterCaseToMatchDatabaseDefaultCase(values[i]); } return newValues; } public String alterCaseToMatchDatabaseDefaultCase(String value) { if (StringUtils.isNotBlank(value)) { boolean storesUpperCase = isStoresUpperCaseIdentifiers(); if (!FormatUtils.isMixedCase(value)) { value = storesUpperCase ? value.toUpperCase() : value.toLowerCase(); } } return value; } public void alterCaseToMatchDatabaseDefaultCase(Table... tables) { for (Table table : tables) { alterCaseToMatchDatabaseDefaultCase(table); } } public void alterCaseToMatchDatabaseDefaultCase(Table table) { table.setName(alterCaseToMatchDatabaseDefaultCase(table.getName())); Column[] columns = table.getColumns(); for (Column column : columns) { column.setName(alterCaseToMatchDatabaseDefaultCase(column.getName())); } IIndex[] indexes = table.getIndices(); for (IIndex index : indexes) { index.setName(alterCaseToMatchDatabaseDefaultCase(index.getName())); IndexColumn[] indexColumns = index.getColumns(); for (IndexColumn indexColumn : indexColumns) { indexColumn.setName(alterCaseToMatchDatabaseDefaultCase(indexColumn.getName())); } } ForeignKey[] fks = table.getForeignKeys(); for (ForeignKey foreignKey : fks) { foreignKey.setName(alterCaseToMatchDatabaseDefaultCase(foreignKey.getName())); foreignKey.setForeignTableName(alterCaseToMatchDatabaseDefaultCase(foreignKey.getForeignTableName())); Reference[] references = foreignKey.getReferences(); for (Reference reference : references) { reference.setForeignColumnName(alterCaseToMatchDatabaseDefaultCase(reference.getForeignColumnName())); reference.setLocalColumnName(alterCaseToMatchDatabaseDefaultCase(reference.getLocalColumnName())); } } } public Database readDatabaseFromXml(InputStream is, boolean alterCaseToMatchDatabaseDefaultCase) { InputStreamReader reader = new InputStreamReader(is); Database database = DatabaseXmlUtil.read(reader); if (alterCaseToMatchDatabaseDefaultCase) { alterCaseToMatchDatabaseDefaultCase(database); } return database; } public boolean canColumnBeUsedInWhereClause(Column column) { return true; } public java.util.Date parseTimestamp(int type, String value) { try { return Timestamp.valueOf(value); } catch (IllegalArgumentException ex) { try { return FormatUtils.parseDate(value, FormatUtils.TIMESTAMP_PATTERNS); } catch (Exception e) { int split = value.lastIndexOf(" "); String datetime = value.substring(0, split).trim(); String timezone = value.substring(split).trim(); try { return Timestamp.valueOf(datetime); // Try it again without the timezone component. } catch (IllegalArgumentException ex2) { return FormatUtils.parseDate(datetime, FormatUtils.TIMESTAMP_PATTERNS, getTimeZone(timezone)); } } } } public TimeZone getTimeZone(String value) { TimeZone tz = TimeZone.getTimeZone("GMT" + value); // try as an offset. ("-05:00") if (tz.getRawOffset() == 0) { tz = TimeZone.getTimeZone(value); // try as a raw code. e.g. "EST" } return tz; } @Override public void makePlatformSpecific(Database database) { Table[] tables = database.getTables(); for (Table table : tables) { for (Column autoIncrementColumn : table.getAutoIncrementColumns()) { if (!autoIncrementColumn.isPrimaryKey() && !getDatabaseInfo().isNonPKIdentityColumnsSupported()) { log.info("Removing auto increment from table " + table.getName() + " for column " + autoIncrementColumn.getName() + " since it was not part of primary key and not supported on this database based on nonPKIdentityColumnsSupported."); autoIncrementColumn.setAutoIncrement(false); } } } } }