diff --git a/pom.xml b/pom.xml
index a82aec239..e6b9650f0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -135,7 +135,7 @@
io.ebean
ebean-migration
- 11.5.4
+ 11.6.1
@@ -192,7 +192,7 @@
org.postgresql
postgresql
- 9.4.1212
+ 42.2.2
provided
diff --git a/src/main/java/io/ebean/config/DbMigrationConfig.java b/src/main/java/io/ebean/config/DbMigrationConfig.java
index 7e47156b3..f40f6f58d 100644
--- a/src/main/java/io/ebean/config/DbMigrationConfig.java
+++ b/src/main/java/io/ebean/config/DbMigrationConfig.java
@@ -102,6 +102,11 @@ public class DbMigrationConfig {
*/
protected Map runPlaceholderMap;
+ /**
+ * DB schema used for the migration (and testing).
+ */
+ protected String dbSchema;
+
/**
* DB user used to run the DB migration.
*/
@@ -373,6 +378,33 @@ public class DbMigrationConfig {
this.dbPassword = dbPassword;
}
+ /**
+ * Return the DB schema to use (for migration, testing etc).
+ */
+ public String getDbSchema() {
+ String schema = readEnvironment("ddl.migration.schema");
+ if (schema != null) {
+ return schema;
+ }
+ return dbSchema;
+ }
+
+ /**
+ * Set the Db schema to use.
+ */
+ public void setDbSchema(String dbSchema) {
+ this.dbSchema = dbSchema;
+ }
+
+ /**
+ * Set the Db schema if it hasn't already been defined.
+ */
+ public void setDefaultDbSchema(String dbSchema) {
+ if (this.dbSchema == null) {
+ this.dbSchema = dbSchema;
+ }
+ }
+
/**
* Return migration versions that should be added to history without running.
*/
@@ -475,6 +507,7 @@ public class DbMigrationConfig {
runMigration = properties.getBoolean("migration.run", runMigration);
metaTable = properties.get("migration.metaTable", metaTable);
runPlaceholders = properties.get("migration.placeholders", runPlaceholders);
+ dbSchema = properties.get("migration.dbSchema", dbSchema);
//Do not set user and pass from "datasource.db.username"
//There is a null test in MigrationRunner::getConnection to handle this
@@ -557,6 +590,7 @@ public class DbMigrationConfig {
runnerConfig.setRunPlaceholders(runPlaceholders);
runnerConfig.setDbUsername(getDbUsername());
runnerConfig.setDbPassword(getDbPassword());
+ runnerConfig.setDbSchema(getDbSchema());
runnerConfig.setClassLoader(classLoader);
if (patchInsertOn != null) {
runnerConfig.setPatchInsertOn(patchInsertOn);
diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java
index 0d0bbd70e..088ec3663 100644
--- a/src/main/java/io/ebean/config/ServerConfig.java
+++ b/src/main/java/io/ebean/config/ServerConfig.java
@@ -296,6 +296,11 @@ public class ServerConfig {
*/
private DataSourceConfig readOnlyDataSourceConfig = new DataSourceConfig();
+ /**
+ * Optional - the database schema that should be used to own the tables etc.
+ */
+ private String dbSchema;
+
/**
* The db migration config (migration resource path etc).
*/
@@ -1120,6 +1125,25 @@ public class ServerConfig {
this.profilingConfig = profilingConfig;
}
+ /**
+ * Return the DB schema to use.
+ */
+ public String getDbSchema() {
+ return dbSchema;
+ }
+
+ /**
+ * Set the DB schema to use. This specifies to use this schema for:
+ *
+ * - Running Database migrations - Create and use the DB schema
+ * - Testing DDL - Create-all.sql DDL execution creates and uses schema
+ * - Testing Docker - Set default schema on connection URL
+ *
+ */
+ public void setDbSchema(String dbSchema) {
+ this.dbSchema = dbSchema;
+ }
+
/**
* Return the DB migration configuration.
*/
@@ -2764,6 +2788,10 @@ public class ServerConfig {
*/
protected void loadSettings(PropertiesWrapper p) {
+ dbSchema = p.get("dbSchema", dbSchema);
+ if (dbSchema != null) {
+ migrationConfig.setDefaultDbSchema(dbSchema);
+ }
profilingConfig.loadSettings(p, name);
migrationConfig.loadSettings(p, name);
platformConfig.loadSettings(p);
diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java
index ced70893c..ecc211289 100644
--- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java
+++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java
@@ -16,6 +16,7 @@ import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.sql.Statement;
import java.sql.Types;
/**
@@ -658,6 +659,39 @@ public class DatabasePlatform {
return persistBatchOnCascade;
}
+ /**
+ * Create the DB schema if it does not exist.
+ */
+ public void createSchemaIfNotExists(String dbSchema, Connection connection) throws SQLException {
+ if (!schemaExists(dbSchema, connection)) {
+ Statement query = connection.createStatement();
+ try {
+ logger.info("create schema:{}", dbSchema);
+ query.executeUpdate("create schema " + dbSchema);
+ } finally {
+ JdbcClose.close(query);
+ }
+ }
+ }
+
+ /**
+ * Return true if the schema exists.
+ */
+ public boolean schemaExists(String dbSchema, Connection connection) throws SQLException {
+ ResultSet schemas = connection.getMetaData().getSchemas();
+ try {
+ while (schemas.next()) {
+ String schema = schemas.getString(1);
+ if (schema.equalsIgnoreCase(dbSchema)) {
+ return true;
+ }
+ }
+ } finally {
+ JdbcClose.close(schemas);
+ }
+ return false;
+ }
+
/**
* Return true if the table exists.
*/
diff --git a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java
index 40614c8b8..e8edf79dc 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java
@@ -1,8 +1,8 @@
package io.ebeaninternal.dbmigration;
-import io.ebean.Transaction;
import io.ebean.config.ServerConfig;
import io.ebean.migration.ddl.DdlRunner;
+import io.ebean.util.JdbcClose;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.dbmigration.model.CurrentModel;
import io.ebeaninternal.extraddl.model.ExtraDdlXmlReader;
@@ -38,6 +38,7 @@ public class DdlGenerator {
private final boolean createOnly;
private final boolean jaxbPresent;
private final boolean ddlCommitOnCreateIndex;
+ private final String dbSchema;
private CurrentModel currentModel;
private String dropAllContent;
@@ -48,6 +49,7 @@ public class DdlGenerator {
this.jaxbPresent = serverConfig.getClassLoadConfig().isJavaxJAXBPresent();
this.generateDdl = serverConfig.isDdlGenerate();
this.createOnly = serverConfig.isDdlCreateOnly();
+ this.dbSchema = serverConfig.getDbSchema();
if (!serverConfig.getTenantMode().isDdlEnabled() && serverConfig.isDdlRun()) {
log.warn("DDL can't be run on startup with TenantMode " + serverConfig.getTenantMode());
this.runDdl = false;
@@ -85,30 +87,54 @@ public class DdlGenerator {
* Run the DDL drop and DDL create scripts if properties have been set.
*/
protected void runDdl() {
-
if (runDdl) {
+ Connection connection = null;
try {
- runInitSql();
- runDropSql();
- runCreateSql();
- runSeedSql();
-
- } catch (IOException e) {
- String msg = "Error reading drop/create script from file system";
- throw new RuntimeException(msg, e);
+ connection = obtainConnection();
+ runDdlWith(connection);
+ } finally {
+ JdbcClose.rollback(connection);
+ JdbcClose.close(connection);
}
}
}
+ private void runDdlWith(Connection connection) {
+ try {
+ if (dbSchema != null) {
+ createSchemaIfRequired(connection);
+ }
+ runInitSql(connection);
+ runDropSql(connection);
+ runCreateSql(connection);
+ runSeedSql(connection);
+ } catch (IOException e) {
+ throw new RuntimeException("Error reading drop/create script from file system", e);
+ }
+ }
+
+ private Connection obtainConnection() {
+ try {
+ return server.getPluginApi().getDataSource().getConnection();
+ } catch (SQLException e) {
+ throw new PersistenceException("Failed to obtain connection to run DDL", e);
+ }
+ }
+
+ private void createSchemaIfRequired(Connection connection) {
+ try {
+ server.getDatabasePlatform().createSchemaIfNotExists(dbSchema, connection);
+ } catch (SQLException e) {
+ throw new PersistenceException("Failed to create DB Schema", e);
+ }
+ }
+
/**
* Execute all the DDL statements in the script.
*/
- public int runScript(boolean expectErrors, String content, String scriptName) {
+ public int runScript(Connection connection, boolean expectErrors, String content, String scriptName) {
DdlRunner runner = new DdlRunner(expectErrors, scriptName);
-
- Transaction transaction = server.createTransaction();
- Connection connection = transaction.getConnection();
try {
if (expectErrors) {
connection.setAutoCommit(true);
@@ -119,64 +145,63 @@ public class DdlGenerator {
if (expectErrors) {
connection.setAutoCommit(false);
}
- transaction.commit();
+ connection.commit();
return count;
} catch (SQLException e) {
throw new PersistenceException("Failed to run script", e);
-
} finally {
- transaction.end();
+ JdbcClose.rollback(connection);
}
}
- protected void runDropSql() throws IOException {
+ protected void runDropSql(Connection connection) throws IOException {
if (!createOnly) {
String ignoreExtraDdl = System.getProperty("ebean.ignoreExtraDdl");
if (!"true".equalsIgnoreCase(ignoreExtraDdl) && jaxbPresent) {
String extraApply = ExtraDdlXmlReader.buildExtra(server.getDatabasePlatform().getName(), true);
if (extraApply != null) {
- runScript(false, extraApply, "extra-dll");
+ runScript(connection, false, extraApply, "extra-dll");
}
}
if (dropAllContent == null) {
dropAllContent = readFile(getDropFileName());
}
- runScript(true, dropAllContent, getDropFileName());
+ runScript(connection, true, dropAllContent, getDropFileName());
}
}
- protected void runCreateSql() throws IOException {
+ protected void runCreateSql(Connection connection) throws IOException {
if (createAllContent == null) {
createAllContent = readFile(getCreateFileName());
}
- runScript(false, createAllContent, getCreateFileName());
+ runScript(connection, false, createAllContent, getCreateFileName());
String ignoreExtraDdl = System.getProperty("ebean.ignoreExtraDdl");
if (!"true".equalsIgnoreCase(ignoreExtraDdl) && jaxbPresent) {
String extraApply = ExtraDdlXmlReader.buildExtra(server.getDatabasePlatform().getName(), false);
if (extraApply != null) {
- runScript(false, extraApply, "extra-dll");
+ runScript(connection, false, extraApply, "extra-dll");
}
}
}
- protected void runInitSql() throws IOException {
- runResourceScript(server.getServerConfig().getDdlInitSql());
+ protected void runInitSql(Connection connection) throws IOException {
+ runResourceScript(connection, server.getServerConfig().getDdlInitSql());
}
- protected void runSeedSql() throws IOException {
- runResourceScript(server.getServerConfig().getDdlSeedSql());
+ protected void runSeedSql(Connection connection) throws IOException {
+ runResourceScript(connection, server.getServerConfig().getDdlSeedSql());
}
- protected void runResourceScript(String sqlScript) throws IOException {
+ protected void runResourceScript(Connection connection, String sqlScript) throws IOException {
if (sqlScript != null) {
try (InputStream is = getClassLoader().getResourceAsStream(sqlScript)) {
if (is != null) {
String content = readContent(new InputStreamReader(is));
- runScript(false, content, sqlScript);
+ runScript(connection, false, content, sqlScript);
}
}
}