Search in sources :

Example 11 with DatabaseObject

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();
    }
}
Also used : DiffOutputControl(liquibase.diff.output.DiffOutputControl) DropTableChange(liquibase.change.core.DropTableChange) Change(liquibase.change.Change) SqlStatement(liquibase.statement.SqlStatement) EmptyDatabaseSnapshot(liquibase.snapshot.EmptyDatabaseSnapshot) DatabaseObject(liquibase.structure.DatabaseObject) CompareControl(liquibase.diff.compare.CompareControl) DiffToChangeLog(liquibase.diff.output.changelog.DiffToChangeLog) DropTableChange(liquibase.change.core.DropTableChange) UnexpectedLiquibaseException(liquibase.exception.UnexpectedLiquibaseException) LiquibaseException(liquibase.exception.LiquibaseException) DiffResult(liquibase.diff.DiffResult) DatabaseSnapshot(liquibase.snapshot.DatabaseSnapshot) EmptyDatabaseSnapshot(liquibase.snapshot.EmptyDatabaseSnapshot) SnapshotControl(liquibase.snapshot.SnapshotControl) UnexpectedLiquibaseException(liquibase.exception.UnexpectedLiquibaseException) RanChangeSet(liquibase.changelog.RanChangeSet) ChangeSet(liquibase.changelog.ChangeSet)

Example 12 with DatabaseObject

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;
}
Also used : Change(liquibase.change.Change) ObjectDifferences(liquibase.diff.ObjectDifferences) DatabaseObjectComparator(liquibase.structure.DatabaseObjectComparator) DatabaseObject(liquibase.structure.DatabaseObject) SimpleDateFormat(java.text.SimpleDateFormat) ChangeSet(liquibase.changelog.ChangeSet)

Example 13 with DatabaseObject

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);
}
Also used : DependencyUtil(liquibase.util.DependencyUtil) Column(liquibase.structure.core.Column) CompareControl(liquibase.diff.compare.CompareControl) DatabaseObject(liquibase.structure.DatabaseObject) DatabaseException(liquibase.exception.DatabaseException)

Example 14 with DatabaseObject

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()]);
}
Also used : CreateViewChange(liquibase.change.core.CreateViewChange) ArrayList(java.util.ArrayList) Change(liquibase.change.Change) CreateViewChange(liquibase.change.core.CreateViewChange) SetTableRemarksChange(liquibase.change.core.SetTableRemarksChange) Difference(liquibase.diff.Difference) View(liquibase.structure.core.View) OracleDatabase(liquibase.database.core.OracleDatabase) Column(liquibase.structure.core.Column) DatabaseObject(liquibase.structure.DatabaseObject) SetTableRemarksChange(liquibase.change.core.SetTableRemarksChange)

Example 15 with DatabaseObject

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) {
            }
        }
    }
}
Also used : ColumnConfig(liquibase.change.ColumnConfig) DatabaseFunction(liquibase.statement.DatabaseFunction) SQLException(java.sql.SQLException) Statement(java.sql.Statement) ArrayList(java.util.ArrayList) InsertDataChange(liquibase.change.core.InsertDataChange) Change(liquibase.change.Change) Date(java.util.Date) SQLException(java.sql.SQLException) UnexpectedLiquibaseException(liquibase.exception.UnexpectedLiquibaseException) InsertDataChange(liquibase.change.core.InsertDataChange) InformixDatabase(liquibase.database.core.InformixDatabase) ResultSet(java.sql.ResultSet) DatabaseObject(liquibase.structure.DatabaseObject) UnexpectedLiquibaseException(liquibase.exception.UnexpectedLiquibaseException)

Aggregations

DatabaseObject (liquibase.structure.DatabaseObject)47 UnexpectedLiquibaseException (liquibase.exception.UnexpectedLiquibaseException)14 CompareControl (liquibase.diff.compare.CompareControl)10 Change (liquibase.change.Change)9 Database (liquibase.database.Database)9 CatalogAndSchema (liquibase.CatalogAndSchema)7 DiffResult (liquibase.diff.DiffResult)6 ObjectDifferences (liquibase.diff.ObjectDifferences)6 ArrayList (java.util.ArrayList)5 EmptyDatabaseSnapshot (liquibase.snapshot.EmptyDatabaseSnapshot)5 Column (liquibase.structure.core.Column)5 Table (liquibase.structure.core.Table)5 HashSet (java.util.HashSet)4 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)4 DiffOutputControl (liquibase.diff.output.DiffOutputControl)4 DatabaseException (liquibase.exception.DatabaseException)4 InvalidExampleException (liquibase.snapshot.InvalidExampleException)4 SnapshotControl (liquibase.snapshot.SnapshotControl)4 DatabaseObjectCollection (liquibase.structure.DatabaseObjectCollection)4 List (java.util.List)3