diff --git a/flyway-community-db-support-archetype/pom.xml b/flyway-community-db-support-archetype/pom.xml
index 1ededac..0d673e1 100644
--- a/flyway-community-db-support-archetype/pom.xml
+++ b/flyway-community-db-support-archetype/pom.xml
@@ -5,7 +5,7 @@
4.0.0
org.flywaydb
flyway-community-db-support-archetype
- 10.13.0
+ 10.14.0
maven-archetype
Archetype - flyway-community-db-support-archetype
diff --git a/flyway-database-clickhouse/pom.xml b/flyway-database-clickhouse/pom.xml
index d250498..cb30199 100644
--- a/flyway-database-clickhouse/pom.xml
+++ b/flyway-database-clickhouse/pom.xml
@@ -23,7 +23,7 @@
org.flywaydb
flyway-community-db-support
- 10.13.0
+ 10.14.0
flyway-database-clickhouse
diff --git a/flyway-database-databricks/pom.xml b/flyway-database-databricks/pom.xml
index 1056b86..3f92628 100644
--- a/flyway-database-databricks/pom.xml
+++ b/flyway-database-databricks/pom.xml
@@ -23,7 +23,7 @@
org.flywaydb
flyway-community-db-support
- 10.13.0
+ 10.14.0
flyway-database-databricks
diff --git a/flyway-database-db2zOS/pom.xml b/flyway-database-db2zOS/pom.xml
new file mode 100644
index 0000000..134e9bf
--- /dev/null
+++ b/flyway-database-db2zOS/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ 4.0.0
+
+ org.flywaydb
+ flyway-community-db-support
+ 10.14.0
+
+
+ flyway-database-db2zOS
+ ${project.artifactId}
+
+
+
+ ${project.groupId}
+ flyway-core
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ maven-resources-plugin
+
+
+ maven-jar-plugin
+
+
+
+
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/DB2ZDatabaseExtension.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/DB2ZDatabaseExtension.java
new file mode 100644
index 0000000..b2be151
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/DB2ZDatabaseExtension.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import org.flywaydb.community.database.db2z.DB2ZConfigurationExtension;
+import org.flywaydb.core.api.FlywayException;
+import org.flywaydb.core.extensibility.PluginMetadata;
+import org.flywaydb.core.internal.util.FileUtils;
+
+public class DB2ZDatabaseExtension implements PluginMetadata {
+
+ public String getDescription() {
+ return "Community-contributed DB2/zOS database support extension " + readVersion() + " by Redgate";
+ }
+
+ public static String readVersion() {
+ try {
+ return FileUtils.copyToString(
+ DB2ZConfigurationExtension.class.getClassLoader().getResourceAsStream("org/flywaydb/community/database/db2z/version.txt"),
+ StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ throw new FlywayException("Unable to read extension version: " + e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZCallProcedureParsedStatement.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZCallProcedureParsedStatement.java
new file mode 100644
index 0000000..e8b7997
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZCallProcedureParsedStatement.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.sql.SQLException;
+import java.util.List;
+import java.util.regex.Pattern;
+import org.flywaydb.core.api.configuration.Configuration;
+import org.flywaydb.core.internal.jdbc.JdbcTemplate;
+import org.flywaydb.core.internal.jdbc.Result;
+import org.flywaydb.core.internal.jdbc.Results;
+import org.flywaydb.core.internal.sqlscript.Delimiter;
+import org.flywaydb.core.internal.sqlscript.ParsedSqlStatement;
+import org.flywaydb.core.internal.sqlscript.SqlScriptExecutor;
+
+
+/**
+ * A DB2Z CALL PROCEDURE statement.
+ */
+public class DB2ZCallProcedureParsedStatement extends ParsedSqlStatement {
+
+ private final String procedureName;
+ private final Object[] parms;
+
+ private static final Pattern DB2Z_DSNUTILU_PROCNAME = Pattern.compile(
+ "\"?SYSPROC\"?\\.\"?DSNUTILU\"?", Pattern.CASE_INSENSITIVE);
+ /**
+ * Creates a new DB2Z CALL PROCEDURE statement.
+ */
+ public DB2ZCallProcedureParsedStatement(int pos, int line, int col, String sql, Delimiter delimiter,
+ boolean canExecuteInTransaction, boolean batchable,
+ String procedureName, Object[] parms) {
+ super(pos, line, col, sql, delimiter, canExecuteInTransaction, batchable);
+ this.procedureName = procedureName;
+ this.parms = parms;
+ }
+
+ @Override
+ public Results execute(JdbcTemplate jdbcTemplate, SqlScriptExecutor sqlScriptExecutor, Configuration config) {
+ Results results;
+ String callStmt = "CALL " + procedureName + "(";
+ for(int i=0; i < parms.length; i++) {
+ callStmt += (i > 0 ? ", ?" : "?");
+ }
+ callStmt += ")";
+
+ results = ((DB2ZJdbcTemplate)jdbcTemplate).executeCallableStatement(callStmt, parms);
+
+ //For SYSPROC.DSNUTILU invocations, check last result row to detect any error
+ if(DB2Z_DSNUTILU_PROCNAME.matcher(procedureName).matches()) {
+ List resultList = results.getResults();
+ if(resultList.size() > 0) {
+ Result result = resultList.get(0);
+ if(result != null) {
+ List> resultData = result.getData();
+ if(resultData != null && resultData.size() > 0) {
+ List lastResultRow = resultData.get(resultData.size()-1);
+ if(lastResultRow != null && lastResultRow.size() > 0 ) {
+ String lastMessage = lastResultRow.get(lastResultRow.size()-1);
+ if(lastMessage != null && (
+ lastMessage.contains("DSNUGBAC - UTILITY EXECUTION TERMINATED, HIGHEST RETURN CODE=") ||
+ lastMessage.contains("DSNUGBAC - UTILITY BATCH MEMORY EXECUTION ABENDED"))) {
+ String message = "DSNUTILU TERMINATED WITH OUTPUT:\n";
+ for(List row : resultData) {
+ message += row.get(row.size()-1) + "\n";
+ }
+ results.setException(new SQLException(message));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return results;
+ }
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZConfigurationExtension.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZConfigurationExtension.java
new file mode 100644
index 0000000..6349f77
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZConfigurationExtension.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.util.Map;
+import lombok.Data;
+import org.flywaydb.core.extensibility.ConfigurationExtension;
+
+@Data
+public class DB2ZConfigurationExtension implements ConfigurationExtension {
+ private static final String DATABASE_NAME = "flyway.db2z.databaseName";
+ private static final String SQL_ID = "flyway.db2z.sqlId";
+
+ /**
+ * The database name for DB2 on z/OS (required for DB2 on z/OS)
+ */
+ private String databaseName = "";
+ /**
+ * The SQLID for DB2 on z/OS (does not necessarily match with schema)
+ */
+ private String sqlId = "";
+
+
+ @Override
+ public String getNamespace() {
+ return "db2z";
+ }
+
+ @Override
+ public void extractParametersFromConfiguration(Map configuration) {
+ databaseName = configuration.getOrDefault(DATABASE_NAME, databaseName);
+ sqlId = configuration.getOrDefault(SQL_ID, sqlId);
+ configuration.remove(DATABASE_NAME);
+ configuration.remove(SQL_ID);
+ }
+
+ @Override
+ public String getConfigurationParameterFromEnvironmentVariable(String environmentVariable) {
+ if ("FLYWAY_DB2Z_DATABASE_NAME".equals(environmentVariable)) {
+ return DATABASE_NAME;
+ }
+ if ("FLYWAY_DB2Z_SQL_ID".equals(environmentVariable)) {
+ return SQL_ID;
+ }
+ return null;
+ }
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZConnection.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZConnection.java
new file mode 100644
index 0000000..29d2d3b
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZConnection.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.sql.SQLException;
+import lombok.CustomLog;
+import org.flywaydb.core.internal.database.base.Connection;
+import org.flywaydb.core.internal.database.base.Schema;
+import org.flywaydb.core.internal.exception.FlywaySqlException;
+
+/**
+ * DB2 connection.
+ */
+@CustomLog
+public class DB2ZConnection extends Connection {
+ DB2ZConnection(DB2ZDatabase database, java.sql.Connection connection) {
+ super(database, connection);
+ this.jdbcTemplate = new DB2ZJdbcTemplate(connection, database.getDatabaseType());
+ }
+
+ @Override
+ protected String getCurrentSchemaNameOrSearchPath() throws SQLException {
+ return jdbcTemplate.queryForString("select current_schema from sysibm.sysdummy1");
+ }
+
+ @Override
+ public void changeCurrentSchemaTo(Schema schema) {
+ try {
+ if (!schema.exists()) {
+ return;
+ }
+ doChangeCurrentSchemaOrSearchPathTo(schema.getName());
+ } catch (SQLException e) {
+ String sqlId = (database.getSqlId() == "") ? schema.getName() : database.getSqlId();
+ LOG.info("SET CURRENT SQLID = '" + sqlId + "'");
+ LOG.info("SET SCHEMA " + database.quote(schema.getName()));
+ throw new FlywaySqlException("Error setting current sqlid and/or schema", e);
+ }
+ }
+
+ @Override
+ public void doChangeCurrentSchemaOrSearchPathTo(String schema) throws SQLException {
+ // Maybe sqlid not same as schema name and entered as config property
+ String sqlId = (database.getSqlId() == "") ? schema : database.getSqlId();
+ jdbcTemplate.execute("SET CURRENT SQLID = '" + sqlId + "'");
+ jdbcTemplate.execute("SET SCHEMA " + database.quote(schema));
+ }
+
+ @Override
+ public Schema getSchema(String name) {
+ return new DB2ZSchema(jdbcTemplate, database, name);
+ }
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZDatabase.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZDatabase.java
new file mode 100644
index 0000000..8337262
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZDatabase.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.flywaydb.core.api.configuration.Configuration;
+import org.flywaydb.core.extensibility.Tier;
+import org.flywaydb.core.internal.database.base.Database;
+import org.flywaydb.core.internal.database.base.Table;
+import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
+import org.flywaydb.core.internal.jdbc.StatementInterceptor;
+
+/**
+ * DB2 database.
+ */
+public class DB2ZDatabase extends Database {
+ private String name;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param configuration The Flyway configuration.
+ */
+ public DB2ZDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
+ super(configuration, jdbcConnectionFactory, statementInterceptor);
+ DB2ZConfigurationExtension configurationExtension = configuration.getPluginRegister().getPlugin(DB2ZConfigurationExtension.class);
+ name = configurationExtension.getDatabaseName();
+ }
+
+ @Override
+ protected DB2ZConnection doGetConnection(Connection connection) {
+ return new DB2ZConnection(this, connection);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getSqlId() {
+ DB2ZConfigurationExtension configurationExtension = configuration.getPluginRegister().getPlugin(DB2ZConfigurationExtension.class);
+ return configurationExtension.getSqlId();
+ }
+
+ @Override
+ public void ensureSupported(Configuration configuration) {
+ ensureDatabaseIsRecentEnough("10.0");
+
+ ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("11.0", Tier.PREMIUM, configuration);
+
+ recommendFlywayUpgradeIfNecessary("12.1");
+ }
+
+ @Override
+ public String getRawCreateScript(Table table, boolean baseline) {
+ String tableSpaceName = "SFLYWAY";
+ String configurationTablespaceName = configuration.getTablespace();
+ if(configurationTablespaceName != null) {
+ tableSpaceName = configurationTablespaceName;
+ }
+ // Maybe sqlid not same as schema name and entered as config property
+ String sqlId = (this.getSqlId() == "") ? table.getSchema().getName() : this.getSqlId();
+
+ return "SET CURRENT SQLID = '" + sqlId + "';\n" +
+ "SET CURRENT SCHEMA = '" + table.getSchema().getName() + "';\n" +
+ "CREATE TABLESPACE " + tableSpaceName + " IN \"" + name + "\" MAXPARTITIONS 1 LOCKSIZE ROW CLOSE YES COMPRESS YES;\n" +
+ "CREATE TABLE " + table + " (\n" +
+ " \"installed_rank\" INT NOT NULL,\n" +
+ " \"version\" VARCHAR(50),\n" +
+ " \"description\" VARCHAR(200) NOT NULL,\n" +
+ " \"type\" VARCHAR(20) NOT NULL,\n" +
+ " \"script\" VARCHAR(1000) NOT NULL,\n" +
+ " \"checksum\" INT,\n" +
+ " \"installed_by\" VARCHAR(100) NOT NULL,\n" +
+ " \"installed_on\" TIMESTAMP DEFAULT NOT NULL,\n" +
+ " \"execution_time\" INT NOT NULL,\n" +
+ " \"success\" SMALLINT NOT NULL,\n" +
+ " CONSTRAINT \"" + table.getName() + "_s\" CHECK (\"success\" in (0, 1))\n" +
+ ") IN \"" + name + "\"." + tableSpaceName + ";\n" +
+ "CREATE UNIQUE INDEX \"" + table.getSchema().getName() + "\".\"" + table.getName() + "_pk_idx\" ON " + table + " (\"installed_rank\");" +
+ "ALTER TABLE " + table + " ADD CONSTRAINT \"" + table.getName() + "_pk\" PRIMARY KEY (\"installed_rank\");\n" +
+ "CREATE INDEX \"" + table.getSchema().getName() + "\".\"" + table.getName() + "_s_idx\" ON " + table + " (\"success\");" +
+ (baseline ? getBaselineStatement(table) + ";\n" : "");
+ }
+
+ @Override
+ public String getSelectStatement(Table table) {
+ return super.getSelectStatement(table)
+ // Allow uncommitted reads so info can be invoked while migrate is running
+ + " WITH UR";
+ }
+
+ @Override
+ protected String doGetCurrentUser() throws SQLException {
+ return getMainConnection().getJdbcTemplate().queryForString("select USER from sysibm.sysdummy1");
+ }
+
+ @Override
+ public boolean supportsDdlTransactions() {
+ return true;
+ }
+
+ @Override
+ public String getBooleanTrue() {
+ return "1";
+ }
+
+ @Override
+ public String getBooleanFalse() {
+ return "0";
+ }
+
+ @Override
+ public String doQuote(String identifier) {
+ return "\"" + identifier + "\"";
+ }
+
+ @Override
+ public boolean catalogIsSchema() {
+ return false;
+ }
+
+ @Override
+ public boolean useSingleConnection() {
+ return true;
+ }
+
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZDatabaseType.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZDatabaseType.java
new file mode 100644
index 0000000..2ae3516
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZDatabaseType.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.sql.Connection;
+import java.sql.Types;
+import java.util.Properties;
+import org.flywaydb.community.database.DB2ZDatabaseExtension;
+import org.flywaydb.core.api.ResourceProvider;
+import org.flywaydb.core.api.configuration.Configuration;
+import org.flywaydb.core.internal.callback.CallbackExecutor;
+import org.flywaydb.core.internal.database.DatabaseType;
+import org.flywaydb.core.internal.database.base.BaseDatabaseType;
+import org.flywaydb.core.internal.database.base.CommunityDatabaseType;
+import org.flywaydb.core.internal.database.base.Database;
+import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
+import org.flywaydb.core.internal.jdbc.StatementInterceptor;
+import org.flywaydb.core.internal.parser.Parser;
+import org.flywaydb.core.internal.parser.ParsingContext;
+import org.flywaydb.core.internal.sqlscript.DefaultSqlScriptExecutor;
+import org.flywaydb.core.internal.sqlscript.SqlScriptExecutorFactory;
+
+public class DB2ZDatabaseType extends BaseDatabaseType implements CommunityDatabaseType {
+
+ public String getName() {
+ return "DB2 for z/OS";
+ }
+
+ @Override
+ public int getNullType() {
+ return Types.VARCHAR;
+ }
+
+ @Override
+ public boolean handlesJDBCUrl(String url) {
+ return url.startsWith("jdbc:db2:") || url.startsWith("jdbc:p6spy:db2:");
+ }
+
+ @Override
+ public String getDriverClass(String url, ClassLoader classLoader) {
+ if (url.startsWith("jdbc:p6spy:db2:")) {
+ return "com.p6spy.engine.spy.P6SpyDriver";
+ }
+ return "com.ibm.db2.jcc.DB2Driver";
+ }
+
+ @Override
+ public boolean handlesDatabaseProductNameAndVersion(String databaseProductName, String databaseProductVersion, Connection connection) {
+ return databaseProductName.startsWith("DB2") && databaseProductVersion.startsWith("DSN");
+ }
+
+ @Override
+ public Database createDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
+ return new DB2ZDatabase(configuration, jdbcConnectionFactory, statementInterceptor);
+ }
+
+ @Override
+ public Parser createParser(Configuration configuration, ResourceProvider resourceProvider, ParsingContext parsingContext) {
+ return new DB2ZParser(configuration, parsingContext);
+ }
+
+ @Override
+ public void setDefaultConnectionProps(String url, Properties props, ClassLoader classLoader) {
+ props.put("clientProgramName", APPLICATION_NAME);
+ props.put("retrieveMessagesFromServerOnGetMessage", "true");
+ }
+
+ @Override
+ public SqlScriptExecutorFactory createSqlScriptExecutorFactory(final JdbcConnectionFactory jdbcConnectionFactory,
+ final CallbackExecutor callbackExecutor,
+ final StatementInterceptor statementInterceptor) {
+ boolean supportsBatch = false;
+
+
+
+
+ final boolean finalSupportsBatch = supportsBatch;
+ final DatabaseType thisRef = this;
+
+ return (connection, undo, batch, outputQueryResults) -> new DefaultSqlScriptExecutor(new DB2ZJdbcTemplate(connection, thisRef),
+ callbackExecutor, undo, finalSupportsBatch && batch, outputQueryResults, statementInterceptor);
+ }
+
+ @Override
+ public int getPriority() {
+ // DB2/zOS needs to be checked in advance of DB2
+ return 1;
+ }
+
+ @Override
+ public String getPluginVersion(Configuration config) {
+ return DB2ZDatabaseExtension.readVersion();
+ }
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZFunction.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZFunction.java
new file mode 100644
index 0000000..22b63ee
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZFunction.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.sql.SQLException;
+import org.flywaydb.core.internal.database.base.Database;
+import org.flywaydb.core.internal.database.base.Function;
+import org.flywaydb.core.internal.database.base.Schema;
+import org.flywaydb.core.internal.jdbc.JdbcTemplate;
+
+/**
+ * DB2-specific function.
+ */
+public class DB2ZFunction extends Function {
+ /**
+ * Creates a new Db2 function.
+ *
+ * @param jdbcTemplate The Jdbc Template for communicating with the DB.
+ * @param database The database-specific support.
+ * @param schema The schema this function lives in.
+ * @param name The name of the function.
+ * @param args The arguments of the function.
+ */
+ DB2ZFunction(JdbcTemplate jdbcTemplate, Database database, Schema schema, String name, String... args) {
+ super(jdbcTemplate, database, schema, name, args);
+ }
+
+ @Override
+ protected void doDrop() throws SQLException {
+ jdbcTemplate.execute("DROP SPECIFIC FUNCTION " + database.quote(schema.getName(), name));
+ }
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZJdbcTemplate.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZJdbcTemplate.java
new file mode 100644
index 0000000..8982518
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZJdbcTemplate.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import org.flywaydb.core.internal.database.DatabaseType;
+import org.flywaydb.core.internal.jdbc.JdbcTemplate;
+import org.flywaydb.core.internal.jdbc.JdbcUtils;
+import org.flywaydb.core.internal.jdbc.Results;
+
+public class DB2ZJdbcTemplate extends JdbcTemplate {
+
+ public DB2ZJdbcTemplate(Connection connection, DatabaseType databaseType) {
+ super(connection, databaseType);
+ }
+
+ /**
+ * Executes this callable sql statement using a PreparedStatement.
+ *
+ * @param sql The statement to execute.
+ * @param params The statement parameters.
+ * @return the results of the execution.
+ */
+ public Results executeCallableStatement(String sql, Object... params) {
+ Results results = new Results();
+ PreparedStatement statement = null;
+ try {
+ statement = prepareStatement(sql, params);
+ boolean hasResults = statement.execute();
+ extractResults(results, statement, sql, hasResults);
+ extractWarnings(results, statement);
+ } catch (final SQLException e) {
+ extractErrors(results, e);
+ } finally {
+ JdbcUtils.closeStatement(statement);
+ }
+ return results;
+ }
+
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZParser.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZParser.java
new file mode 100644
index 0000000..4eb8210
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZParser.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import lombok.CustomLog;
+import org.flywaydb.core.api.configuration.Configuration;
+import org.flywaydb.core.internal.parser.Parser;
+import org.flywaydb.core.internal.parser.ParserContext;
+import org.flywaydb.core.internal.parser.ParsingContext;
+import org.flywaydb.core.internal.parser.PeekingReader;
+import org.flywaydb.core.internal.parser.Recorder;
+import org.flywaydb.core.internal.parser.StatementType;
+import org.flywaydb.core.internal.parser.Token;
+import org.flywaydb.core.internal.parser.TokenType;
+import org.flywaydb.core.internal.sqlscript.Delimiter;
+import org.flywaydb.core.internal.sqlscript.ParsedSqlStatement;
+
+@CustomLog
+public class DB2ZParser extends Parser {
+ private static final String COMMENT_DIRECTIVE = "--#";
+ private static final String SET_TERMINATOR_DIRECTIVE = COMMENT_DIRECTIVE + "SET TERMINATOR ";
+
+ public DB2ZParser(Configuration configuration, ParsingContext parsingContext) {
+ super(configuration, parsingContext, COMMENT_DIRECTIVE.length());
+ }
+
+ // WHILE and FOR both contain DO before the body of the block, so are both handled by the DO keyword
+ // See https://www.ibm.com/support/knowledgecenter/en/SSEPEK_10.0.0/sqlref/src/tpc/db2z_sqlplnativeintro.html
+ private static final List CONTROL_FLOW_KEYWORDS = Arrays.asList("LOOP", "CASE", "DO", "REPEAT", "IF");
+
+ private static final Pattern CREATE_IF_NOT_EXISTS = Pattern.compile(
+ ".*CREATE\\s([^\\s]+\\s){0,2}IF\\sNOT\\sEXISTS");
+ private static final Pattern DROP_IF_EXISTS = Pattern.compile(
+ ".*DROP\\s([^\\s]+\\s){0,2}IF\\sEXISTS");
+ private static final Pattern STORED_PROCEDURE_CALL = Pattern.compile(
+ "^CALL");
+ private static final StatementType DB2Z_CALL_STATEMENT = new StatementType();
+ // Do not assume first line is beginning of CALL statement. Maybe comment or whitelines first...
+ private static final Pattern DB2Z_CALL_WITH_PARMS_REGEX = Pattern.compile(
+ "CALL\\s+(?([^\\s]+\\.)?[^\\s]+)(\\(\\s*(?\\S.*)\\s*\\))", Pattern.CASE_INSENSITIVE);
+
+ //Split on comma if that comma has zero, or an even number of quotes ahead
+ private static final Pattern PARMS_SPLIT_REGEX = Pattern.compile(",(?=(?:[^']*'[^']*')*[^']*$)");
+ private static final Pattern STRING_PARM_REGEX = Pattern.compile("'.*'");
+ private static final Pattern INTEGER_PARM_REGEX = Pattern.compile("-?\\d+");
+
+ @Override
+ protected StatementType detectStatementType(String simplifiedStatement, ParserContext context, PeekingReader reader) {
+ LOG.debug("detectStatementType: simplifiedStatement=" + simplifiedStatement);
+ if (STORED_PROCEDURE_CALL.matcher(simplifiedStatement).matches()) {
+ LOG.debug("detectStatementType: DB2Z CALL statement found" );
+ return DB2Z_CALL_STATEMENT;
+ }
+ return super.detectStatementType(simplifiedStatement, context, reader);
+ }
+
+ @Override
+ protected ParsedSqlStatement createStatement(PeekingReader reader, Recorder recorder,
+ int statementPos, int statementLine, int statementCol,
+ int nonCommentPartPos, int nonCommentPartLine, int nonCommentPartCol,
+ StatementType statementType, boolean canExecuteInTransaction,
+ Delimiter delimiter, String sql, boolean batchable) throws IOException {
+ LOG.debug(sql);
+ if (statementType == DB2Z_CALL_STATEMENT) {
+ Matcher callMatcher = DB2Z_CALL_WITH_PARMS_REGEX.matcher(sql);
+ if(callMatcher.find()) {
+ String procName = callMatcher.group("procname");
+ String parmsString = callMatcher.group("args");
+ String[] parmStrings = PARMS_SPLIT_REGEX.split(parmsString);
+ Object[] parms = new Object[parmStrings.length];
+ for(int i = 0; i < parmStrings.length; i++) {
+ String prmTrimmed = parmStrings[i].trim();
+ LOG.debug("createStatement: DB2Z CALL with parms: " + procName + " " + prmTrimmed );
+ if (STRING_PARM_REGEX.matcher(prmTrimmed).matches()) {
+ //For string literals, remove the surrounding single quotes and
+ //de-escape any single quotes inside the string
+ parms[i] = prmTrimmed.substring(1, prmTrimmed.length() - 1).replace("''", "'");
+ } else if (INTEGER_PARM_REGEX.matcher(prmTrimmed).matches()) {
+ parms[i] = Integer.valueOf(prmTrimmed);
+ } else if (prmTrimmed.toUpperCase().equals("NULL")) {
+ parms[i] = null;
+ } else {
+ parms[i] = prmTrimmed;
+ }
+ }
+ return new DB2ZCallProcedureParsedStatement(statementPos, statementLine, statementCol,
+ sql, delimiter, canExecuteInTransaction, batchable, procName, parms);
+ }
+ }
+ LOG.debug("createStatement: DB2Z CALL no parms " + statementType + " " + sql);
+ return super.createStatement(reader, recorder, statementPos, statementLine, statementCol,
+ nonCommentPartPos, nonCommentPartLine, nonCommentPartCol,
+ statementType, canExecuteInTransaction, delimiter, sql, batchable
+ );
+ }
+
+ @Override
+ protected void adjustBlockDepth(ParserContext context, List tokens, Token keyword, PeekingReader reader) throws IOException {
+ boolean previousTokenIsKeyword = !tokens.isEmpty() && tokens.get(tokens.size() - 1).getType() == TokenType.KEYWORD;
+
+ int lastKeywordIndex = getLastKeywordIndex(tokens);
+ String previousKeyword = lastKeywordIndex >= 0 ? tokens.get(lastKeywordIndex).getText() : null;
+
+ lastKeywordIndex = getLastKeywordIndex(tokens, lastKeywordIndex);
+ String previousPreviousToken = lastKeywordIndex >= 0 ? tokens.get(lastKeywordIndex).getText() : null;
+
+ if (
+ // BEGIN increases block depth, exception when used with ROW BEGIN
+ ("BEGIN".equals(keyword.getText()) && (!"ROW".equals(previousKeyword) || previousPreviousToken == null || "EACH".equals(previousPreviousToken)))
+ // Control flow keywords increase depth
+ || CONTROL_FLOW_KEYWORDS.contains(keyword.getText())
+ ) {
+ // But not END IF and END WHILE
+ if (!previousTokenIsKeyword || !"END".equals(previousKeyword)) {
+ context.increaseBlockDepth(keyword.getText());
+
+ }
+ } else if (
+ // END decreases block depth, exception when used with ROW END
+ ("END".equals(keyword.getText()) && !"ROW".equals(previousKeyword))
+ || doTokensMatchPattern(tokens, keyword, CREATE_IF_NOT_EXISTS)
+ || doTokensMatchPattern(tokens, keyword, DROP_IF_EXISTS)) {
+ context.decreaseBlockDepth();
+ }
+ }
+
+ @Override
+ protected void resetDelimiter(ParserContext context) {
+ // Do not reset delimiter as delimiter changes survive beyond a single statement
+ }
+
+ @Override
+ protected boolean isCommentDirective(String peek) {
+ return peek.startsWith(COMMENT_DIRECTIVE);
+ }
+
+ @Override
+ protected Token handleCommentDirective(PeekingReader reader, ParserContext context, int pos, int line, int col) throws IOException {
+ if (SET_TERMINATOR_DIRECTIVE.equals(reader.peek(SET_TERMINATOR_DIRECTIVE.length()))) {
+ reader.swallow(SET_TERMINATOR_DIRECTIVE.length());
+ String delimiter = reader.readUntilExcluding('\n', '\r');
+ return new Token(TokenType.NEW_DELIMITER, pos, line, col, delimiter.trim(), delimiter, context.getParensDepth());
+ }
+ reader.swallowUntilExcluding('\n', '\r');
+ return new Token(TokenType.COMMENT, pos, line, col, null, null, context.getParensDepth());
+ }
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZSchema.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZSchema.java
new file mode 100644
index 0000000..37a3400
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZSchema.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.flywaydb.community.database.db2z;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.CustomLog;
+import org.flywaydb.core.internal.database.base.Function;
+import org.flywaydb.core.internal.database.base.Schema;
+import org.flywaydb.core.internal.database.base.Table;
+import org.flywaydb.core.internal.database.base.Type;
+import org.flywaydb.core.internal.jdbc.JdbcTemplate;
+
+/**
+ * DB2 implementation of Schema.
+ */
+@CustomLog
+public class DB2ZSchema extends Schema {
+ /**
+ * Creates a new DB2 schema.
+ *
+ * @param jdbcTemplate The Jdbc Template for communicating with the DB.
+ * @param database The database-specific support.
+ * @param name The name of the schema.
+ */
+ DB2ZSchema(JdbcTemplate jdbcTemplate, DB2ZDatabase database, String name) {
+ super(jdbcTemplate, database, name);
+ }
+
+ @Override
+ protected boolean doExists() throws SQLException {
+ /**
+ * For DB2 on z/OS, a schema is not an object that can be created or dropped and is not listed in the catalog.
+ * Instead, we do need to check whether the database exists (which is a container for tablespaces and other storage related objects)
+ */
+ return jdbcTemplate.queryForInt("SELECT COUNT(*) FROM sysibm.sysdatabase WHERE name=?", database.getName()) > 0;
+ }
+
+ @Override
+ protected boolean doEmpty() throws SQLException {
+ int objectCount = jdbcTemplate.queryForInt("select count(*) from sysibm.systables where dbname = ? AND creator = ?", database.getName(), name);
+ objectCount += jdbcTemplate.queryForInt("select count(*) from sysibm.syssequences where schema = ?", name);
+ objectCount += jdbcTemplate.queryForInt("select count(*) from sysibm.sysindexes where creator = ?", name);
+ objectCount += jdbcTemplate.queryForInt("select count(*) from sysibm.sysroutines where schema = ?", name);
+ objectCount += jdbcTemplate.queryForInt("select count(*) from sysibm.systriggers where schema = ?", name);
+ return objectCount == 0;
+ }
+
+ @Override
+ protected void doCreate() throws SQLException {
+ throw new UnsupportedOperationException("Create Schema - is not supported in db2 on zOS");
+ }
+
+ @Override
+ protected void doDrop() throws SQLException {
+ throw new UnsupportedOperationException("Drop Schema - is not supported in db2 on zOS");
+ }
+
+ @Override
+ protected void doClean() throws SQLException {
+ // MQTs are dropped when the backing views or tables are dropped
+ // Indexes in DB2 are dropped when the corresponding table is dropped
+
+ // drop versioned table link -> not supported for DB2 9.x
+ List dropVersioningStatements = generateDropVersioningStatement();
+ if (!dropVersioningStatements.isEmpty()) {
+ // Do a explicit drop of MQTs in order to be able to drop the Versioning
+ for (String dropTableStatement : generateDropStatements("M", "TABLE")) {
+ jdbcTemplate.execute(dropTableStatement);
+ }
+ }
+
+ for (String dropVersioningStatement : dropVersioningStatements) {
+ jdbcTemplate.execute(dropVersioningStatement);
+ }
+
+ // diable archiving on table
+ List disableArchivingStatements = generateDisableArchivingStatement();
+ if (!disableArchivingStatements.isEmpty()) {
+ // Do a explicit drop of MQTs in order to be able to drop the Versioning
+ for (String dropTableStatement : generateDropStatements("M", "TABLE")) {
+ jdbcTemplate.execute(dropTableStatement);
+ }
+ }
+
+ for (String disableArchivingStatement : disableArchivingStatements) {
+ jdbcTemplate.execute(disableArchivingStatement);
+ }
+
+ // views
+ /* We need to query for all views in schema after each DROP because of a
+ * specific property in z/OS to DROP dependent nested views (views depending on other views).
+ */
+ List dropStatements = generateDropStatements("V", "VIEW");
+ while(dropStatements.size() != 0) {
+ String dropStatement = dropStatements.get(0);
+ jdbcTemplate.execute(dropStatement);
+ dropStatements = generateDropStatements("V", "VIEW");
+ }
+
+ // aliases
+ for (String dropStatement : generateDropStatements("A", "ALIAS")) {
+ jdbcTemplate.execute(dropStatement);
+ }
+
+ for (Table table : allTables()) {
+ table.drop();
+ }
+
+ // temporary Tables
+ for (String dropStatement : generateDropStatements("G", "TABLE")) {
+ jdbcTemplate.execute(dropStatement);
+ }
+
+ // explicit tablespace
+ for (String dropStatement : generateDropStatementsForRegularTablespace()) {
+ jdbcTemplate.execute(dropStatement);
+ }
+
+ for (String dropStatement : generateDropStatementsForLobTablespace()) {
+ jdbcTemplate.execute(dropStatement);
+ }
+
+ // sequences
+ for (String dropStatement : generateDropStatementsForSequences()) {
+ jdbcTemplate.execute(dropStatement);
+ }
+
+ // procedures
+ for (String dropStatement : generateDropStatementsForProcedures()) {
+ jdbcTemplate.execute(dropStatement);
+ }
+
+ // triggers
+ for (String dropStatement : generateDropStatementsForTriggers()) {
+ jdbcTemplate.execute(dropStatement);
+ }
+
+ for (Function function : allFunctions()) {
+ function.drop();
+ }
+
+ // types. TODO: find out, why generic drop type function is not working at all times with Db2Z
+ // For now, call the one that is working for sure
+ for (String dropStatement : generateDropStatementsForTypes()) {
+ jdbcTemplate.execute(dropStatement);
+ }
+
+ for (Type type : allTypes()) {
+ type.drop();
+ }
+ }
+
+ private String getSqlId() {
+ /**
+ * Get SQLID.
+ * When sqlid not set, implicitly use schema name for sqlid
+ */
+ String sqlId = (database.getSqlId() == "") ?name : database.getSqlId();
+ return sqlId;
+ }
+
+ /**
+ * Generates DROP statements for the procedures in this schema.
+ *
+ * @return The drop statements.
+ * @throws SQLException when the statements could not be generated.
+ */
+ private List generateDropStatementsForProcedures() throws SQLException {
+ String dropProcGenQuery = "select rtrim(NAME) from SYSIBM.SYSROUTINES where CAST_FUNCTION = 'N' " +
+ " and ROUTINETYPE = 'P' and SCHEMA = '" + name + "' and OWNER = '" + this.getSqlId() + "'";
+ return buildDropStatements("DROP PROCEDURE", dropProcGenQuery);
+ }
+
+ /**
+ * Generates DROP statements for the sequences in this schema.
+ *
+ * @return The drop statements.
+ * @throws SQLException when the statements could not be generated.
+ */
+ private List generateDropStatementsForSequences() throws SQLException {
+ String dropSeqGenQuery = "select rtrim(NAME) from SYSIBM.SYSSEQUENCES where SCHEMA = '" + name
+ + "' and SEQTYPE='S' and OWNER = '" + this.getSqlId() + "'";
+ return buildDropStatements("DROP SEQUENCE", dropSeqGenQuery);
+ }
+
+ /**
+ * Generates DROP statements for the explicitly-created tablespaces in this database with the schema user as creator.
+ *
+ * @return The drop statements.
+ * @throws SQLException when the statements could not be generated.
+ */
+ private List generateDropStatementsForRegularTablespace() throws SQLException {
+ //Only drop explicitly created tablespaces for current database and created under this specific schema authorization ID
+ //Note that this also drops the related table for partitioned tablespaces.
+ String dropTablespaceGenQuery = "select rtrim(NAME) FROM SYSIBM.SYSTABLESPACE where IMPLICIT = 'N' AND DBNAME = '" + database.getName() + "' AND CREATOR = '" + this.getSqlId() + "' AND TYPE <> 'O'";
+
+ List dropStatements = new ArrayList<>();
+ List dbObjects = jdbcTemplate.queryForStringList(dropTablespaceGenQuery);
+ for (String dbObject : dbObjects) {
+ LOG.debug("DROP TABLESPACE " + database.quote(database.getName(), dbObject));
+ dropStatements.add("DROP TABLESPACE " + database.quote(database.getName(), dbObject));
+ }
+ return dropStatements;
+ }
+
+ private List generateDropStatementsForLobTablespace() throws SQLException {
+ String dropTablespaceGenQuery = "select rtrim(NAME) FROM SYSIBM.SYSTABLESPACE where IMPLICIT = 'N' AND DBNAME = '" + database.getName() + "' AND CREATOR = '" + this.getSqlId() + "' AND TYPE = 'O'";
+
+ List dropStatements = new ArrayList<>();
+ List dbObjects = jdbcTemplate.queryForStringList(dropTablespaceGenQuery);
+ for (String dbObject : dbObjects) {
+ LOG.debug("DROP TABLESPACE " + database.quote(database.getName(), dbObject));
+ dropStatements.add("DROP TABLESPACE " + database.quote(database.getName(), dbObject));
+ }
+ return dropStatements;
+ }
+
+ /**
+ * Generates DROP statements for this type of table, representing this type of object in this schema.
+ *
+ * @param tableType The type of table (Can be T, V, S, ...).
+ * @param objectType The type of object.
+ * @return The drop statements.
+ * @throws SQLException when the statements could not be generated.
+ */
+ private List generateDropStatements(String tableType, String objectType) throws SQLException {
+ String dropTablesGenQuery = "select rtrim(NAME) from SYSIBM.SYSTABLES where TYPE='" + tableType + "' and OWNER = '" + this.getSqlId() + "' AND CREATOR = '" + name + "'";
+ return buildDropStatements("DROP " + objectType, dropTablesGenQuery);
+ }
+
+ /**
+ * Generates DROP statements for the triggers in this schema.
+ *
+ * @return The drop statements.
+ * @throws SQLException when the statements could not be generated.
+ */
+ private List generateDropStatementsForTriggers() throws SQLException {
+ String dropTrigGenQuery = "select TRIGNAME from SYSIBM.SYSTRIGGERS where SCHEMA = '" + name + "' and OWNER = '" + this.getSqlId() + "'";
+ LOG.debug(dropTrigGenQuery);
+ return buildDropStatements("DROP TRIGGER", dropTrigGenQuery);
+ }
+
+ /**
+ * Generates DROP statements for the types in this schema.
+ *
+ * @return The drop statements.
+ * @throws SQLException when the statements could not be generated.
+ */
+ private List generateDropStatementsForTypes() throws SQLException {
+ String dropProcGenQuery = "select rtrim(NAME) from SYSIBM.SYSROUTINES where CAST_FUNCTION = 'Y' " +
+ " and ROUTINETYPE = 'T' and SCHEMA = '" + name + "' and OWNER = '" + this.getSqlId() + "'";
+ return buildDropStatements("DROP PROCEDURE", dropProcGenQuery);
+ }
+
+ /**
+ * Builds the drop statements for database objects in this schema.
+ *
+ * @param dropPrefix The drop command for the database object (e.g. 'drop table').
+ * @param query The query to get all present database objects
+ * @return The statements.
+ * @throws SQLException when the drop statements could not be built.
+ */
+ private List buildDropStatements(final String dropPrefix, final String query) throws SQLException {
+ List dropStatements = new ArrayList<>();
+ List dbObjects = jdbcTemplate.queryForStringList(query);
+ for (String dbObject : dbObjects) {
+ LOG.debug(dropPrefix + " " + database.quote(name, dbObject));
+ dropStatements.add(dropPrefix + " " + database.quote(name, dbObject));
+ }
+ return dropStatements;
+ }
+
+ /**
+ * @return All tables that have versioning associated with them.
+ */
+ private List generateDropVersioningStatement() throws SQLException {
+ List dropVersioningStatements = new ArrayList<>();
+ Table[] versioningTables = findTables("select rtrim(NAME) from SYSIBM.SYSTABLES where VERSIONING_TABLE <> '' and CREATOR = '" + name + "' and OWNER = '" + this.getSqlId() + "'");
+ for (Table table : versioningTables) {
+ LOG.debug("ALTER TABLE " + table.toString() + " DROP VERSIONING");
+ dropVersioningStatements.add("ALTER TABLE " + table.toString() + " DROP VERSIONING");
+ }
+
+ return dropVersioningStatements;
+ }
+
+ /**
+ * @return All tables that have archiving associated with them.
+ */
+ private List generateDisableArchivingStatement() throws SQLException {
+ List dropArchivingStatements = new ArrayList<>();
+ Table[] archivingTables = findTables("select rtrim(NAME) from SYSIBM.SYSTABLES where ARCHIVING_TABLE <> '' and CREATOR = '" + name + "' and OWNER = '" + this.getSqlId() + "'");
+ for (Table table : archivingTables) {
+ LOG.debug("ALTER TABLE " + table.toString() + " DISABLE ARCHIVE");
+ dropArchivingStatements.add("ALTER TABLE " + table.toString() + " DISABLE ARCHIVE");
+ }
+ return dropArchivingStatements;
+ }
+
+ private DB2ZTable[] findTables(String sqlQuery, String... params) throws SQLException {
+ List tableNames = jdbcTemplate.queryForStringList(sqlQuery, params);
+ DB2ZTable[] tables = new DB2ZTable[tableNames.size()];
+ for (int i = 0; i < tableNames.size(); i++) {
+ tables[i] = new DB2ZTable(jdbcTemplate, database, this, tableNames.get(i));
+ }
+ return tables;
+ }
+
+ @Override
+ protected DB2ZTable[] doAllTables() throws SQLException {
+ return findTables("select rtrim(NAME) from SYSIBM.SYSTABLES where TYPE='T' and CREATOR = '" + name + "' and OWNER = '" + this.getSqlId() + "'");
+ }
+
+ @Override
+ protected Function[] doAllFunctions() throws SQLException {
+ List functionNames = jdbcTemplate.queryForStringList(
+ "select rtrim(SPECIFICNAME) from SYSIBM.SYSROUTINES where"
+ // Functions only
+ + " ROUTINETYPE='F'"
+ // That aren't system-generated or built-in
+ + " AND ORIGIN IN ("
+ + "'E', " // User-defined, external
+ + "'M', " // Template function
+ + "'Q', " // SQL-bodied
+ + "'U')" // User-defined, based on a source
+ + " and SCHEMA = '" + name + "' and OWNER = '" + this.getSqlId() + "'");
+
+ List functions = new ArrayList<>();
+ for (String functionName : functionNames) {
+ functions.add(getFunction(functionName));
+ }
+
+ return functions.toArray(new Function[0]);
+ }
+
+ @Override
+ public Table getTable(String tableName) {
+ return new DB2ZTable(jdbcTemplate, database, this, tableName);
+ }
+
+ @Override
+ protected Type getType(String typeName) {
+ return new DB2ZType(jdbcTemplate, database, this, typeName);
+ }
+
+ @Override
+ public Function getFunction(String functionName, String... args) {
+ return new DB2ZFunction(jdbcTemplate, database, this, functionName, args);
+ }
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZTable.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZTable.java
new file mode 100644
index 0000000..db36c28
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZTable.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.sql.SQLException;
+import lombok.CustomLog;
+import org.flywaydb.core.api.logging.Log;
+import org.flywaydb.core.api.logging.LogFactory;
+import org.flywaydb.core.internal.database.base.Table;
+import org.flywaydb.core.internal.jdbc.JdbcTemplate;
+
+/**
+ * Db2-specific table.
+ */
+@CustomLog
+public class DB2ZTable extends Table {
+
+ /**
+ * Creates a new Db2 table.
+ *
+ * @param jdbcTemplate The Jdbc Template for communicating with the DB.
+ * @param database The database-specific support.
+ * @param schema The schema this table lives in.
+ * @param name The name of the table.
+ */
+ DB2ZTable(JdbcTemplate jdbcTemplate, DB2ZDatabase database, DB2ZSchema schema, String name) {
+ super(jdbcTemplate, database, schema, name);
+ }
+
+ @Override
+ protected void doDrop() throws SQLException {
+
+ String dbName = jdbcTemplate.queryForString("SELECT DBNAME FROM SYSIBM.SYSTABLES WHERE NAME=? AND CREATOR=?", this.getName(), this.getSchema().getName());
+ String tableSpaceName = jdbcTemplate.queryForString("SELECT TSNAME FROM SYSIBM.SYSTABLES WHERE NAME=? AND CREATOR=?", this.getName(), this.getSchema().getName());
+ //Use sqlid as creator with tablespace. When sqlid is not set, implicitly use schema name for sqlid
+ String sqlId = (database.getSqlId() == "") ? this.getSchema().getName() : database.getSqlId();
+ String implicit = jdbcTemplate.queryForString("SELECT IMPLICIT FROM SYSIBM.SYSTABLESPACE WHERE DBNAME=? AND CREATOR=? AND NAME=?", dbName, sqlId, tableSpaceName);
+ String tableSpaceType = jdbcTemplate.queryForString("SELECT TYPE FROM SYSIBM.SYSTABLESPACE WHERE DBNAME=? AND CREATOR=? AND NAME=?", dbName, sqlId, tableSpaceName);
+
+ if (implicit == null || implicit.isEmpty()) {
+ LOG.debug("Nothing to drop because table " + this.getName() + " does exist on tablespace " + tableSpaceName + " but with creator other than " + sqlId);
+ } else {
+ if (implicit.equals("N") && (tableSpaceType.equals("G") || tableSpaceType.equals("R"))) {
+ //Tablespace will be dropped by DB2ZSchema.doClean()
+ LOG.debug("Table '" + this + "' cannot be dropped directly (tableSpaceName=" + tableSpaceName + ", implicit=" + implicit + ", tableSpaceType=" + tableSpaceType + ")");
+ } else {
+ LOG.debug("Dropping table " + this + " ...");
+ jdbcTemplate.execute("DROP TABLE " + this);
+ }
+ }
+ }
+
+ @Override
+ protected boolean doExists() throws SQLException {
+ return exists(null, schema, name);
+ }
+
+ @Override
+ protected void doLock() throws SQLException {
+ jdbcTemplate.update("lock table " + this + " in exclusive mode");
+ }
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZType.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZType.java
new file mode 100644
index 0000000..e7c0610
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/DB2ZType.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.flywaydb.community.database.db2z;
+
+import java.sql.SQLException;
+import org.flywaydb.core.internal.database.base.Type;
+import org.flywaydb.core.internal.jdbc.JdbcTemplate;
+
+/**
+ * Db2-specific type.
+ */
+public class DB2ZType extends Type {
+ /**
+ * Creates a new Db2 type.
+ *
+ * @param jdbcTemplate The Jdbc Template for communicating with the DB.
+ * @param database The database-specific support.
+ * @param schema The schema this type lives in.
+ * @param name The name of the type.
+ */
+ DB2ZType(JdbcTemplate jdbcTemplate, DB2ZDatabase database, DB2ZSchema schema, String name) {
+ super(jdbcTemplate, database, schema, name);
+ }
+
+ @Override
+ protected void doDrop() throws SQLException {
+ jdbcTemplate.execute("DROP TYPE " + database.quote(schema.getName(), name));
+ }
+}
diff --git a/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/package-info.java b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/package-info.java
new file mode 100644
index 0000000..43b9a17
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/java/org/flywaydb/community/database/db2z/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Red Gate Software Ltd 2010-2022
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Private API. No compatibility guarantees provided.
+ */
+package org.flywaydb.community.database.db2z;
diff --git a/flyway-database-db2zOS/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin b/flyway-database-db2zOS/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin
new file mode 100644
index 0000000..3dd3ba3
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin
@@ -0,0 +1,2 @@
+org.flywaydb.community.database.db2z.DB2ZDatabaseType
+org.flywaydb.community.database.db2z.DB2ZConfigurationExtension
diff --git a/flyway-database-db2zOS/src/main/resources/org/flywaydb/community/database/db2z/version.txt b/flyway-database-db2zOS/src/main/resources/org/flywaydb/community/database/db2z/version.txt
new file mode 100644
index 0000000..1785151
--- /dev/null
+++ b/flyway-database-db2zOS/src/main/resources/org/flywaydb/community/database/db2z/version.txt
@@ -0,0 +1 @@
+${pom.version}
\ No newline at end of file
diff --git a/flyway-database-ignite/pom.xml b/flyway-database-ignite/pom.xml
index e1788d3..9a1d56f 100644
--- a/flyway-database-ignite/pom.xml
+++ b/flyway-database-ignite/pom.xml
@@ -23,7 +23,7 @@
org.flywaydb
flyway-community-db-support
- 10.13.0
+ 10.14.0
flyway-database-ignite
diff --git a/flyway-database-oceanbase/pom.xml b/flyway-database-oceanbase/pom.xml
index 887909c..0ce0bb7 100644
--- a/flyway-database-oceanbase/pom.xml
+++ b/flyway-database-oceanbase/pom.xml
@@ -23,7 +23,7 @@
org.flywaydb
flyway-community-db-support
- 10.13.0
+ 10.14.0
flyway-database-oceanbase
diff --git a/flyway-database-tidb/pom.xml b/flyway-database-tidb/pom.xml
index 8b4db54..c669189 100644
--- a/flyway-database-tidb/pom.xml
+++ b/flyway-database-tidb/pom.xml
@@ -23,7 +23,7 @@
org.flywaydb
flyway-community-db-support
- 10.13.0
+ 10.14.0
flyway-database-tidb
diff --git a/flyway-database-yugabytedb/pom.xml b/flyway-database-yugabytedb/pom.xml
index 8a907d6..7f1a35f 100644
--- a/flyway-database-yugabytedb/pom.xml
+++ b/flyway-database-yugabytedb/pom.xml
@@ -23,7 +23,7 @@
org.flywaydb
flyway-community-db-support
- 10.13.0
+ 10.14.0
flyway-database-yugabytedb
diff --git a/pom.xml b/pom.xml
index 5bdc3db..3f3bb82 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
flyway-community-db-support
pom
- 10.13.0
+ 10.14.0
${project.artifactId}
@@ -39,10 +39,11 @@
flyway-database-oceanbase
flyway-database-databricks
flyway-community-db-support-archetype
+ flyway-database-db2zOS
- 10.13.0
+ 10.14.0