Search in sources :

Example 1 with DiffToChangeLog

use of liquibase.diff.output.changelog.DiffToChangeLog in project minijax by minijax.

the class LiquibaseHelper method generateMigrations.

private File generateMigrations(final Database referenceDatabase, final Database targetDatabase) throws LiquibaseException, IOException {
    if (!resourcesDir.exists()) {
        resourcesDir.mkdirs();
    }
    if (!migrationsDir.exists()) {
        migrationsDir.mkdirs();
    }
    if (masterChangeLogFile.exists()) {
        LOG.info("Checking current database state");
        validateDatabaseState(targetDatabase);
    } else {
        LOG.info("Creating new master changelog");
        writeChangeSets(masterChangeLogFile, emptyList());
    }
    @SuppressWarnings("unchecked") final SnapshotControl snapshotControl = new SnapshotControl(referenceDatabase, liquibase.structure.core.Schema.class, liquibase.structure.core.Table.class, liquibase.structure.core.Column.class, liquibase.structure.core.PrimaryKey.class, liquibase.structure.core.Index.class);
    LOG.info("Executing diff");
    final CompareControl compareControl = new CompareControl(snapshotControl.getTypesToInclude());
    final DiffResult diffResult = DiffGeneratorFactory.getInstance().compare(referenceDatabase, targetDatabase, compareControl);
    LOG.info("Converting diff to changelog");
    final DiffOutputControl diffOutputControl = new DiffOutputControl(false, false, true, null);
    final DiffToChangeLog diffToChangeLog = new DiffToChangeLog(diffResult, diffOutputControl);
    diffToChangeLog.setChangeSetAuthor(System.getProperty("user.name"));
    final List<ChangeSet> changeSets = filterChangeSets(diffToChangeLog.generateChangeSets());
    LOG.info("Found {} changes", changeSets.size());
    if (changeSets.isEmpty()) {
        return null;
    }
    final File generatedChangeLogFile = new File(migrationsDir, generateFileName(masterChangeLogFile));
    LOG.info("Writing new changelog: {}", generatedChangeLogFile);
    writeChangeSets(generatedChangeLogFile, changeSets);
    LOG.info("Add migration to master changelog: {}", masterChangeLogFile);
    addIncludeFile(generatedChangeLogFile);
    LOG.info("Cleaning changelog");
    cleanXmlFile(masterChangeLogFile);
    cleanXmlFile(generatedChangeLogFile);
    LOG.info("Diff complete");
    return generatedChangeLogFile;
}
Also used : CompareControl(liquibase.diff.compare.CompareControl) DiffOutputControl(liquibase.diff.output.DiffOutputControl) DiffToChangeLog(liquibase.diff.output.changelog.DiffToChangeLog) DiffResult(liquibase.diff.DiffResult) SnapshotControl(liquibase.snapshot.SnapshotControl) ChangeSet(liquibase.changelog.ChangeSet) File(java.io.File)

Example 2 with DiffToChangeLog

use of liquibase.diff.output.changelog.DiffToChangeLog in project stdlib by petergeneric.

the class LiquibaseCore method executeAction.

/**
 * Executes the Liquibase update.
 */
