use of liquibase.database.AbstractJdbcDatabase in project liquibase by liquibase.
the class MissingUniqueConstraintChangeGenerator method alreadyExists.
private boolean alreadyExists(Index backingIndex, Database comparisonDatabase, DiffOutputControl control) {
boolean found = false;
try {
String catalogName = null;
String schemaName = null;
if (control.getIncludeCatalog()) {
catalogName = backingIndex.getTable().getSchema().getCatalogName();
}
if (control.getIncludeSchema()) {
schemaName = backingIndex.getTable().getSchema().getName();
}
Index backingIndexCopy = new Index(backingIndex.getName(), catalogName, schemaName, backingIndex.getTable().getName());
for (Column column : backingIndex.getColumns()) {
backingIndexCopy.addColumn(column);
}
// get the diffResult from the database object
// This was set from DiffToChangeLog#generateChangeSets() so that we can access it here
DiffResult diffResult = null;
if (comparisonDatabase instanceof AbstractJdbcDatabase) {
diffResult = (DiffResult) ((AbstractJdbcDatabase) comparisonDatabase).get("diffResult");
}
if (diffResult != null) {
// check against the snapshot (better performance)
Index foundIndex = diffResult.getComparisonSnapshot().get(backingIndexCopy);
found = foundIndex != null;
} else {
// go to the db to find out
found = SnapshotGeneratorFactory.getInstance().has(backingIndexCopy, comparisonDatabase);
}
} catch (Exception e) {
Scope.getCurrentScope().getLog(getClass()).warning("Error checking for backing index " + backingIndex.toString() + ": " + e.getMessage(), e);
}
return found;
}
use of liquibase.database.AbstractJdbcDatabase in project liquibase by liquibase.
the class ForeignKeySnapshotGenerator method snapshotObject.
@Override
protected DatabaseObject snapshotObject(DatabaseObject example, DatabaseSnapshot snapshot) throws DatabaseException, InvalidExampleException {
Database database = snapshot.getDatabase();
List<CachedRow> importedKeyMetadataResultSet;
try {
Table fkTable = ((ForeignKey) example).getForeignKeyTable();
String searchCatalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(fkTable.getSchema());
String searchSchema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(fkTable.getSchema());
String searchTableName = database.correctObjectName(fkTable.getName(), Table.class);
importedKeyMetadataResultSet = ((JdbcDatabaseSnapshot) snapshot).getMetaDataFromCache().getForeignKeys(searchCatalog, searchSchema, searchTableName, example.getName());
ForeignKey foreignKey = null;
for (CachedRow row : importedKeyMetadataResultSet) {
String fk_name = cleanNameFromDatabase(row.getString("FK_NAME"), database);
if (snapshot.getDatabase().isCaseSensitive()) {
if (!fk_name.equals(example.getName())) {
continue;
} else if (!fk_name.equalsIgnoreCase(example.getName())) {
continue;
}
}
if (foreignKey == null) {
foreignKey = new ForeignKey();
}
foreignKey.setName(fk_name);
String fkTableCatalog = cleanNameFromDatabase(row.getString(METADATA_FKTABLE_CAT), database);
String fkTableSchema = cleanNameFromDatabase(row.getString(METADATA_FKTABLE_SCHEM), database);
String fkTableName = cleanNameFromDatabase(row.getString(METADATA_FKTABLE_NAME), database);
Table foreignKeyTable = new Table().setName(fkTableName);
foreignKeyTable.setSchema(new Schema(new Catalog(fkTableCatalog), fkTableSchema));
foreignKey.setForeignKeyTable(foreignKeyTable);
Column fkColumn = new Column(cleanNameFromDatabase(row.getString(METADATA_FKCOLUMN_NAME), database)).setRelation(foreignKeyTable);
boolean alreadyAdded = false;
for (Column existing : foreignKey.getForeignKeyColumns()) {
if (DatabaseObjectComparatorFactory.getInstance().isSameObject(existing, fkColumn, snapshot.getSchemaComparisons(), database)) {
// already added. One is probably an alias
alreadyAdded = true;
}
}
if (alreadyAdded) {
break;
}
CatalogAndSchema pkTableSchema = ((AbstractJdbcDatabase) database).getSchemaFromJdbcInfo(row.getString(METADATA_PKTABLE_CAT), row.getString(METADATA_PKTABLE_SCHEM));
Table tempPkTable = (Table) new Table().setName(row.getString(METADATA_PKTABLE_NAME)).setSchema(new Schema(pkTableSchema.getCatalogName(), pkTableSchema.getSchemaName()));
foreignKey.setPrimaryKeyTable(tempPkTable);
Column pkColumn = new Column(cleanNameFromDatabase(row.getString(METADATA_PKCOLUMN_NAME), database)).setRelation(tempPkTable);
foreignKey.addForeignKeyColumn(fkColumn);
foreignKey.addPrimaryKeyColumn(pkColumn);
// DB2 on z/OS doesn't support ON UPDATE
if (!(database instanceof Db2zDatabase)) {
ForeignKeyConstraintType updateRule = convertToForeignKeyConstraintType(row.getInt(METADATA_UPDATE_RULE), database);
foreignKey.setUpdateRule(updateRule);
}
ForeignKeyConstraintType deleteRule = convertToForeignKeyConstraintType(row.getInt(METADATA_DELETE_RULE), database);
foreignKey.setDeleteRule(deleteRule);
short deferrability = row.getShort(METADATA_DEFERRABILITY);
// it should be set to DatabaseMetaData.importedKeyNotDeferrable(7)
if ((deferrability == 0) || (deferrability == DatabaseMetaData.importedKeyNotDeferrable)) {
foreignKey.setDeferrable(false);
foreignKey.setInitiallyDeferred(false);
} else if (deferrability == DatabaseMetaData.importedKeyInitiallyDeferred) {
foreignKey.setDeferrable(true);
foreignKey.setInitiallyDeferred(true);
} else if (deferrability == DatabaseMetaData.importedKeyInitiallyImmediate) {
foreignKey.setDeferrable(true);
foreignKey.setInitiallyDeferred(false);
} else {
throw new RuntimeException("Unknown deferrability result: " + deferrability);
}
setValidateOptionIfAvailable(database, foreignKey, row);
Index exampleIndex = new Index().setRelation(foreignKey.getForeignKeyTable());
exampleIndex.getColumns().addAll(foreignKey.getForeignKeyColumns());
exampleIndex.addAssociatedWith(Index.MARK_FOREIGN_KEY);
foreignKey.setBackingIndex(exampleIndex);
}
if (snapshot.get(ForeignKey.class).contains(foreignKey)) {
return null;
}
return foreignKey;
} catch (Exception e) {
throw new DatabaseException(e);
}
}
use of liquibase.database.AbstractJdbcDatabase in project liquibase by liquibase.
the class ForeignKeySnapshotGenerator method addTo.
// public Boolean has(DatabaseObject example, DatabaseSnapshot snapshot, SnapshotGeneratorChain chain) throws DatabaseException {
// if (example instanceof ForeignKey) {
// Database database = snapshot.getDatabase();
// String searchCatalog = database.getJdbcCatalogName(example.getSchema());
// String searchSchema = database.getJdbcSchemaName(example.getSchema());
// String searchTableName = null;
// if (((ForeignKey) example).getForeignKeyTable() != null) {
// searchTableName = ((ForeignKey) example).getForeignKeyTable().getName();
// }
// String fkName = example.getName();
//
// ResultSet rs = null;
// try {
// rs = getMetaDataFromCache(database).getForeignKeys(searchCatalog, searchSchema, searchTableName);
// while (rs.next()) {
// if (fkName.equals(rs.getString("FK_NAME"))) {
// return true;
// }
// }
// return false;
// } catch (SQLException e) {
// throw new DatabaseException(e);
// } finally {
// if (rs != null) {
// try {
// rs.close();
// } catch (SQLException ignored) { }
// }
// }
// } else {
// return chain.has(example, snapshot);
// }
// }
@Override
protected void addTo(DatabaseObject foundObject, DatabaseSnapshot snapshot) throws DatabaseException, InvalidExampleException {
if (!snapshot.getSnapshotControl().shouldInclude(ForeignKey.class)) {
return;
}
if (foundObject instanceof Table) {
Table table = (Table) foundObject;
Database database = snapshot.getDatabase();
Schema schema;
schema = table.getSchema();
Set<String> seenFks = new HashSet<>();
List<CachedRow> importedKeyMetadataResultSet;
try {
importedKeyMetadataResultSet = ((JdbcDatabaseSnapshot) snapshot).getMetaDataFromCache().getForeignKeys(((AbstractJdbcDatabase) database).getJdbcCatalogName(schema), ((AbstractJdbcDatabase) database).getJdbcSchemaName(schema), database.correctObjectName(table.getName(), Table.class), null);
for (CachedRow row : importedKeyMetadataResultSet) {
ForeignKey fk = new ForeignKey().setName(row.getString("FK_NAME")).setForeignKeyTable(table);
if (seenFks.add(fk.getName())) {
table.getOutgoingForeignKeys().add(fk);
}
}
} catch (Exception e) {
throw new DatabaseException(e);
}
}
}
use of liquibase.database.AbstractJdbcDatabase in project liquibase by liquibase.
the class IndexSnapshotGenerator method snapshotObject.
@Override
protected DatabaseObject snapshotObject(DatabaseObject example, DatabaseSnapshot snapshot) throws DatabaseException, InvalidExampleException {
Database database = snapshot.getDatabase();
Relation exampleIndex = ((Index) example).getRelation();
String tableName = null;
Schema schema = null;
if (exampleIndex != null) {
tableName = exampleIndex.getName();
schema = exampleIndex.getSchema();
}
if (schema == null) {
schema = new Schema(database.getDefaultCatalogName(), database.getDefaultSchemaName());
}
for (int i = 0; i < ((Index) example).getColumns().size(); i++) {
((Index) example).getColumns().set(i, ((Index) example).getColumns().get(i));
}
String exampleName = example.getName();
if (exampleName != null) {
exampleName = database.correctObjectName(exampleName, Index.class);
}
Map<String, Index> foundIndexes = new HashMap<>();
JdbcDatabaseSnapshot.CachingDatabaseMetaData databaseMetaData = null;
List<CachedRow> rs = null;
try {
databaseMetaData = ((JdbcDatabaseSnapshot) snapshot).getMetaDataFromCache();
rs = databaseMetaData.getIndexInfo(((AbstractJdbcDatabase) database).getJdbcCatalogName(schema), ((AbstractJdbcDatabase) database).getJdbcSchemaName(schema), tableName, exampleName);
for (CachedRow row : rs) {
String rawIndexName = row.getString("INDEX_NAME");
String indexName = cleanNameFromDatabase(rawIndexName, database);
String correctedIndexName = database.correctObjectName(indexName, Index.class);
if (indexName == null) {
continue;
}
if ((exampleName != null) && !exampleName.equals(correctedIndexName)) {
continue;
}
/*
* TODO Informix generates indexnames with a leading blank if no name given.
* An identifier with a leading blank is not allowed.
* So here is it replaced.
*/
if ((database instanceof InformixDatabase) && indexName.startsWith(" ")) {
// suppress creation of generated_index records
continue;
}
short type = row.getShort("TYPE");
Boolean nonUnique = row.getBoolean("NON_UNIQUE");
if (nonUnique == null) {
nonUnique = true;
}
String columnName = cleanNameFromDatabase(row.getString("COLUMN_NAME"), database);
short position = row.getShort("ORDINAL_POSITION");
String definition = StringUtil.trimToNull(row.getString("FILTER_CONDITION"));
if (definition != null) {
if (!(database instanceof OracleDatabase)) {
// TODO: this replaceAll code has been there for a long time but we don't know why. Investigate when it is ever needed and modify it to be smarter
definition = definition.replaceAll("\"", "");
}
}
if ((columnName == null) && (definition == null)) {
// nothing to index, not sure why these come through sometimes
continue;
}
if (!(database instanceof H2Database) && type == DatabaseMetaData.tableIndexStatistic) {
continue;
}
/*
* In Oracle database, ALL_IND_COLUMNS/ALL_IND_EXPRESSIONS (the views from which we bulk-fetch the
* column definitions for a given index) can show a strange behaviour if an index column consists of
* a regular table column, but its sort order is DESC(ending). In this case, we get something like
* this (example values):
* ALL_IND_COLUMNS.COLUMN_NAME=SYS_NC00006$
* ALL_IND_EXPRESSIONS.COLUMN_EXPRESSIONS="COLUMN1FORDESC"
* Note that the quote characters (") are part of the actual column value!
* Our strategy here is: If the expression would be a valid Oracle identifier, but not a valid Oracle
* function name, then we assume it is the name of a regular column.
*/
if ((database instanceof OracleDatabase) && (definition != null) && (columnName != null)) {
String potentialColumnExpression = definition.replaceFirst("^\"?(.*?)\"?$", "$1");
OracleDatabase oracle = (OracleDatabase) database;
if (oracle.isValidOracleIdentifier(potentialColumnExpression, Index.class) && (!oracle.isFunction(potentialColumnExpression))) {
columnName = potentialColumnExpression;
definition = null;
}
}
// Have we already seen/found this index? If not, let's read its properties!
Index returnIndex = foundIndexes.get(correctedIndexName);
if (returnIndex == null) {
returnIndex = new Index();
Relation relation = new Table();
if ("V".equals(row.getString("INTERNAL_OBJECT_TYPE"))) {
relation = new View();
}
returnIndex.setRelation(relation.setName(row.getString("TABLE_NAME")).setSchema(schema));
returnIndex.setName(indexName);
returnIndex.setUnique(!nonUnique);
String tablespaceName = row.getString("TABLESPACE_NAME");
if ((tablespaceName != null) && database.supportsTablespaces()) {
returnIndex.setTablespace(tablespaceName);
}
if (type == DatabaseMetaData.tableIndexClustered) {
returnIndex.setClustered(true);
} else if (database instanceof MSSQLDatabase) {
returnIndex.setClustered(false);
}
if (database instanceof MSSQLDatabase) {
Boolean recompute = (Boolean) row.get("NO_RECOMPUTE");
if (recompute != null) {
recompute = !recompute;
}
returnIndex.setAttribute("padIndex", row.get("IS_PADDED"));
returnIndex.setAttribute("fillFactor", row.get("FILL_FACTOR"));
returnIndex.setAttribute("ignoreDuplicateKeys", row.get("IGNORE_DUP_KEY"));
returnIndex.setAttribute("recomputeStatistics", recompute);
returnIndex.setAttribute("incrementalStatistics", row.get("IS_INCREMENTAL"));
returnIndex.setAttribute("allowRowLocks", row.get("ALLOW_ROW_LOCKS"));
returnIndex.setAttribute("allowPageLocks", row.get("ALLOW_PAGE_LOCKS"));
}
foundIndexes.put(correctedIndexName, returnIndex);
}
if ((database instanceof MSSQLDatabase) && (Boolean) row.get("IS_INCLUDED_COLUMN")) {
List<String> includedColumns = returnIndex.getAttribute("includedColumns", List.class);
if (includedColumns == null) {
includedColumns = new ArrayList<>();
returnIndex.setAttribute("includedColumns", includedColumns);
}
includedColumns.add(columnName);
} else {
if (position != 0) {
// if really a column, position is 1-based.
for (int i = returnIndex.getColumns().size(); i < position; i++) {
returnIndex.getColumns().add(null);
}
// or is it a computed expression (definition != null)
if (definition == null) {
String ascOrDesc;
if (database instanceof Db2zDatabase) {
ascOrDesc = row.getString("ORDER");
} else {
ascOrDesc = row.getString("ASC_OR_DESC");
}
Boolean descending = "D".equals(ascOrDesc) ? Boolean.TRUE : ("A".equals(ascOrDesc) ? Boolean.FALSE : null);
returnIndex.getColumns().set(position - 1, new Column(columnName).setDescending(descending).setRelation(returnIndex.getRelation()));
} else {
returnIndex.getColumns().set(position - 1, new Column().setRelation(returnIndex.getRelation()).setName(definition, true));
}
}
}
}
} catch (Exception e) {
throw new DatabaseException(e);
}
if (exampleName != null) {
Index index = foundIndexes.get(exampleName);
return index;
} else {
// prefer clustered version of the index
List<Index> nonClusteredIndexes = new ArrayList<>();
for (Index index : foundIndexes.values()) {
if (DatabaseObjectComparatorFactory.getInstance().isSameObject(index.getRelation(), exampleIndex, snapshot.getSchemaComparisons(), database)) {
boolean actuallyMatches = false;
if (database.isCaseSensitive()) {
if (index.getColumnNames().equals(((Index) example).getColumnNames())) {
actuallyMatches = true;
}
} else {
if (index.getColumnNames().equalsIgnoreCase(((Index) example).getColumnNames())) {
actuallyMatches = true;
}
}
if (actuallyMatches) {
if ((index.getClustered() != null) && index.getClustered()) {
return finalizeIndex(schema, tableName, index, snapshot);
} else {
nonClusteredIndexes.add(index);
}
}
}
}
if (!nonClusteredIndexes.isEmpty()) {
return finalizeIndex(schema, tableName, nonClusteredIndexes.get(0), snapshot);
}
return null;
}
}
use of liquibase.database.AbstractJdbcDatabase in project liquibase by liquibase.
the class ViewSnapshotGenerator method addTo.
@Override
protected void addTo(DatabaseObject foundObject, DatabaseSnapshot snapshot) throws DatabaseException, InvalidExampleException {
if (!snapshot.getSnapshotControl().shouldInclude(View.class)) {
return;
}
if (foundObject instanceof Schema) {
Schema schema = (Schema) foundObject;
Database database = snapshot.getDatabase();
List<CachedRow> viewsMetadataRs = null;
try {
viewsMetadataRs = ((JdbcDatabaseSnapshot) snapshot).getMetaDataFromCache().getViews(((AbstractJdbcDatabase) database).getJdbcCatalogName(schema), ((AbstractJdbcDatabase) database).getJdbcSchemaName(schema), null);
for (CachedRow row : viewsMetadataRs) {
CatalogAndSchema catalogAndSchema = ((AbstractJdbcDatabase) database).getSchemaFromJdbcInfo(row.getString("TABLE_CAT"), row.getString("TABLE_SCHEM"));
View view = new View();
view.setName(row.getString("TABLE_NAME"));
view.setSchema(new Schema(catalogAndSchema.getCatalogName(), catalogAndSchema.getSchemaName()));
view.setRemarks(row.getString("REMARKS"));
String definition = StringUtil.standardizeLineEndings(row.getString("OBJECT_BODY"));
view.setDefinition(definition);
if (database instanceof OracleDatabase) {
view.setAttribute("editioning", "Y".equals(row.getString("EDITIONING_VIEW")));
}
schema.addDatabaseObject(view);
}
} catch (SQLException e) {
throw new DatabaseException(e);
}
}
}
Aggregations