use of liquibase.structure.DatabaseObject in project liquibase by liquibase.
the class AbstractJdbcDatabase method dropDatabaseObjects.
@Override
public void dropDatabaseObjects(final CatalogAndSchema schemaToDrop) throws LiquibaseException {
ObjectQuotingStrategy currentStrategy = this.getObjectQuotingStrategy();
this.setObjectQuotingStrategy(ObjectQuotingStrategy.QUOTE_ALL_OBJECTS);
try {
DatabaseSnapshot snapshot;
try {
final SnapshotControl snapshotControl = new SnapshotControl(this);
final Set<Class<? extends DatabaseObject>> typesToInclude = snapshotControl.getTypesToInclude();
// We do not need to remove indexes and primary/unique keys explicitly. They should be removed
// as part of tables.
typesToInclude.remove(Index.class);
typesToInclude.remove(PrimaryKey.class);
typesToInclude.remove(UniqueConstraint.class);
if (supportsForeignKeyDisable() || getShortName().equals("postgresql")) {
// We do not remove ForeignKey because they will be disabled and removed as parts of tables.
// Postgress is treated as if we can disable foreign keys because we can't drop
// the foreign keys of a partitioned table, as discovered in
// https://github.com/liquibase/liquibase/issues/1212
typesToInclude.remove(ForeignKey.class);
}
final long createSnapshotStarted = System.currentTimeMillis();
snapshot = SnapshotGeneratorFactory.getInstance().createSnapshot(schemaToDrop, this, snapshotControl);
Scope.getCurrentScope().getLog(getClass()).fine(String.format("Database snapshot generated in %d ms. Snapshot includes: %s", System.currentTimeMillis() - createSnapshotStarted, typesToInclude));
} catch (LiquibaseException e) {
throw new UnexpectedLiquibaseException(e);
}
final long changeSetStarted = System.currentTimeMillis();
CompareControl compareControl = new CompareControl(new CompareControl.SchemaComparison[] { new CompareControl.SchemaComparison(CatalogAndSchema.DEFAULT, schemaToDrop) }, snapshot.getSnapshotControl().getTypesToInclude());
DiffResult diffResult = DiffGeneratorFactory.getInstance().compare(new EmptyDatabaseSnapshot(this), snapshot, compareControl);
List<ChangeSet> changeSets = new DiffToChangeLog(diffResult, new DiffOutputControl(true, true, false, null).addIncludedSchema(schemaToDrop)).generateChangeSets();
Scope.getCurrentScope().getLog(getClass()).fine(String.format("ChangeSet to Remove Database Objects generated in %d ms.", System.currentTimeMillis() - changeSetStarted));
boolean previousAutoCommit = this.getAutoCommitMode();
// clear out currently executed statements
this.commit();
// some DDL doesn't work in autocommit mode
this.setAutoCommit(false);
final boolean reEnableFK = supportsForeignKeyDisable() && disableForeignKeyChecks();
try {
for (ChangeSet changeSet : changeSets) {
changeSet.setFailOnError(false);
for (Change change : changeSet.getChanges()) {
if (change instanceof DropTableChange) {
((DropTableChange) change).setCascadeConstraints(true);
}
SqlStatement[] sqlStatements = change.generateStatements(this);
for (SqlStatement statement : sqlStatements) {
Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).execute(statement);
}
}
this.commit();
}
} finally {
if (reEnableFK) {
enableForeignKeyChecks();
}
}
ChangeLogHistoryServiceFactory.getInstance().getChangeLogService(this).destroy();
LockServiceFactory.getInstance().getLockService(this).destroy();
this.setAutoCommit(previousAutoCommit);
Scope.getCurrentScope().getLog(getClass()).info(String.format("Successfully deleted all supported object types in schema %s.", schemaToDrop.toString()));
} finally {
this.setObjectQuotingStrategy(currentStrategy);
this.commit();
}
}
use of liquibase.structure.DatabaseObject in project liquibase by liquibase.
the class DiffToChangeLog method generateChangeSets.
public List<ChangeSet> generateChangeSets() {
final ChangeGeneratorFactory changeGeneratorFactory = ChangeGeneratorFactory.getInstance();
DatabaseObjectComparator comparator = new DatabaseObjectComparator();
String created = null;
if (GlobalConfiguration.GENERATE_CHANGESET_CREATED_VALUES.getCurrentValue()) {
created = new SimpleDateFormat("yyyy-MM-dd HH:mmZ").format(new Date());
}
List<Class<? extends DatabaseObject>> types = getOrderedOutputTypes(ChangedObjectChangeGenerator.class);
List<ChangeSet> updateChangeSets = new ArrayList<ChangeSet>();
// Keep a reference to DiffResult in the comparision database so that it can be retrieved later
// This is to avoid changing the MissingObjectChangeGenerator API and still be able to pass the
// initial DiffResult Object which can be used to check for the objects available in the database
// without doing any expensive db calls. Example usage is in MissingUniqueConstraintChangeGenerator#alreadyExists()
Database comparisionDatabase = diffResult.getComparisonSnapshot().getDatabase();
if (comparisionDatabase instanceof AbstractJdbcDatabase) {
((AbstractJdbcDatabase) comparisionDatabase).set("diffResult", diffResult);
}
for (Class<? extends DatabaseObject> type : types) {
ObjectQuotingStrategy quotingStrategy = diffOutputControl.getObjectQuotingStrategy();
for (Map.Entry<? extends DatabaseObject, ObjectDifferences> entry : diffResult.getChangedObjects(type, comparator).entrySet()) {
if (!diffResult.getReferenceSnapshot().getDatabase().isLiquibaseObject(entry.getKey()) && !diffResult.getReferenceSnapshot().getDatabase().isSystemObject(entry.getKey())) {
Change[] changes = changeGeneratorFactory.fixChanged(entry.getKey(), entry.getValue(), diffOutputControl, diffResult.getReferenceSnapshot().getDatabase(), diffResult.getComparisonSnapshot().getDatabase());
addToChangeSets(changes, updateChangeSets, quotingStrategy, created);
}
}
}
types = getOrderedOutputTypes(MissingObjectChangeGenerator.class);
List<DatabaseObject> missingObjects = new ArrayList<DatabaseObject>();
for (Class<? extends DatabaseObject> type : types) {
for (DatabaseObject object : diffResult.getMissingObjects(type, getDbObjectComparator())) {
if (object == null) {
continue;
}
if (!diffResult.getReferenceSnapshot().getDatabase().isLiquibaseObject(object) && !diffResult.getReferenceSnapshot().getDatabase().isSystemObject(object)) {
missingObjects.add(object);
}
}
}
List<ChangeSet> createChangeSets = new ArrayList<ChangeSet>();
for (DatabaseObject object : sortMissingObjects(missingObjects, diffResult.getReferenceSnapshot().getDatabase())) {
ObjectQuotingStrategy quotingStrategy = diffOutputControl.getObjectQuotingStrategy();
Change[] changes = changeGeneratorFactory.fixMissing(object, diffOutputControl, diffResult.getReferenceSnapshot().getDatabase(), diffResult.getComparisonSnapshot().getDatabase());
addToChangeSets(changes, createChangeSets, quotingStrategy, created);
}
List<ChangeSet> deleteChangeSets = new ArrayList<ChangeSet>();
types = getOrderedOutputTypes(UnexpectedObjectChangeGenerator.class);
for (Class<? extends DatabaseObject> type : types) {
ObjectQuotingStrategy quotingStrategy = diffOutputControl.getObjectQuotingStrategy();
for (DatabaseObject object : sortUnexpectedObjects(diffResult.getUnexpectedObjects(type, comparator), diffResult.getReferenceSnapshot().getDatabase())) {
if (!diffResult.getComparisonSnapshot().getDatabase().isLiquibaseObject(object) && !diffResult.getComparisonSnapshot().getDatabase().isSystemObject(object)) {
Change[] changes = changeGeneratorFactory.fixUnexpected(object, diffOutputControl, diffResult.getReferenceSnapshot().getDatabase(), diffResult.getComparisonSnapshot().getDatabase());
addToChangeSets(changes, deleteChangeSets, quotingStrategy, created);
}
}
}
// remove the diffResult from the database object
if (comparisionDatabase instanceof AbstractJdbcDatabase) {
((AbstractJdbcDatabase) comparisionDatabase).set("diffResult", null);
}
List<ChangeSet> changeSets = new ArrayList<ChangeSet>();
changeSets.addAll(createChangeSets);
changeSets.addAll(deleteChangeSets);
changeSets.addAll(updateChangeSets);
return changeSets;
}
use of liquibase.structure.DatabaseObject in project liquibase by liquibase.
the class DiffToChangeLog method sortObjects.
private List<DatabaseObject> sortObjects(final String type, Collection<DatabaseObject> objects, Database database) {
if (!objects.isEmpty() && supportsSortingObjects(database) && (database.getConnection() != null) && !(database.getConnection() instanceof OfflineConnection)) {
List<String> schemas = new ArrayList<>();
CompareControl.SchemaComparison[] schemaComparisons = this.diffOutputControl.getSchemaComparisons();
if (schemaComparisons != null) {
for (CompareControl.SchemaComparison comparison : schemaComparisons) {
String schemaName = comparison.getReferenceSchema().getSchemaName();
if (schemaName == null) {
schemaName = database.getDefaultSchemaName();
}
schemas.add(schemaName);
}
}
if (schemas.isEmpty()) {
schemas.add(database.getDefaultSchemaName());
}
try {
final List<String> dependencyOrder = new ArrayList<>();
DependencyUtil.NodeValueListener<String> nameListener = new DependencyUtil.NodeValueListener<String>() {
@Override
public void evaluating(String nodeValue) {
dependencyOrder.add(nodeValue);
}
};
DependencyUtil.DependencyGraph<String> graph = new DependencyUtil.DependencyGraph<String>(nameListener);
addDependencies(graph, schemas, database);
graph.computeDependencies();
if (!dependencyOrder.isEmpty()) {
final List<DatabaseObject> toSort = new ArrayList<>();
final List<DatabaseObject> toNotSort = new ArrayList<>();
for (DatabaseObject obj : objects) {
if (!(obj instanceof Column)) {
String schemaName = null;
if (obj.getSchema() != null) {
schemaName = obj.getSchema().getName();
}
String name = schemaName + "." + obj.getName();
if (dependencyOrder.contains(name)) {
toSort.add(obj);
} else {
toNotSort.add(obj);
}
} else {
toNotSort.add(obj);
}
}
Collections.sort(toSort, new Comparator<DatabaseObject>() {
@Override
public int compare(DatabaseObject o1, DatabaseObject o2) {
String o1Schema = null;
if (o1.getSchema() != null) {
o1Schema = o1.getSchema().getName();
}
String o2Schema = null;
if (o2.getSchema() != null) {
o2Schema = o2.getSchema().getName();
}
Integer o1Order = dependencyOrder.indexOf(o1Schema + "." + o1.getName());
int o2Order = dependencyOrder.indexOf(o2Schema + "." + o2.getName());
int order = o1Order.compareTo(o2Order);
if ("unexpected".equals(type)) {
order = order * -1;
}
return order;
}
});
toSort.addAll(toNotSort);
return toSort;
}
} catch (DatabaseException e) {
Scope.getCurrentScope().getLog(getClass()).fine("Cannot get object dependencies: " + e.getMessage());
}
}
return new ArrayList<>(objects);
}
use of liquibase.structure.DatabaseObject in project liquibase by liquibase.
the class ChangedViewChangeGenerator method fixChanged.
@Override
public Change[] fixChanged(DatabaseObject changedObject, ObjectDifferences differences, DiffOutputControl control, Database referenceDatabase, final Database comparisonDatabase, ChangeGeneratorChain chain) {
View view = (View) changedObject;
CreateViewChange change = createViewChange();
change.setViewName(view.getName());
change.setReplaceIfExists(true);
if (control.getIncludeCatalog()) {
change.setCatalogName(view.getSchema().getCatalogName());
}
if (control.getIncludeSchema()) {
change.setSchemaName(view.getSchema().getName());
}
String selectQuery = view.getDefinition();
boolean fullDefinitionOverridden = false;
if (selectQuery == null) {
selectQuery = "COULD NOT DETERMINE VIEW QUERY";
} else if ((comparisonDatabase instanceof OracleDatabase) && (view.getColumns() != null) && !view.getColumns().isEmpty()) {
String viewName;
if ((change.getCatalogName() == null) && (change.getSchemaName() == null)) {
viewName = comparisonDatabase.escapeObjectName(change.getViewName(), View.class);
} else {
viewName = comparisonDatabase.escapeViewName(change.getCatalogName(), change.getSchemaName(), change.getViewName());
}
selectQuery = "CREATE OR REPLACE FORCE VIEW " + viewName + " (" + StringUtil.join(view.getColumns(), ", ", new StringUtil.StringUtilFormatter() {
@Override
public String toString(Object obj) {
if ((((Column) obj).getComputed() != null) && ((Column) obj).getComputed()) {
return ((Column) obj).getName();
} else {
return comparisonDatabase.escapeColumnName(null, null, null, ((Column) obj).getName(), false);
}
}
}) + ") AS " + selectQuery;
change.setFullDefinition(true);
fullDefinitionOverridden = true;
}
change.setSelectQuery(selectQuery);
if (!fullDefinitionOverridden) {
change.setFullDefinition(view.getContainsFullDefinition());
}
List<Change> changes = new ArrayList<>();
changes.add(change);
Difference changedRemarks = differences.getDifference("remarks");
if (changedRemarks != null) {
SetTableRemarksChange setRemarksChange = new SetTableRemarksChange();
if (control.getIncludeCatalog()) {
setRemarksChange.setCatalogName(view.getSchema().getCatalogName());
}
if (control.getIncludeSchema()) {
setRemarksChange.setSchemaName(view.getSchema().getName());
}
setRemarksChange.setTableName(view.getName());
setRemarksChange.setRemarks(view.getRemarks());
changes.add(setRemarksChange);
}
return changes.toArray(new Change[changes.size()]);
}
use of liquibase.structure.DatabaseObject in project liquibase by liquibase.
the class MissingDataChangeGenerator method fixMissing.
@Override
public Change[] fixMissing(DatabaseObject missingObject, DiffOutputControl outputControl, Database referenceDatabase, Database comparisionDatabase, ChangeGeneratorChain chain) {
Statement stmt = null;
ResultSet rs = null;
try {
Data data = (Data) missingObject;
Table table = data.getTable();
if (referenceDatabase.isLiquibaseObject(table)) {
return null;
}
String sql = "SELECT * FROM " + referenceDatabase.escapeTableName(table.getSchema().getCatalogName(), table.getSchema().getName(), table.getName());
stmt = ((JdbcConnection) referenceDatabase.getConnection()).createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(1000);
rs = stmt.executeQuery(sql);
List<String> columnNames = new ArrayList<>();
for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
columnNames.add(rs.getMetaData().getColumnName(i + 1));
}
List<Change> changes = new ArrayList<>();
while (rs.next()) {
InsertDataChange change = new InsertDataChange();
if (outputControl.getIncludeCatalog()) {
change.setCatalogName(table.getSchema().getCatalogName());
}
if (outputControl.getIncludeSchema()) {
change.setSchemaName(table.getSchema().getName());
}
change.setTableName(table.getName());
// loop over all columns for this row
for (int i = 0; i < columnNames.size(); i++) {
ColumnConfig column = new ColumnConfig();
column.setName(columnNames.get(i));
Object value = JdbcUtil.getResultSetValue(rs, i + 1);
if (value == null) {
column.setValue(null);
} else if (value instanceof Number) {
column.setValueNumeric((Number) value);
} else if (value instanceof Boolean) {
column.setValueBoolean((Boolean) value);
} else if (value instanceof Date) {
column.setValueDate((Date) value);
} else if (value instanceof byte[]) {
if (referenceDatabase instanceof InformixDatabase) {
column.setValue(new String((byte[]) value, GlobalConfiguration.OUTPUT_FILE_ENCODING.getCurrentValue()));
}
column.setValueComputed(new DatabaseFunction("UNSUPPORTED FOR DIFF: BINARY DATA"));
} else {
// fall back to simple string
column.setValue(value.toString());
}
change.addColumn(column);
}
// for each row, add a new change
// (there will be one group per table)
changes.add(change);
}
return changes.toArray(new Change[changes.size()]);
} catch (Exception e) {
throw new UnexpectedLiquibaseException(e);
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException ignore) {
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException ignore) {
}
}
}
}
Aggregations