private static void executeAction(InitialContext jndi, GuiceApplicationValueContainer config, Map<String, String> parameters, LiquibaseAction action) throws NamingException, SQLException, LiquibaseException, IOException, ParserConfigurationException {
    // N.B. liquibase may create a databasechangeloglock / databasechangelog table if one does not already exist
    if (action.isWriteAction() && StringUtils.equalsIgnoreCase("true", config.getValue(HIBERNATE_IS_READONLY))) {
        log.info("Changing liquibase action from " + action + " to ASSERT_UPDATED because hibernate is set to read only mode");
        action = LiquibaseAction.ASSERT_UPDATED;
    }
    // Fail if hbm2ddl is enabled (Hibernate should not be involved in schema management)
    if (StringUtils.isNotEmpty(config.getValue(HIBERNATE_SCHEMA_MANAGEMENT)) && action != LiquibaseAction.GENERATE_CHANGELOG) {
        throw new RuntimeException("Liquibase is enabled but so is " + HIBERNATE_SCHEMA_MANAGEMENT + ". Only one of these schema management methods may be used at a time.");
    }
    final String dataSourceName = config.getDataSource();
    final String changeLogFile = config.getValue(GuiceProperties.LIQUIBASE_CHANGELOG);
    final String contexts = config.getValue(GuiceProperties.LIQUIBASE_CONTEXTS);
    final String labels = config.getValue(GuiceProperties.LIQUIBASE_LABELS);
    final String defaultSchema = config.getDefaultSchema();
    final String jdbcUrl = config.getValue(AvailableSettings.URL);
    final String jdbcUsername = config.getValue(AvailableSettings.USER);
    final String jdbcPassword = config.getValue(AvailableSettings.PASS);
    if (StringUtils.isEmpty(dataSourceName) && StringUtils.isEmpty(jdbcUrl))
        throw new RuntimeException("Cannot run Liquibase: no JNDI datasource or JDBC URL set");
    else if (changeLogFile == null)
        throw new RuntimeException("Cannot run Liquibase: " + GuiceProperties.LIQUIBASE_CHANGELOG + " is not set");
    int storedTransactionIsolation = Integer.MIN_VALUE;
    Connection connection = null;
    Database database = null;
    try {
        // Set up the resource accessor
        final ResourceAccessor resourceAccessor;
        {
            final CompositeResourceAccessor composite;
            {
                ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
                ResourceAccessor threadClFO = new ClassLoaderResourceAccessor(contextClassLoader);
                ResourceAccessor clFO = new ClassLoaderResourceAccessor();
                ResourceAccessor fsFO = new FileSystemResourceAccessor();
                composite = new CompositeResourceAccessor(clFO, fsFO, threadClFO);
            }
            // If loading a resource with an absolute path fails, re-try it as a path relative to /
            // This is for unit tests where /liquibase/changelog.xml needs to be accessed as liquibase/changelog.xml
            final ResourceAccessor fallback = new RetryAbsoluteAsRelativeResourceAccessor(composite);
            // Wrap the resource accessor in a filter that interprets ./ as the changeLogFile folder
            resourceAccessor = new RelativePathFilteringResourceAccessor(fallback, changeLogFile);
        }
        // Set up the database
        {
            if (StringUtils.isNotEmpty(dataSourceName)) {
                if (log.isDebugEnabled())
                    log.debug("Look up datasource for liquibase: " + dataSourceName);
                final DataSource dataSource = (DataSource) jndi.lookup(dataSourceName);
                connection = dataSource.getConnection();
            } else {
                if (log.isDebugEnabled())
                    log.debug("Create JDBC Connection directly: " + jdbcUrl);
                // N.B. do we need to call Class.forName on the JDBC Driver URL?
                // JDBC drivers should expose themselves using the service provider interface nowadays so this shouldn't be necessary
                connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword);
            }
            // Allow changing the transaction isolation away from the default for liquibase
            // This is a hack inserted for SQL Server where the SNAPSHOT isolation is being used
            // because in this mode it refuses to execute certain DDL statements because of metadata not being versioned
            {
                storedTransactionIsolation = connection.getTransactionIsolation();
                // In this case we change to READ UNCOMMITTED for the duration of the liquibase run
                if (storedTransactionIsolation == 4096) {
                    connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
                }
            }
            database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
            database.setDefaultSchemaName(defaultSchema);
        }
        Liquibase liquibase = new Liquibase(changeLogFile, resourceAccessor, database);
        for (Map.Entry<String, String> param : parameters.entrySet()) {
            liquibase.setChangeLogParameter(param.getKey(), param.getValue());
        }
        if (log.isDebugEnabled())
            log.debug("Execute liquibase action: " + action);
        switch(action) {
            case ASSERT_UPDATED:
                // Figure out which changesets need to be run
                List<ChangeSet> unrun = liquibase.listUnrunChangeSets(new Contexts(contexts), new LabelExpression(labels));
                if (log.isDebugEnabled())
                    log.debug("Pending changesets: " + unrun);
                // If any need to be run, fail
                if (unrun.size() > 0)
                    throw new LiquibaseChangesetsPending(unrun);
                else
                    return;
            case UPDATE:
                // Perform a schema update
                liquibase.update(new Contexts(contexts), new LabelExpression(labels));
                return;
            case MARK_UPDATED:
                // Mark all pending changesets as run
                liquibase.changeLogSync(new Contexts(contexts), new LabelExpression(labels));
                return;
            case GENERATE_CHANGELOG:
                CatalogAndSchema catalogueAndSchema = CatalogAndSchema.DEFAULT;
                DiffToChangeLog writer = new DiffToChangeLog(new DiffOutputControl(false, false, false, new CompareControl.SchemaComparison[0]));
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                PrintStream pw = new PrintStream(bos);
                liquibase.generateChangeLog(catalogueAndSchema, writer, pw);
                System.out.println("********** GENERATED CHANGELOG START **********");
                System.out.println(new String(bos.toByteArray()));
                System.out.println("********** GENERATED CHANGELOG END **********");
                break;
            default:
                throw new RuntimeException("Unknown liquibase action: " + action);
        }
    } finally {
        // N.B. we don't return to isolations < 0 (isolation at db defaults)
        if (connection != null && connection.getTransactionIsolation() != storedTransactionIsolation && storedTransactionIsolation >= 0) {
            connection.setTransactionIsolation(storedTransactionIsolation);
        }
        if (database != null)
            database.close();
        else if (connection != null)
            connection.close();
    }
}
Also used : CompositeResourceAccessor(liquibase.resource.CompositeResourceAccessor) FileSystemResourceAccessor(liquibase.resource.FileSystemResourceAccessor) ClassLoaderResourceAccessor(liquibase.resource.ClassLoaderResourceAccessor) ResourceAccessor(liquibase.resource.ResourceAccessor) JdbcConnection(liquibase.database.jvm.JdbcConnection) Contexts(liquibase.Contexts) Database(liquibase.database.Database) DiffToChangeLog(liquibase.diff.output.changelog.DiffToChangeLog) ChangeSet(liquibase.changelog.ChangeSet) PrintStream(java.io.PrintStream) LiquibaseChangesetsPending(com.peterphi.std.guice.liquibase.exception.LiquibaseChangesetsPending) Connection(java.sql.Connection) JdbcConnection(liquibase.database.jvm.JdbcConnection) DiffOutputControl(liquibase.diff.output.DiffOutputControl) ByteArrayOutputStream(java.io.ByteArrayOutputStream) CatalogAndSchema(liquibase.CatalogAndSchema) DataSource(javax.sql.DataSource) CompositeResourceAccessor(liquibase.resource.CompositeResourceAccessor) Liquibase(liquibase.Liquibase) LabelExpression(liquibase.LabelExpression) FileSystemResourceAccessor(liquibase.resource.FileSystemResourceAccessor) ClassLoaderResourceAccessor(liquibase.resource.ClassLoaderResourceAccessor) HashMap(java.util.HashMap) Map(java.util.Map)

