diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/LiquibaseJpaUpdaterProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/LiquibaseJpaUpdaterProvider.java index 8ecba4f51c..bf84c27b7c 100755 --- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/LiquibaseJpaUpdaterProvider.java +++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/LiquibaseJpaUpdaterProvider.java @@ -33,11 +33,19 @@ import org.keycloak.models.KeycloakSession; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.io.Writer; import java.lang.reflect.Method; import java.sql.Connection; import java.util.List; import java.util.Set; import liquibase.LabelExpression; +import liquibase.database.Database; +import liquibase.exception.DatabaseException; +import liquibase.executor.Executor; +import liquibase.executor.ExecutorService; +import liquibase.executor.LoggingExecutor; +import liquibase.statement.core.CreateDatabaseChangeLogTableStatement; +import liquibase.util.StreamUtil; /** * @author Stian Thorgersen @@ -110,7 +118,12 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider { } if (exportFile != null) { - liquibase.update((Contexts) null, new FileWriter(exportFile)); + try (Writer exportWriter = new FileWriter(exportFile)) { + if (ranChangeSets.isEmpty()) { + outputChangeLogTableCreationScript(liquibase, exportWriter); + } + liquibase.update((Contexts) null, new LabelExpression(), exportWriter, false); + } } else { liquibase.update((Contexts) null); } @@ -125,6 +138,27 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider { } } + private void outputChangeLogTableCreationScript(Liquibase liquibase, final Writer exportWriter) throws DatabaseException { + Database database = liquibase.getDatabase(); + + Executor oldTemplate = ExecutorService.getInstance().getExecutor(database); + LoggingExecutor executor = new LoggingExecutor(ExecutorService.getInstance().getExecutor(database), exportWriter, database); + ExecutorService.getInstance().setExecutor(database, executor); + + executor.comment("*********************************************************************"); + executor.comment("* Keycloak database creation script - apply this script to empty DB *"); + executor.comment("*********************************************************************" + StreamUtil.getLineSeparator()); + + executor.execute(new CreateDatabaseChangeLogTableStatement()); + // DatabaseChangeLogLockTable is created before this code is executed and recreated if it does not exist automatically + // in org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService.init() called indirectly from + // KeycloakApplication constructor (search for waitForLock() call). Hence it is not included in the creation script. + + executor.comment("*********************************************************************" + StreamUtil.getLineSeparator()); + + ExecutorService.getInstance().setExecutor(database, oldTemplate); + } + @Override public Status validate(Connection connection, String defaultSchema) { logger.debug("Validating if database is updated");