Example 3 with DiffToChangeLog

use of liquibase.diff.output.changelog.DiffToChangeLog in project dropwizard by dropwizard.

the class DbDumpCommand method run.

@Override
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public void run(Namespace namespace, Liquibase liquibase) throws Exception {
    final Set<Class<? extends DatabaseObject>> compareTypes = new HashSet<>();
    if (isTrue(namespace.getBoolean("columns"))) {
        compareTypes.add(Column.class);
    }
    if (isTrue(namespace.getBoolean("data"))) {
        compareTypes.add(Data.class);
    }
    if (isTrue(namespace.getBoolean("foreign-keys"))) {
        compareTypes.add(ForeignKey.class);
    }
    if (isTrue(namespace.getBoolean("indexes"))) {
        compareTypes.add(Index.class);
    }
    if (isTrue(namespace.getBoolean("primary-keys"))) {
        compareTypes.add(PrimaryKey.class);
    }
    if (isTrue(namespace.getBoolean("sequences"))) {
        compareTypes.add(Sequence.class);
    }
    if (isTrue(namespace.getBoolean("tables"))) {
        compareTypes.add(Table.class);
    }
    if (isTrue(namespace.getBoolean("unique-constraints"))) {
        compareTypes.add(UniqueConstraint.class);
    }
    if (isTrue(namespace.getBoolean("views"))) {
        compareTypes.add(View.class);
    }
    final DiffToChangeLog diffToChangeLog = new DiffToChangeLog(new DiffOutputControl());
    final Database database = liquibase.getDatabase();
    final String filename = namespace.getString("output");
    if (filename != null) {
        try (PrintStream file = new PrintStream(filename, StandardCharsets.UTF_8.name())) {
            generateChangeLog(database, database.getDefaultSchema(), diffToChangeLog, file, compareTypes);
        }
    } else {
        generateChangeLog(database, database.getDefaultSchema(), diffToChangeLog, outputStream, compareTypes);
    }
}
Also used : PrintStream(java.io.PrintStream) Database(liquibase.database.Database) DatabaseObject(liquibase.structure.DatabaseObject) DiffOutputControl(liquibase.diff.output.DiffOutputControl) DiffToChangeLog(liquibase.diff.output.changelog.DiffToChangeLog) HashSet(java.util.HashSet)

Example 4 with DiffToChangeLog

use of liquibase.diff.output.changelog.DiffToChangeLog in project liquibase by liquibase.

the class PostgreSQLIntegrationTest method testMissingDataGenerator.

@Test
public void testMissingDataGenerator() throws Exception {
    Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", getDatabase()).execute(new RawSqlStatement("CREATE TABLE \"FIRST_TABLE\" (\"ID\" INT, \"NAME\" VARCHAR(20), \"LAST_NAME\" VARCHAR(20) DEFAULT 'Snow', " + "\"AGE\" INT DEFAULT 25, \"REGISTRATION_DATE\" date DEFAULT TO_DATE('2014-08-11', 'YYYY-MM-DD'), " + "\"COMPVALCOL\" INT DEFAULT 1*22)"));
    Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", getDatabase()).execute(new RawSqlStatement("CREATE TABLE \"SECOND_TABLE\" (\"ID\" INT, \"NAME\" VARCHAR(20))"));
    Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", getDatabase()).execute(new RawSqlStatement("ALTER TABLE \"FIRST_TABLE\" ADD CONSTRAINT \"FIRST_TABLE_PK\" PRIMARY KEY (\"ID\")"));
    Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", getDatabase()).execute(new RawSqlStatement("ALTER TABLE \"SECOND_TABLE\" ADD CONSTRAINT \"FIRST_TABLE_FK\" FOREIGN KEY (\"ID\") REFERENCES \"FIRST_TABLE\"(\"ID\")"));
    Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", getDatabase()).execute(new RawSqlStatement("CREATE INDEX \"IDX_FIRST_TABLE\" ON \"FIRST_TABLE\"(\"NAME\")"));
    Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", getDatabase()).execute(new RawSqlStatement("INSERT INTO \"FIRST_TABLE\"(\"ID\", \"NAME\") VALUES (1, 'JOHN')"));
    Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", getDatabase()).execute(new RawSqlStatement("INSERT INTO \"FIRST_TABLE\"(\"ID\", \"NAME\", \"LAST_NAME\", \"AGE\", \"REGISTRATION_DATE\", \"COMPVALCOL\") VALUES (2, 'JEREMY', 'IRONS', 71, TO_DATE('2020-04-01', 'YYYY-MM-DD'), 2*11 )"));
    Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", getDatabase()).execute(new RawSqlStatement("INSERT INTO \"SECOND_TABLE\"(\"ID\", \"NAME\") VALUES (1, 'JOHN')"));
    Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", getDatabase()).execute(new RawSqlStatement("INSERT INTO \"SECOND_TABLE\"(\"ID\", \"NAME\") VALUES (2, 'JEREMY')"));
    DiffResult diffResult = DiffGeneratorFactory.getInstance().compare(getDatabase(), null, new CompareControl());
    DiffToChangeLog changeLogWriter = new DiffToChangeLog(diffResult, new DiffOutputControl(false, false, false, null));
    List<ChangeSet> changeSets = changeLogWriter.generateChangeSets();
    boolean found = false;
    for (ChangeSet changeSet : changeSets) {
        List<Change> changes = changeSet.getChanges();
        for (Change change : changes) {
            if (!(change instanceof CreateTableChange)) {
                continue;
            }
            found = ((CreateTableChange) change).getTableName().equals("FIRST_TABLE");
            if (found) {
                break;
            }
        }
        if (found) {
            break;
        }
    }
    Assert.assertTrue("There should be a table named \"FIRST_TABLE\"", found);
}
Also used : RawSqlStatement(liquibase.statement.core.RawSqlStatement) CreateTableChange(liquibase.change.core.CreateTableChange) CompareControl(liquibase.diff.compare.CompareControl) DiffOutputControl(liquibase.diff.output.DiffOutputControl) DiffToChangeLog(liquibase.diff.output.changelog.DiffToChangeLog) DiffResult(liquibase.diff.DiffResult) Change(liquibase.change.Change) CreateTableChange(liquibase.change.core.CreateTableChange) AddPrimaryKeyChange(liquibase.change.core.AddPrimaryKeyChange) ChangeSet(liquibase.changelog.ChangeSet) Test(org.junit.Test) AbstractIntegrationTest(liquibase.dbtest.AbstractIntegrationTest)

Example 5 with DiffToChangeLog

use of liquibase.diff.output.changelog.DiffToChangeLog in project liquibase by liquibase.

the class PostgreSQLIntegrationTest method testDependenciesInGenerateChangeLog.

@Test
public void testDependenciesInGenerateChangeLog() throws Exception {
    assumeNotNull(this.getDatabase());
    Liquibase liquibase = createLiquibase(this.dependenciesChangeLog);
    clearDatabase();
    try {
        liquibase.update(new Contexts());
        Database database = liquibase.getDatabase();
        DiffResult diffResult = DiffGeneratorFactory.getInstance().compare(database, null, new CompareControl());
        DiffToChangeLog changeLogWriter = new DiffToChangeLog(diffResult, new DiffOutputControl(false, false, false, null));
        List<ChangeSet> changeSets = changeLogWriter.generateChangeSets();
        Assert.assertTrue(changeSets.size() > 0);
        ChangeSet addPrimaryKeyChangeSet = changeSets.stream().filter(changeSet -> changeSet.getChanges().get(0) instanceof AddPrimaryKeyChange).findFirst().orElse(null);
        Assert.assertNull(addPrimaryKeyChangeSet);
    } catch (ValidationFailedException e) {
        e.printDescriptiveError(System.out);
        throw e;
    }
}
Also used : Liquibase(liquibase.Liquibase) ValidationFailedException(liquibase.exception.ValidationFailedException) Database(liquibase.database.Database) CompareControl(liquibase.diff.compare.CompareControl) DiffOutputControl(liquibase.diff.output.DiffOutputControl) DiffToChangeLog(liquibase.diff.output.changelog.DiffToChangeLog) AddPrimaryKeyChange(liquibase.change.core.AddPrimaryKeyChange) DiffResult(liquibase.diff.DiffResult) Contexts(liquibase.Contexts) ChangeSet(liquibase.changelog.ChangeSet) Test(org.junit.Test) AbstractIntegrationTest(liquibase.dbtest.AbstractIntegrationTest)

Aggregations

DiffToChangeLog (liquibase.diff.output.changelog.DiffToChangeLog)14 DiffOutputControl (liquibase.diff.output.DiffOutputControl)13 DiffResult (liquibase.diff.DiffResult)11 CompareControl (liquibase.diff.compare.CompareControl)9 ChangeSet (liquibase.changelog.ChangeSet)7 Test (org.junit.Test)7 PrintStream (java.io.PrintStream)6 Database (liquibase.database.Database)5 SnapshotControl (liquibase.snapshot.SnapshotControl)4 File (java.io.File)3 Liquibase (liquibase.Liquibase)3 AbstractIntegrationTest (liquibase.dbtest.AbstractIntegrationTest)3 DatabaseException (liquibase.exception.DatabaseException)3 ValidationFailedException (liquibase.exception.ValidationFailedException)3 DatabaseSnapshot (liquibase.snapshot.DatabaseSnapshot)3 IOException (java.io.IOException)2 UnsupportedEncodingException (java.io.UnsupportedEncodingException)2 ParserConfigurationException (javax.xml.parsers.ParserConfigurationException)2 CatalogAndSchema (liquibase.CatalogAndSchema)2 Contexts (liquibase.Contexts)2