From c03db5e0f054a2e774bb4893f28a9772729355bd Mon Sep 17 00:00:00 2001 From: w-seok Date: Tue, 30 Jul 2024 14:33:27 +0900 Subject: [PATCH 01/34] init --- flyway-database-tibero/pom.xml | 21 +++++++++++++++++++++ pom.xml | 1 + 2 files changed, 22 insertions(+) create mode 100644 flyway-database-tibero/pom.xml diff --git a/flyway-database-tibero/pom.xml b/flyway-database-tibero/pom.xml new file mode 100644 index 0000000..c188855 --- /dev/null +++ b/flyway-database-tibero/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + org.flywaydb + flyway-community-db-support + 10.16.0 + + + com.tmax + flyway-database-tibero + + + 21 + 21 + UTF-8 + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 097c008..6e9d51c 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ flyway-database-databricks flyway-database-db2zos flyway-community-db-support-archetype + flyway-database-tibero From 1036172ae470d993de0b7b6dfe81f2a2a5d16b86 Mon Sep 17 00:00:00 2001 From: birdie Date: Tue, 30 Jul 2024 15:48:58 +0900 Subject: [PATCH 02/34] flyway for tibero structure setting --- flyway-database-tibero/pom.xml | 43 ++++++++++++--- .../database/TiberoDatabaseExtension.java | 6 +++ .../database/tibero/TiberoConnection.java | 22 ++++++++ .../database/tibero/TiberoDatabase.java | 52 +++++++++++++++++++ .../database/tibero/TiberoDatabaseType.java | 52 +++++++++++++++++++ .../database/tibero/TiberoParser.java | 12 +++++ .../database/tibero/TiberoSchema.java | 49 +++++++++++++++++ .../database/tibero/TiberoTable.java | 27 ++++++++++ .../org.flywaydb.core.extensibility.Plugin | 1 + 9 files changed, 256 insertions(+), 8 deletions(-) create mode 100644 flyway-database-tibero/src/main/java/org/flywaydb/community/database/TiberoDatabaseExtension.java create mode 100644 flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoConnection.java create mode 100644 flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java create mode 100644 flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabaseType.java create mode 100644 flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoParser.java create mode 100644 flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java create mode 100644 flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java create mode 100644 flyway-database-tibero/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin diff --git a/flyway-database-tibero/pom.xml b/flyway-database-tibero/pom.xml index c188855..bc85afe 100644 --- a/flyway-database-tibero/pom.xml +++ b/flyway-database-tibero/pom.xml @@ -1,21 +1,48 @@ + + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + org.flywaydb flyway-community-db-support 10.16.0 - com.tmax flyway-database-tibero + ${project.artifactId} + + + + ${project.groupId} + flyway-core + + + + + + + + + - - 21 - 21 - UTF-8 - + + + + src/main/resources + true + + + + + maven-resources-plugin + + + maven-jar-plugin + + + \ No newline at end of file diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/TiberoDatabaseExtension.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/TiberoDatabaseExtension.java new file mode 100644 index 0000000..6d96335 --- /dev/null +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/TiberoDatabaseExtension.java @@ -0,0 +1,6 @@ +package org.flywaydb.community.database; + +import org.flywaydb.core.extensibility.PluginMetadata; + +public class TiberoDatabaseExtension implements PluginMetadata { +} diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoConnection.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoConnection.java new file mode 100644 index 0000000..e1b5c88 --- /dev/null +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoConnection.java @@ -0,0 +1,22 @@ +package org.flywaydb.community.database.tibero; + +import java.sql.SQLException; +import org.flywaydb.core.internal.database.base.Connection; +import org.flywaydb.core.internal.database.base.Schema; + +public class TiberoConnection extends Connection { + + protected TiberoConnection(TiberoDatabase database, java.sql.Connection connection) { + super(database, connection); + } + + @Override + protected String getCurrentSchemaNameOrSearchPath() throws SQLException { + return ""; + } + + @Override + public Schema getSchema(String s) { + return null; + } +} diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java new file mode 100644 index 0000000..d2f75f7 --- /dev/null +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java @@ -0,0 +1,52 @@ +package org.flywaydb.community.database.tibero; + +import java.sql.Connection; +import org.flywaydb.core.api.configuration.Configuration; +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; + + +public class TiberoDatabase extends Database { + + public TiberoDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, + StatementInterceptor statementInterceptor) { + super(configuration, jdbcConnectionFactory, statementInterceptor); + } + + @Override + protected TiberoConnection doGetConnection(Connection connection) { + return null; + } + + @Override + public void ensureSupported(Configuration configuration) { + + } + + @Override + public boolean supportsDdlTransactions() { + return false; + } + + @Override + public String getBooleanTrue() { + return ""; + } + + @Override + public String getBooleanFalse() { + return ""; + } + + @Override + public boolean catalogIsSchema() { + return false; + } + + @Override + public String getRawCreateScript(Table table, boolean b) { + return ""; + } +} diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabaseType.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabaseType.java new file mode 100644 index 0000000..1a737b0 --- /dev/null +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabaseType.java @@ -0,0 +1,52 @@ +package org.flywaydb.community.database.tibero; + +import java.sql.Connection; +import org.flywaydb.core.api.ResourceProvider; +import org.flywaydb.core.api.configuration.Configuration; +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; + +public class TiberoDatabaseType extends BaseDatabaseType implements CommunityDatabaseType { + + @Override + public String getName() { + return ""; + } + + @Override + public int getNullType() { + return 0; + } + + @Override + public boolean handlesJDBCUrl(String s) { + return false; + } + + @Override + public String getDriverClass(String s, ClassLoader classLoader) { + return ""; + } + + @Override + public boolean handlesDatabaseProductNameAndVersion(String s, String s1, Connection connection) { + return false; + } + + @Override + public Database createDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, + StatementInterceptor statementInterceptor) { + return null; + } + + @Override + public Parser createParser(Configuration configuration, ResourceProvider resourceProvider, + ParsingContext parsingContext) { + return null; + } +} diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoParser.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoParser.java new file mode 100644 index 0000000..16fd2ce --- /dev/null +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoParser.java @@ -0,0 +1,12 @@ +package org.flywaydb.community.database.tibero; + +import org.flywaydb.core.api.configuration.Configuration; +import org.flywaydb.core.internal.parser.Parser; +import org.flywaydb.core.internal.parser.ParsingContext; + +public class TiberoParser extends Parser { + + protected TiberoParser(Configuration configuration, ParsingContext parsingContext, int peekDepth) { + super(configuration, parsingContext, peekDepth); + } +} diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java new file mode 100644 index 0000000..d3147d5 --- /dev/null +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java @@ -0,0 +1,49 @@ +package org.flywaydb.community.database.tibero; + + +import java.sql.SQLException; +import org.flywaydb.core.internal.database.base.Schema; +import org.flywaydb.core.internal.database.base.Table; +import org.flywaydb.core.internal.jdbc.JdbcTemplate; + +public class TiberoSchema extends Schema { + + public TiberoSchema(JdbcTemplate jdbcTemplate, TiberoDatabase database, String name) { + super(jdbcTemplate, database, name); + } + + @Override + protected boolean doExists() throws SQLException { + return false; + } + + @Override + protected boolean doEmpty() throws SQLException { + return false; + } + + @Override + protected void doCreate() throws SQLException { + + } + + @Override + protected void doDrop() throws SQLException { + + } + + @Override + protected void doClean() throws SQLException { + + } + + @Override + protected TiberoTable[] doAllTables() throws SQLException { + return new TiberoTable[0]; + } + + @Override + public Table getTable(String s) { + return null; + } +} diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java new file mode 100644 index 0000000..8375d23 --- /dev/null +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java @@ -0,0 +1,27 @@ +package org.flywaydb.community.database.tibero; + +import java.sql.SQLException; +import org.flywaydb.core.internal.database.base.Table; +import org.flywaydb.core.internal.jdbc.JdbcTemplate; + +public class TiberoTable extends Table { + + public TiberoTable(JdbcTemplate jdbcTemplate, TiberoDatabase database, TiberoSchema schema, String name) { + super(jdbcTemplate, database, schema, name); + } + + @Override + protected boolean doExists() throws SQLException { + return false; + } + + @Override + protected void doLock() throws SQLException { + + } + + @Override + protected void doDrop() throws SQLException { + + } +} diff --git a/flyway-database-tibero/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin b/flyway-database-tibero/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin new file mode 100644 index 0000000..da9a3f5 --- /dev/null +++ b/flyway-database-tibero/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin @@ -0,0 +1 @@ +org.flywaydb.community.database.tibero.TiberoDatabaseType From fa0f4daae0e778720a2460467d97d3ad00ea58ad Mon Sep 17 00:00:00 2001 From: w-seok Date: Thu, 1 Aug 2024 09:57:23 +0900 Subject: [PATCH 03/34] feat: add TiberoConnection --- .../database/tibero/TiberoConnection.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoConnection.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoConnection.java index e1b5c88..11f2e6a 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoConnection.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoConnection.java @@ -12,11 +12,23 @@ protected TiberoConnection(TiberoDatabase database, java.sql.Connection connecti @Override protected String getCurrentSchemaNameOrSearchPath() throws SQLException { - return ""; + return jdbcTemplate.queryForString("SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL"); } @Override - public Schema getSchema(String s) { - return null; + public void doChangeCurrentSchemaOrSearchPathTo(String schema) throws SQLException { + jdbcTemplate.execute("ALTER SESSION SET CURRENT_SCHEMA=" + database.quote(schema)); + } + + @Override + public Schema doGetCurrentSchema() throws SQLException { + String currentSchema = getCurrentSchemaNameOrSearchPath(); + + return getSchema(currentSchema); + } + + @Override + public Schema getSchema(String name) { + return new TiberoSchema(jdbcTemplate, database, name); } } From 435dbfbfd60a27e5e5d8e9786298aacae22e72d2 Mon Sep 17 00:00:00 2001 From: YGwan Date: Thu, 1 Aug 2024 09:59:17 +0900 Subject: [PATCH 04/34] create version.txt --- flyway-database-tibero/src/main/resources/tibero/version.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 flyway-database-tibero/src/main/resources/tibero/version.txt diff --git a/flyway-database-tibero/src/main/resources/tibero/version.txt b/flyway-database-tibero/src/main/resources/tibero/version.txt new file mode 100644 index 0000000..1785151 --- /dev/null +++ b/flyway-database-tibero/src/main/resources/tibero/version.txt @@ -0,0 +1 @@ +${pom.version} \ No newline at end of file From 37985aa8277d9ac21ba6a0f445087f11e8aea78a Mon Sep 17 00:00:00 2001 From: YGwan Date: Thu, 1 Aug 2024 10:00:04 +0900 Subject: [PATCH 05/34] flyway for tibero database extension --- .../database/TiberoDatabaseExtension.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/TiberoDatabaseExtension.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/TiberoDatabaseExtension.java index 6d96335..5a87099 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/TiberoDatabaseExtension.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/TiberoDatabaseExtension.java @@ -1,6 +1,27 @@ package org.flywaydb.community.database; +import org.flywaydb.core.api.FlywayException; import org.flywaydb.core.extensibility.PluginMetadata; +import org.flywaydb.core.internal.util.FileUtils; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Objects; public class TiberoDatabaseExtension implements PluginMetadata { + + public String getDescription() { + return "Community-contributed Tibero database support extension " + readVersion() + " by Redgate"; + } + + public static String readVersion() { + try { + return FileUtils.copyToString( + Objects.requireNonNull(TiberoDatabaseExtension.class.getClassLoader() + .getResourceAsStream("org/flywaydb/community/database/tibero/version.txt")), + StandardCharsets.UTF_8); + } catch (IOException e) { + throw new FlywayException("Unable to read extension version: " + e.getMessage(), e); + } + } } From cef65630a019cba466316d1fc681661bcdfc04b6 Mon Sep 17 00:00:00 2001 From: Bellroute Date: Thu, 1 Aug 2024 10:17:38 +0900 Subject: [PATCH 06/34] feat: add TiberoDatabaseType --- .../database/tibero/TiberoDatabase.java | 9 ++++++ .../database/tibero/TiberoDatabaseType.java | 28 +++++++++++-------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java index d2f75f7..5ce77e5 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java @@ -6,6 +6,7 @@ import org.flywaydb.core.internal.database.base.Table; import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory; import org.flywaydb.core.internal.jdbc.StatementInterceptor; +import org.flywaydb.core.internal.util.StringUtils; public class TiberoDatabase extends Database { @@ -15,6 +16,14 @@ public TiberoDatabase(Configuration configuration, JdbcConnectionFactory jdbcCon super(configuration, jdbcConnectionFactory, statementInterceptor); } + public static void enableTiberoTNSNameSupport() { + String tiberoAdminEnvVar = System.getenv("TIBERO_ADMIN"); + String tiberoAdminSysProp = System.getProperty("TIBERO_NET_ADMIN"); + if (StringUtils.hasLength(tiberoAdminEnvVar) && tiberoAdminSysProp == null) { + System.setProperty("TIBERO_NET_ADMIN", tiberoAdminEnvVar); + } + } + @Override protected TiberoConnection doGetConnection(Connection connection) { return null; diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabaseType.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabaseType.java index 1a737b0..b5ad268 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabaseType.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabaseType.java @@ -1,6 +1,7 @@ package org.flywaydb.community.database.tibero; import java.sql.Connection; +import java.sql.Types; import org.flywaydb.core.api.ResourceProvider; import org.flywaydb.core.api.configuration.Configuration; import org.flywaydb.core.internal.database.base.BaseDatabaseType; @@ -15,38 +16,41 @@ public class TiberoDatabaseType extends BaseDatabaseType implements CommunityDat @Override public String getName() { - return ""; + return "Tibero"; } @Override public int getNullType() { - return 0; + return Types.VARCHAR; } @Override - public boolean handlesJDBCUrl(String s) { - return false; + public boolean handlesJDBCUrl(String url) { + return url.startsWith("jdbc:tibero"); } @Override - public String getDriverClass(String s, ClassLoader classLoader) { - return ""; + public String getDriverClass(String url, ClassLoader classLoader) { + return "com.tmax.tibero.jdbc.TbDriver"; } @Override - public boolean handlesDatabaseProductNameAndVersion(String s, String s1, Connection connection) { - return false; + public boolean handlesDatabaseProductNameAndVersion(String databaseProductName, + String databaseProductVersion, Connection connection) { + return true; } @Override - public Database createDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, - StatementInterceptor statementInterceptor) { - return null; + public Database createDatabase(Configuration configuration, + JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) { + TiberoDatabase.enableTiberoTNSNameSupport(); + + return new TiberoDatabase(configuration, jdbcConnectionFactory, statementInterceptor); } @Override public Parser createParser(Configuration configuration, ResourceProvider resourceProvider, ParsingContext parsingContext) { - return null; + return new TiberoParser(configuration, parsingContext, 3); } } From 6220fb82a3353147939699c7de16a85ca9b925c4 Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Thu, 1 Aug 2024 10:36:29 +0900 Subject: [PATCH 07/34] add TiberoTable --- .../community/database/tibero/TiberoTable.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java index 8375d23..e7f0c4b 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java @@ -6,22 +6,26 @@ public class TiberoTable extends Table { - public TiberoTable(JdbcTemplate jdbcTemplate, TiberoDatabase database, TiberoSchema schema, String name) { + public TiberoTable(JdbcTemplate jdbcTemplate, TiberoDatabase database, TiberoSchema schema, + String name) { super(jdbcTemplate, database, schema, name); } @Override - protected boolean doExists() throws SQLException { - return false; + protected void doDrop() throws SQLException { + jdbcTemplate.execute( + "DROP TABLE " + database.quote(schema.getName(), name) + " CASCADE CONSTRAINTS PURGE"); } @Override - protected void doLock() throws SQLException { - + protected boolean doExists() throws SQLException { + return exists(null, schema, name); } @Override - protected void doDrop() throws SQLException { - + protected void doLock() throws SQLException { + jdbcTemplate.execute("LOCK TABLE " + this + " IN EXCLUSIVE MODE"); } } + +} From b77e793419ffdea85e31bffd5bc054b30b24b62a Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Thu, 1 Aug 2024 10:44:04 +0900 Subject: [PATCH 08/34] add TiberoDatabase zero to catalog --- .../database/tibero/TiberoDatabase.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java index 5ce77e5..c3560f4 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java @@ -16,7 +16,7 @@ public TiberoDatabase(Configuration configuration, JdbcConnectionFactory jdbcCon super(configuration, jdbcConnectionFactory, statementInterceptor); } - public static void enableTiberoTNSNameSupport() { + public static void enableTiberoTBDSNSupport() { String tiberoAdminEnvVar = System.getenv("TIBERO_ADMIN"); String tiberoAdminSysProp = System.getProperty("TIBERO_NET_ADMIN"); if (StringUtils.hasLength(tiberoAdminEnvVar) && tiberoAdminSysProp == null) { @@ -26,12 +26,19 @@ public static void enableTiberoTNSNameSupport() { @Override protected TiberoConnection doGetConnection(Connection connection) { - return null; + return new TiberoConnection(this, connection); } @Override - public void ensureSupported(Configuration configuration) { + protected String doGetCurrentUser() throws SQLException { + return getMainConnection().getJdbcTemplate().queryForString("SELECT USER FROM DUAL"); + } + @Override + public void ensureSupported(Configuration configuration) { + ensureDatabaseIsRecentEnough("7.0"); + ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("7.0", Tier.PREMIUM, configuration); + recommendFlywayUpgradeIfNecessaryForMajorVersion("21.3"); } @Override @@ -41,12 +48,12 @@ public boolean supportsDdlTransactions() { @Override public String getBooleanTrue() { - return ""; + return "1"; } @Override public String getBooleanFalse() { - return ""; + return "0"; } @Override From a9f2907862790b4e434f4a2d4d5142061718ff85 Mon Sep 17 00:00:00 2001 From: birdie Date: Thu, 1 Aug 2024 10:48:54 +0900 Subject: [PATCH 09/34] add TiberoDatabase rawScript, xml db, role grant --- .../database/tibero/TiberoDatabase.java | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java index c3560f4..2dc2a95 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java @@ -1,7 +1,9 @@ package org.flywaydb.community.database.tibero; 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; @@ -16,7 +18,7 @@ public TiberoDatabase(Configuration configuration, JdbcConnectionFactory jdbcCon super(configuration, jdbcConnectionFactory, statementInterceptor); } - public static void enableTiberoTBDSNSupport() { + public static void enableTiberoTNSNameSupport() { String tiberoAdminEnvVar = System.getenv("TIBERO_ADMIN"); String tiberoAdminSysProp = System.getProperty("TIBERO_NET_ADMIN"); if (StringUtils.hasLength(tiberoAdminEnvVar) && tiberoAdminSysProp == null) { @@ -62,7 +64,35 @@ public boolean catalogIsSchema() { } @Override - public String getRawCreateScript(Table table, boolean b) { - return ""; + public String getRawCreateScript(Table table, boolean baseline) { + String tablespace = configuration.getTablespace() == null + ? "" + : " TABLESPACE \"" + configuration.getTablespace() + "\""; + + return "CREATE TABLE " + table + " (\n" + + " \"installed_rank\" NUMBER NOT NULL,\n" + + " \"version\" VARCHAR2(50),\n" + + " \"description\" VARCHAR2(200) NOT NULL,\n" + + " \"type\" VARCHAR2(20) NOT NULL,\n" + + " \"script\" VARCHAR2(1000) NOT NULL,\n" + + " \"checksum\" NUMBER,\n" + + " \"installed_by\" VARCHAR2(100) NOT NULL,\n" + + " \"installed_on\" TIMESTAMP DEFAULT SYSDATE NOT NULL,\n" + + " \"execution_time\" NUMBER NOT NULL,\n" + + " \"success\" NUMBER(1) NOT NULL,\n" + + " CONSTRAINT \"" + table.getName() + "_pk\" PRIMARY KEY (\"installed_rank\")\n" + + ")" + tablespace + ";\n" + + (baseline ? getBaselineStatement(table) + ";\n" : "") + + "CREATE INDEX \"" + table.getSchema().getName() + "\".\"" + table.getName() + "_s_idx\" ON " + table + + " (\"success\");\n"; + } + + boolean isXmlDbAvailable() throws SQLException { + return isDataDictViewAccessible("ALL_XML_TABLES"); + } + + boolean isPrivOrRoleGranted(String name) throws SQLException { + return queryReturnsRows("SELECT 1 FROM SESSION_PRIVS WHERE PRIVILEGE = ? UNION ALL " + + "SELECT 1 FROM SESSION_ROLES WHERE ROLE = ?", name, name); } } From 8df3b956275cfe36d1427ecda79aa277d27e0d38 Mon Sep 17 00:00:00 2001 From: Bellroute Date: Thu, 1 Aug 2024 10:52:09 +0900 Subject: [PATCH 10/34] add TiberoDatabase queryReturnsRows, isDataDicViewAccessible --- .../community/database/tibero/TiberoDatabase.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java index 2dc2a95..39abb1e 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java @@ -10,7 +10,6 @@ import org.flywaydb.core.internal.jdbc.StatementInterceptor; import org.flywaydb.core.internal.util.StringUtils; - public class TiberoDatabase extends Database { public TiberoDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, @@ -95,4 +94,18 @@ boolean isPrivOrRoleGranted(String name) throws SQLException { return queryReturnsRows("SELECT 1 FROM SESSION_PRIVS WHERE PRIVILEGE = ? UNION ALL " + "SELECT 1 FROM SESSION_ROLES WHERE ROLE = ?", name, name); } + + boolean queryReturnsRows(String query, String... params) throws SQLException { + return getMainConnection().getJdbcTemplate() + .queryForBoolean("SELECT CASE WHEN EXISTS(" + query + ") THEN 1 ELSE 0 END FROM DUAL", params); + } + + private boolean isDataDictViewAccessible(String owner, String name) throws SQLException { + return queryReturnsRows("SELECT * FROM DBA_TAB_PRIVS WHERE OWNER = ? AND TABLE_NAME = ?" + + " AND PRIVILEGE = 'SELECT'", owner, name); + } + + boolean isDataDictViewAccessible(String name) throws SQLException { + return isDataDictViewAccessible("SYS", name); + } } From 7ea55f213448fc583406ea226327b36b5719d0ad Mon Sep 17 00:00:00 2001 From: w-seok Date: Thu, 1 Aug 2024 10:54:55 +0900 Subject: [PATCH 11/34] feat: add TiberoDatabase systemSchema, dbOrAll, locatorAvailable --- .../database/tibero/TiberoDatabase.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java index 39abb1e..5d02ad4 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java @@ -2,6 +2,10 @@ import java.sql.Connection; import java.sql.SQLException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + import org.flywaydb.core.api.configuration.Configuration; import org.flywaydb.core.extensibility.Tier; import org.flywaydb.core.internal.database.base.Database; @@ -108,4 +112,33 @@ private boolean isDataDictViewAccessible(String owner, String name) throws SQLEx boolean isDataDictViewAccessible(String name) throws SQLException { return isDataDictViewAccessible("SYS", name); } + + Set getSystemSchemas() throws SQLException { + + Set result = new HashSet<>(Arrays.asList( + "SYS", "SYSTEM", + "SYSCAT", + "SYSMAN", + "SYSGIS", + "OUTLN", + "TIBERO", + "TIBERO1" + )); + + result.addAll(getMainConnection().getJdbcTemplate().queryForStringList( + "SELECT USERNAME FROM DBA_USERS WHERE USERNAME LIKE 'SYS%'" + )); + + return result; + } + + String dbaOrAll(String baseName) throws SQLException { + return isPrivOrRoleGranted("SELECT ANY DICTIONARY") || isDataDictViewAccessible("DBA_" + baseName) + ? "DBA_" + baseName + : "ALL_" + baseName; + } + + boolean isLocatorAvailable() throws SQLException { + return isDataDictViewAccessible("SYSGIS", "ALL_GEOMETRY_COLUMNS"); + } } From a4fa517d420bc1502699a4216b5facf041d80427 Mon Sep 17 00:00:00 2001 From: YGwan Date: Thu, 1 Aug 2024 10:58:58 +0900 Subject: [PATCH 12/34] add TiberoDatabase isFlashbackDataArchiveAvailable --- .../database/tibero/TiberoDatabase.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java index 5d02ad4..e674dc4 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java @@ -132,6 +132,43 @@ Set getSystemSchemas() throws SQLException { return result; } + boolean isFlashbackDataArchiveAvailable(String schemaName) throws SQLException { + String paramQuery = "SELECT COUNT(*) FROM V$PARAMETERS WHERE NAME LIKE '%FLASHBACK%' AND VALUE IS NOT NULL AND (LENGTH(TRIM(VALUE)) > 0 OR VALUE != '0')"; + int paramCount = getMainConnection().getJdbcTemplate().queryForInt(paramQuery); + + if (paramCount == 0) { + return false; + } + + String destQuery = "SELECT VALUE FROM V$PARAMETERS WHERE NAME = 'FLASHBACK_LOG_ARCHIVE_DEST'"; + String flashbackDest = getMainConnection().getJdbcTemplate().queryForString(destQuery); + + if (flashbackDest == null || flashbackDest.trim().isEmpty()) { + return false; + } + + String logModeQuery = "SELECT LOG_MODE FROM V$DATABASE"; + String logMode = getMainConnection().getJdbcTemplate().queryForString(logModeQuery); + + if (!"ARCHIVELOG".equalsIgnoreCase(logMode)) { + return false; + } + + String tablespaceQuery = "SELECT COUNT(*) FROM DBA_USERS u JOIN V$TABLESPACE t ON u.DEFAULT_TABLESPACE = t.NAME WHERE u.USERNAME = ? AND t.FLASHBACK_ON = 'YES'"; + int flashbackOnCount = getMainConnection().getJdbcTemplate() + .queryForInt(tablespaceQuery, schemaName.toUpperCase()); + + if (flashbackOnCount == 0) { + return false; + } + + String privilegeQuery = "SELECT COUNT(*) FROM DBA_SYS_PRIVS WHERE GRANTEE = ? AND (PRIVILEGE = 'FLASHBACK ANY TABLE' OR PRIVILEGE = 'FLASHBACK OBJECT')"; + int privilegeCount = getMainConnection().getJdbcTemplate() + .queryForInt(privilegeQuery, schemaName.toUpperCase()); + + return privilegeCount != 0; + } + String dbaOrAll(String baseName) throws SQLException { return isPrivOrRoleGranted("SELECT ANY DICTIONARY") || isDataDictViewAccessible("DBA_" + baseName) ? "DBA_" + baseName From 11f9b1d321d4b153991b8c9d38cad911c9befabe Mon Sep 17 00:00:00 2001 From: birdie Date: Thu, 1 Aug 2024 11:05:51 +0900 Subject: [PATCH 13/34] add tibero schema --- .../database/tibero/TiberoSchema.java | 80 +++++++++++++++++-- 1 file changed, 73 insertions(+), 7 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java index d3147d5..373e32a 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java @@ -2,9 +2,15 @@ import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.flywaydb.core.internal.database.base.Schema; import org.flywaydb.core.internal.database.base.Table; import org.flywaydb.core.internal.jdbc.JdbcTemplate; +import org.flywaydb.core.internal.util.StringUtils; public class TiberoSchema extends Schema { @@ -12,24 +18,27 @@ public TiberoSchema(JdbcTemplate jdbcTemplate, TiberoDatabase database, String n super(jdbcTemplate, database, name); } + boolean isDefaultSchemaForUser() throws SQLException { + return name.equals(database.doGetCurrentUser()); + } + @Override protected boolean doExists() throws SQLException { - return false; + return database.queryReturnsRows("SELECT * FROM ALL_USERS WHERE USERNAME = ?", name); } @Override protected boolean doEmpty() throws SQLException { - return false; + return true; } @Override protected void doCreate() throws SQLException { - } @Override protected void doDrop() throws SQLException { - + jdbcTemplate.execute("DROP USER " + database.quote(name) + " CASCADE"); } @Override @@ -39,11 +48,68 @@ protected void doClean() throws SQLException { @Override protected TiberoTable[] doAllTables() throws SQLException { - return new TiberoTable[0]; + return new TiberoTable[1]; } @Override - public Table getTable(String s) { - return null; + @SuppressWarnings("rawtypes") + public Table getTable(String tableName) { + return new TiberoTable(jdbcTemplate, database, this, tableName); + } + + public enum ObjectType { + TABLE("TABLE"), + ; + + private final String name; + private final String dropOptions; + + ObjectType(String name, String dropOptions) { + this.name = name; + this.dropOptions = dropOptions; + } + + ObjectType(String name) { + this(name, ""); + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return super.toString().replace('_', ' '); + } + + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT DISTINCT OBJECT_NAME FROM ALL_OBJECTS WHERE OWNER = ? AND OBJECT_TYPE = ?", + schema.getName(), this.getName() + ); + } + + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + return "DROP " + this.getName() + " " + database.quote(schema.getName(), objectName) + + (StringUtils.hasText(dropOptions) ? " " + dropOptions : ""); + } + + public void dropObjects(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + for (String objectName : getObjectNames(jdbcTemplate, database, schema)) { + jdbcTemplate.execute( + generateDropStatement(jdbcTemplate, database, schema, objectName)); + } + } + + private void warnUnsupported(String schemaName, String typeDesc) { + + } + + private void warnUnsupported(String schemaName) { + warnUnsupported(schemaName, this.toString().toLowerCase() + "s"); + } } } From 4d6eb452c48d102d782159735e08eeaf2d54a08f Mon Sep 17 00:00:00 2001 From: Bellroute Date: Thu, 1 Aug 2024 11:19:39 +0900 Subject: [PATCH 14/34] add tibero schema trigger, queue_table, scheduler_chain, scheduler_job, scheduler_program --- .../database/tibero/TiberoSchema.java | 172 +++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java index 373e32a..431a898 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java @@ -1,12 +1,19 @@ package org.flywaydb.community.database.tibero; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.QUEUE_TABLE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULER_CHAIN; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULER_JOB; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULER_PROGRAM; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.TRIGGER; + import java.sql.SQLException; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import org.flywaydb.core.api.FlywayException; import org.flywaydb.core.internal.database.base.Schema; import org.flywaydb.core.internal.database.base.Table; import org.flywaydb.core.internal.jdbc.JdbcTemplate; @@ -43,9 +50,59 @@ protected void doDrop() throws SQLException { @Override protected void doClean() throws SQLException { + if (isSystem()) { + throw new FlywayException("Clean not supported on Tibero for system schema " + database.quote(name) + "! " + + "It must not be changed in any way except by running an Tibero-supplied script!"); + } + + if (database.isFlashbackDataArchiveAvailable(name)) { + disableFlashbackArchiveForFbaTrackedTables(); + } + + if (database.isLocatorAvailable()) { + cleanLocatorMetadata(); + } + + Set objectTypeNames = ObjectType.getObjectTypeNames(jdbcTemplate, database, this); + List objectTypesToClean = List.of( + TRIGGER, + QUEUE_TABLE, + SCHEDULER_CHAIN, + SCHEDULER_JOB, + SCHEDULER_PROGRAM + ); + + for (ObjectType objectType : objectTypesToClean) { + if (objectTypeNames.contains(objectType.getName())) { + objectType.dropObjects(jdbcTemplate, database, this); + } + } + + if (isDefaultSchemaForUser()) { + jdbcTemplate.execute("PURGE RECYCLEBIN"); + } } + public boolean isSystem() throws SQLException { + return database.getSystemSchemas().contains(name); + } + + private void cleanLocatorMetadata() throws SQLException { + if (!locatorMetadataExists()) { + return; + } + + if (!isDefaultSchemaForUser()) { + return; + } + + jdbcTemplate.getConnection().commit(); + jdbcTemplate.execute("DELETE FROM USER_GEOMETRY_COLUMNS"); + jdbcTemplate.getConnection().commit(); + } + + @Override protected TiberoTable[] doAllTables() throws SQLException { return new TiberoTable[1]; @@ -58,7 +115,120 @@ public Table getTable(String tableName) { } public enum ObjectType { - TABLE("TABLE"), + TRIGGER("TRIGGER"), + QUEUE_TABLE("QUEUE TABLE") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT QUEUE_TABLE FROM ALL_QUEUE_TABLES WHERE OWNER = ?", + schema.getName() + ); + } + + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + return "BEGIN DBMS_AQADM.DROP_QUEUE_TABLE('" + objectName + "'); END;"; + } + }, + SCHEDULER_CHAIN("SCHEDULER_CHAINS") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT CHAIN_NAME FROM " + database.dbaOrAll(SCHEDULER_CHAIN.getName()) + " WHERE OWNER_ID IN (" + + "SELECT DISTINCT USER_ID FROM ALL_USERS WHERE USERNAME = ? " + + ") ", schema.getName() + ); + } + + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + + deleteChainRules(jdbcTemplate, database, objectName); + deleteChainSteps(jdbcTemplate, database, objectName); + return "BEGIN DBMS_SCHEDULER.DROP_CHAIN('" + objectName + "'); END;"; + } + + private void deleteChainRules(JdbcTemplate jdbcTemplate, TiberoDatabase database, String objectName) { + try { + final String SCHEDULER_JOB_RULE_TABLE_NAME = database.dbaOrAll("SCHEDULER_RULES"); + + List ruleNames = jdbcTemplate.queryForStringList( + "SELECT RULE_NAME FROM " + SCHEDULER_JOB_RULE_TABLE_NAME + " WHERE CHAIN_NAME = ?", + objectName); + + for (String ruleName : ruleNames) { + jdbcTemplate.execute( + "BEGIN DBMS_SCHEDULER.DROP_CHAIN_RULE('" + objectName + "','" + ruleName + "'); END;"); + } + + } catch (SQLException e) { + } + } + + private void deleteChainSteps(JdbcTemplate jdbcTemplate, TiberoDatabase database, String objectName) { + try { + final String SCHEDULER_JOB_STEP_TABLE_NAME = database.dbaOrAll("SCHEDULER_STEPS"); + + List stepNames = jdbcTemplate.queryForStringList( + "SELECT STEP_NAME FROM " + SCHEDULER_JOB_STEP_TABLE_NAME + " WHERE CHAIN_NAME = ?", + objectName); + + for (String stepName : stepNames) { + jdbcTemplate.execute( + "BEGIN DBMS_SCHEDULER.DROP_CHAIN_STEP('" + objectName + "','" + stepName + "'); END;"); + } + + } catch (SQLException e) { + } + } + }, + + SCHEDULER_JOB("SCHEDULER_JOBS") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT JOB_NAME FROM " + database.dbaOrAll(SCHEDULER_JOB.getName()) + " WHERE OWNER = ?", + schema.getName() + ); + } + + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + + try { + final String SCHEDULER_JOB_LOG_TABLE_NAME = database.dbaOrAll("SCHEDULER_JOB_LOG"); + + jdbcTemplate.update("DELETE FROM " + SCHEDULER_JOB_LOG_TABLE_NAME + " WHERE JOB_NAME = ?", + objectName); + } catch (SQLException e) { + } + + return "BEGIN DBMS_SCHEDULER.DROP_JOB('" + objectName + "'); END;"; + } + }, + + SCHEDULER_PROGRAM("SCHEDULER_PROGRAMS") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT PROGRAM_NAME FROM " + database.dbaOrAll(SCHEDULER_PROGRAM.getName()) + " WHERE OWNER = ?", + schema.getName() + ); + } + + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + return "BEGIN DBMS_SCHEDULER.DROP_PROGRAM('" + objectName + "'); END;"; + } + }, ; private final String name; From d3736651de1c51eef6fb7d797161d3261566ca44 Mon Sep 17 00:00:00 2001 From: YGwan Date: Thu, 1 Aug 2024 11:26:04 +0900 Subject: [PATCH 15/34] add tibero schema schedule, sql_translation_profile, materialized_view, materialized_view_log, dimension --- .../database/tibero/TiberoSchema.java | 223 ++++++++++++++---- 1 file changed, 174 insertions(+), 49 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java index 431a898..109c713 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java @@ -1,23 +1,19 @@ package org.flywaydb.community.database.tibero; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.QUEUE_TABLE; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULER_CHAIN; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULER_JOB; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULER_PROGRAM; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.TRIGGER; +import org.flywaydb.core.api.FlywayException; +import org.flywaydb.core.internal.database.base.Schema; +import org.flywaydb.core.internal.database.base.Table; +import org.flywaydb.core.internal.jdbc.JdbcTemplate; +import org.flywaydb.core.internal.util.StringUtils; import java.sql.SQLException; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import org.flywaydb.core.api.FlywayException; -import org.flywaydb.core.internal.database.base.Schema; -import org.flywaydb.core.internal.database.base.Table; -import org.flywaydb.core.internal.jdbc.JdbcTemplate; -import org.flywaydb.core.internal.util.StringUtils; + +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.*; public class TiberoSchema extends Schema { @@ -52,7 +48,7 @@ protected void doDrop() throws SQLException { protected void doClean() throws SQLException { if (isSystem()) { throw new FlywayException("Clean not supported on Tibero for system schema " + database.quote(name) + "! " + - "It must not be changed in any way except by running an Tibero-supplied script!"); + "It must not be changed in any way except by running an Tibero-supplied script!"); } if (database.isFlashbackDataArchiveAvailable(name)) { @@ -66,12 +62,17 @@ protected void doClean() throws SQLException { Set objectTypeNames = ObjectType.getObjectTypeNames(jdbcTemplate, database, this); List objectTypesToClean = List.of( - TRIGGER, - QUEUE_TABLE, - SCHEDULER_CHAIN, - SCHEDULER_JOB, - SCHEDULER_PROGRAM - ); + TRIGGER, + QUEUE_TABLE, + SCHEDULER_CHAIN, + SCHEDULER_JOB, + SCHEDULER_PROGRAM, + SCHEDULE, + SQL_TRANSLATION_PROFILE, + MATERIALIZED_VIEW, + MATERIALIZED_VIEW_LOG, + DIMENSION + ); for (ObjectType objectType : objectTypesToClean) { if (objectTypeNames.contains(objectType.getName())) { @@ -102,6 +103,10 @@ private void cleanLocatorMetadata() throws SQLException { jdbcTemplate.getConnection().commit(); } + private boolean locatorMetadataExists() throws SQLException { + return database.queryReturnsRows("SELECT * FROM ALL_GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = ?", + name); + } @Override protected TiberoTable[] doAllTables() throws SQLException { @@ -114,38 +119,63 @@ public Table getTable(String tableName) { return new TiberoTable(jdbcTemplate, database, this, tableName); } + private void disableFlashbackArchiveForFbaTrackedTables() throws SQLException { + boolean dbaViewAccessible = database.isPrivOrRoleGranted("SELECT ANY DICTIONARY") + || database.isDataDictViewAccessible("DBMS_FLASHBACK"); + + if (!dbaViewAccessible && !isDefaultSchemaForUser()) { + return; + } + + String queryForRecycleBinStatus = + "SELECT VALUE FROM " + database.quote("SYS", "V$PARAMETERS") + " WHERE NAME = 'USE_RECYCLEBIN'"; + String recycleBinStatus = jdbcTemplate.queryForString(queryForRecycleBinStatus); + + if (!"NO".equalsIgnoreCase(recycleBinStatus)) { + jdbcTemplate.execute("ALTER SYSTEM SET USE_RECYCLEBIN = N"); + + while (!"NO".equalsIgnoreCase(jdbcTemplate.queryForString(queryForRecycleBinStatus))) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new FlywayException("Interrupted while waiting for recycle bin to be disabled.", e); + } + } + } + } + public enum ObjectType { TRIGGER("TRIGGER"), QUEUE_TABLE("QUEUE TABLE") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT QUEUE_TABLE FROM ALL_QUEUE_TABLES WHERE OWNER = ?", - schema.getName() + "SELECT QUEUE_TABLE FROM ALL_QUEUE_TABLES WHERE OWNER = ?", + schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { return "BEGIN DBMS_AQADM.DROP_QUEUE_TABLE('" + objectName + "'); END;"; } }, SCHEDULER_CHAIN("SCHEDULER_CHAINS") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT CHAIN_NAME FROM " + database.dbaOrAll(SCHEDULER_CHAIN.getName()) + " WHERE OWNER_ID IN (" - + "SELECT DISTINCT USER_ID FROM ALL_USERS WHERE USERNAME = ? " - + ") ", schema.getName() + "SELECT CHAIN_NAME FROM " + database.dbaOrAll(SCHEDULER_CHAIN.getName()) + " WHERE OWNER_ID IN (" + + "SELECT DISTINCT USER_ID FROM ALL_USERS WHERE USERNAME = ? " + + ") ", schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { deleteChainRules(jdbcTemplate, database, objectName); deleteChainSteps(jdbcTemplate, database, objectName); @@ -157,12 +187,12 @@ private void deleteChainRules(JdbcTemplate jdbcTemplate, TiberoDatabase database final String SCHEDULER_JOB_RULE_TABLE_NAME = database.dbaOrAll("SCHEDULER_RULES"); List ruleNames = jdbcTemplate.queryForStringList( - "SELECT RULE_NAME FROM " + SCHEDULER_JOB_RULE_TABLE_NAME + " WHERE CHAIN_NAME = ?", - objectName); + "SELECT RULE_NAME FROM " + SCHEDULER_JOB_RULE_TABLE_NAME + " WHERE CHAIN_NAME = ?", + objectName); for (String ruleName : ruleNames) { jdbcTemplate.execute( - "BEGIN DBMS_SCHEDULER.DROP_CHAIN_RULE('" + objectName + "','" + ruleName + "'); END;"); + "BEGIN DBMS_SCHEDULER.DROP_CHAIN_RULE('" + objectName + "','" + ruleName + "'); END;"); } } catch (SQLException e) { @@ -174,12 +204,12 @@ private void deleteChainSteps(JdbcTemplate jdbcTemplate, TiberoDatabase database final String SCHEDULER_JOB_STEP_TABLE_NAME = database.dbaOrAll("SCHEDULER_STEPS"); List stepNames = jdbcTemplate.queryForStringList( - "SELECT STEP_NAME FROM " + SCHEDULER_JOB_STEP_TABLE_NAME + " WHERE CHAIN_NAME = ?", - objectName); + "SELECT STEP_NAME FROM " + SCHEDULER_JOB_STEP_TABLE_NAME + " WHERE CHAIN_NAME = ?", + objectName); for (String stepName : stepNames) { jdbcTemplate.execute( - "BEGIN DBMS_SCHEDULER.DROP_CHAIN_STEP('" + objectName + "','" + stepName + "'); END;"); + "BEGIN DBMS_SCHEDULER.DROP_CHAIN_STEP('" + objectName + "','" + stepName + "'); END;"); } } catch (SQLException e) { @@ -190,22 +220,22 @@ private void deleteChainSteps(JdbcTemplate jdbcTemplate, TiberoDatabase database SCHEDULER_JOB("SCHEDULER_JOBS") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT JOB_NAME FROM " + database.dbaOrAll(SCHEDULER_JOB.getName()) + " WHERE OWNER = ?", - schema.getName() + "SELECT JOB_NAME FROM " + database.dbaOrAll(SCHEDULER_JOB.getName()) + " WHERE OWNER = ?", + schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { try { final String SCHEDULER_JOB_LOG_TABLE_NAME = database.dbaOrAll("SCHEDULER_JOB_LOG"); jdbcTemplate.update("DELETE FROM " + SCHEDULER_JOB_LOG_TABLE_NAME + " WHERE JOB_NAME = ?", - objectName); + objectName); } catch (SQLException e) { } @@ -216,19 +246,76 @@ public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase da SCHEDULER_PROGRAM("SCHEDULER_PROGRAMS") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT PROGRAM_NAME FROM " + database.dbaOrAll(SCHEDULER_PROGRAM.getName()) + " WHERE OWNER = ?", - schema.getName() + "SELECT PROGRAM_NAME FROM " + database.dbaOrAll(SCHEDULER_PROGRAM.getName()) + " WHERE OWNER = ?", + schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { return "BEGIN DBMS_SCHEDULER.DROP_PROGRAM('" + objectName + "'); END;"; } }, + + SCHEDULE("SCHEDULER_SCHEDULES") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT SCHEDULE_NAME FROM " + database.dbaOrAll(SCHEDULE.getName()) + " WHERE OWNER = ?", + schema.getName() + ); + } + + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + return "BEGIN DBMS_SCHEDULER.DROP_SCHEDULE('" + objectName + "'); END;"; + } + }, + + SQL_TRANSLATION_PROFILE("SQL TRANSLATION PROFILE") { + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + return "BEGIN DBMS_SQL_TRANSLATOR.DROP_PROFILE('" + database.quote(schema.getName(), + objectName) + "'); END;"; + } + }, + + MATERIALIZED_VIEW("MATERIALIZED VIEW", "PRESERVE TABLE"), + + MATERIALIZED_VIEW_LOG("MATERIALIZED VIEW LOG") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT MASTER FROM ALL_MVIEW_LOGS WHERE LOG_OWNER = ?", + schema.getName() + ); + } + + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + return "DROP " + this.getName() + " ON " + database.quote(schema.getName(), + objectName); + } + }, + + DIMENSION("DIMENSION") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT 'DIMENSION' FROM DUAL", + schema.getName() + ); + } + }, ; private final String name; @@ -253,24 +340,24 @@ public String toString() { } public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT DISTINCT OBJECT_NAME FROM ALL_OBJECTS WHERE OWNER = ? AND OBJECT_TYPE = ?", - schema.getName(), this.getName() + "SELECT DISTINCT OBJECT_NAME FROM ALL_OBJECTS WHERE OWNER = ? AND OBJECT_TYPE = ?", + schema.getName(), this.getName() ); } public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { return "DROP " + this.getName() + " " + database.quote(schema.getName(), objectName) + - (StringUtils.hasText(dropOptions) ? " " + dropOptions : ""); + (StringUtils.hasText(dropOptions) ? " " + dropOptions : ""); } public void dropObjects(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { for (String objectName : getObjectNames(jdbcTemplate, database, schema)) { jdbcTemplate.execute( - generateDropStatement(jdbcTemplate, database, schema, objectName)); + generateDropStatement(jdbcTemplate, database, schema, objectName)); } } @@ -281,5 +368,43 @@ private void warnUnsupported(String schemaName, String typeDesc) { private void warnUnsupported(String schemaName) { warnUnsupported(schemaName, this.toString().toLowerCase() + "s"); } + + public static Set getObjectTypeNames(JdbcTemplate jdbcTemplate, + TiberoDatabase database, TiberoSchema schema) throws SQLException { + String query = + "SELECT DISTINCT OBJECT_TYPE FROM " + database.dbaOrAll("OBJECTS") + " WHERE OWNER = ? " + + + "UNION SELECT '" + MATERIALIZED_VIEW_LOG.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM ALL_MVIEW_LOGS WHERE LOG_OWNER = ?) " + + + "UNION SELECT '" + QUEUE_TABLE.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM ALL_QUEUE_TABLES WHERE OWNER = ?) " + + + "UNION SELECT '" + DATABASE_LINK.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll("DB_LINKS") + " WHERE OWNER = ?) " + + "UNION SELECT '" + CONTEXT.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM V$CONTEXT WHERE NAMESPACE = ?) " + + + "UNION SELECT '" + CREDENTIAL.getName() + "' FROM DUAL " + + + "UNION SELECT '" + SCHEDULER_PROGRAM.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll(SCHEDULER_PROGRAM.getName()) + " WHERE OWNER = ?) " + + + "UNION SELECT '" + SCHEDULE.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll(SCHEDULE.getName()) + " WHERE OWNER = ?) " + + + "UNION SELECT '" + SCHEDULER_JOB.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll(SCHEDULER_JOB.getName()) + " WHERE OWNER = ?) " + + + "UNION SELECT '" + SCHEDULER_CHAIN.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll(SCHEDULER_CHAIN.getName()) + " WHERE OWNER_ID IN (" + + "SELECT DISTINCT USER_ID FROM ALL_USERS WHERE USERNAME = ?)" + + ") "; + + String[] params = new String[9]; + Arrays.fill(params, schema.getName()); + + return new HashSet<>(jdbcTemplate.queryForStringList(query, params)); + } } } From 479605adbe4cb1e7fc2c61a0033ac4ac583d168e Mon Sep 17 00:00:00 2001 From: birdie Date: Thu, 1 Aug 2024 11:29:50 +0900 Subject: [PATCH 16/34] add tibero schema view, table, index, sequence, function --- .../database/tibero/TiberoSchema.java | 232 +++++++++++------- 1 file changed, 143 insertions(+), 89 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java index 109c713..1618ff7 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java @@ -14,6 +14,11 @@ import java.util.Set; import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.*; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.FUNCTION; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.INDEX; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SEQUENCE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.TABLE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.VIEW; public class TiberoSchema extends Schema { @@ -48,7 +53,7 @@ protected void doDrop() throws SQLException { protected void doClean() throws SQLException { if (isSystem()) { throw new FlywayException("Clean not supported on Tibero for system schema " + database.quote(name) + "! " + - "It must not be changed in any way except by running an Tibero-supplied script!"); + "It must not be changed in any way except by running an Tibero-supplied script!"); } if (database.isFlashbackDataArchiveAvailable(name)) { @@ -62,17 +67,22 @@ protected void doClean() throws SQLException { Set objectTypeNames = ObjectType.getObjectTypeNames(jdbcTemplate, database, this); List objectTypesToClean = List.of( - TRIGGER, - QUEUE_TABLE, - SCHEDULER_CHAIN, - SCHEDULER_JOB, - SCHEDULER_PROGRAM, - SCHEDULE, - SQL_TRANSLATION_PROFILE, - MATERIALIZED_VIEW, - MATERIALIZED_VIEW_LOG, - DIMENSION - ); + TRIGGER, + QUEUE_TABLE, + SCHEDULER_CHAIN, + SCHEDULER_JOB, + SCHEDULER_PROGRAM, + SCHEDULE, + SQL_TRANSLATION_PROFILE, + MATERIALIZED_VIEW, + MATERIALIZED_VIEW_LOG, + DIMENSION, + VIEW, + TABLE, + INDEX, + SEQUENCE, + FUNCTION, + ); for (ObjectType objectType : objectTypesToClean) { if (objectTypeNames.contains(objectType.getName())) { @@ -105,7 +115,7 @@ private void cleanLocatorMetadata() throws SQLException { private boolean locatorMetadataExists() throws SQLException { return database.queryReturnsRows("SELECT * FROM ALL_GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = ?", - name); + name); } @Override @@ -121,14 +131,14 @@ public Table getTable(String tableName) { private void disableFlashbackArchiveForFbaTrackedTables() throws SQLException { boolean dbaViewAccessible = database.isPrivOrRoleGranted("SELECT ANY DICTIONARY") - || database.isDataDictViewAccessible("DBMS_FLASHBACK"); + || database.isDataDictViewAccessible("DBMS_FLASHBACK"); if (!dbaViewAccessible && !isDefaultSchemaForUser()) { return; } String queryForRecycleBinStatus = - "SELECT VALUE FROM " + database.quote("SYS", "V$PARAMETERS") + " WHERE NAME = 'USE_RECYCLEBIN'"; + "SELECT VALUE FROM " + database.quote("SYS", "V$PARAMETERS") + " WHERE NAME = 'USE_RECYCLEBIN'"; String recycleBinStatus = jdbcTemplate.queryForString(queryForRecycleBinStatus); if (!"NO".equalsIgnoreCase(recycleBinStatus)) { @@ -149,33 +159,33 @@ public enum ObjectType { QUEUE_TABLE("QUEUE TABLE") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT QUEUE_TABLE FROM ALL_QUEUE_TABLES WHERE OWNER = ?", - schema.getName() + "SELECT QUEUE_TABLE FROM ALL_QUEUE_TABLES WHERE OWNER = ?", + schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { return "BEGIN DBMS_AQADM.DROP_QUEUE_TABLE('" + objectName + "'); END;"; } }, SCHEDULER_CHAIN("SCHEDULER_CHAINS") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT CHAIN_NAME FROM " + database.dbaOrAll(SCHEDULER_CHAIN.getName()) + " WHERE OWNER_ID IN (" - + "SELECT DISTINCT USER_ID FROM ALL_USERS WHERE USERNAME = ? " - + ") ", schema.getName() + "SELECT CHAIN_NAME FROM " + database.dbaOrAll(SCHEDULER_CHAIN.getName()) + " WHERE OWNER_ID IN (" + + "SELECT DISTINCT USER_ID FROM ALL_USERS WHERE USERNAME = ? " + + ") ", schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { deleteChainRules(jdbcTemplate, database, objectName); deleteChainSteps(jdbcTemplate, database, objectName); @@ -187,12 +197,12 @@ private void deleteChainRules(JdbcTemplate jdbcTemplate, TiberoDatabase database final String SCHEDULER_JOB_RULE_TABLE_NAME = database.dbaOrAll("SCHEDULER_RULES"); List ruleNames = jdbcTemplate.queryForStringList( - "SELECT RULE_NAME FROM " + SCHEDULER_JOB_RULE_TABLE_NAME + " WHERE CHAIN_NAME = ?", - objectName); + "SELECT RULE_NAME FROM " + SCHEDULER_JOB_RULE_TABLE_NAME + " WHERE CHAIN_NAME = ?", + objectName); for (String ruleName : ruleNames) { jdbcTemplate.execute( - "BEGIN DBMS_SCHEDULER.DROP_CHAIN_RULE('" + objectName + "','" + ruleName + "'); END;"); + "BEGIN DBMS_SCHEDULER.DROP_CHAIN_RULE('" + objectName + "','" + ruleName + "'); END;"); } } catch (SQLException e) { @@ -204,12 +214,12 @@ private void deleteChainSteps(JdbcTemplate jdbcTemplate, TiberoDatabase database final String SCHEDULER_JOB_STEP_TABLE_NAME = database.dbaOrAll("SCHEDULER_STEPS"); List stepNames = jdbcTemplate.queryForStringList( - "SELECT STEP_NAME FROM " + SCHEDULER_JOB_STEP_TABLE_NAME + " WHERE CHAIN_NAME = ?", - objectName); + "SELECT STEP_NAME FROM " + SCHEDULER_JOB_STEP_TABLE_NAME + " WHERE CHAIN_NAME = ?", + objectName); for (String stepName : stepNames) { jdbcTemplate.execute( - "BEGIN DBMS_SCHEDULER.DROP_CHAIN_STEP('" + objectName + "','" + stepName + "'); END;"); + "BEGIN DBMS_SCHEDULER.DROP_CHAIN_STEP('" + objectName + "','" + stepName + "'); END;"); } } catch (SQLException e) { @@ -220,22 +230,22 @@ private void deleteChainSteps(JdbcTemplate jdbcTemplate, TiberoDatabase database SCHEDULER_JOB("SCHEDULER_JOBS") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT JOB_NAME FROM " + database.dbaOrAll(SCHEDULER_JOB.getName()) + " WHERE OWNER = ?", - schema.getName() + "SELECT JOB_NAME FROM " + database.dbaOrAll(SCHEDULER_JOB.getName()) + " WHERE OWNER = ?", + schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { try { final String SCHEDULER_JOB_LOG_TABLE_NAME = database.dbaOrAll("SCHEDULER_JOB_LOG"); jdbcTemplate.update("DELETE FROM " + SCHEDULER_JOB_LOG_TABLE_NAME + " WHERE JOB_NAME = ?", - objectName); + objectName); } catch (SQLException e) { } @@ -246,16 +256,16 @@ public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase da SCHEDULER_PROGRAM("SCHEDULER_PROGRAMS") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT PROGRAM_NAME FROM " + database.dbaOrAll(SCHEDULER_PROGRAM.getName()) + " WHERE OWNER = ?", - schema.getName() + "SELECT PROGRAM_NAME FROM " + database.dbaOrAll(SCHEDULER_PROGRAM.getName()) + " WHERE OWNER = ?", + schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { return "BEGIN DBMS_SCHEDULER.DROP_PROGRAM('" + objectName + "'); END;"; } }, @@ -263,16 +273,16 @@ public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase da SCHEDULE("SCHEDULER_SCHEDULES") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT SCHEDULE_NAME FROM " + database.dbaOrAll(SCHEDULE.getName()) + " WHERE OWNER = ?", - schema.getName() + "SELECT SCHEDULE_NAME FROM " + database.dbaOrAll(SCHEDULE.getName()) + " WHERE OWNER = ?", + schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { return "BEGIN DBMS_SCHEDULER.DROP_SCHEDULE('" + objectName + "'); END;"; } }, @@ -280,9 +290,9 @@ public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase da SQL_TRANSLATION_PROFILE("SQL TRANSLATION PROFILE") { @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { return "BEGIN DBMS_SQL_TRANSLATOR.DROP_PROFILE('" + database.quote(schema.getName(), - objectName) + "'); END;"; + objectName) + "'); END;"; } }, @@ -291,31 +301,75 @@ public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase da MATERIALIZED_VIEW_LOG("MATERIALIZED VIEW LOG") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT MASTER FROM ALL_MVIEW_LOGS WHERE LOG_OWNER = ?", - schema.getName() + "SELECT MASTER FROM ALL_MVIEW_LOGS WHERE LOG_OWNER = ?", + schema.getName() ); } @Override public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { return "DROP " + this.getName() + " ON " + database.quote(schema.getName(), - objectName); + objectName); } }, DIMENSION("DIMENSION") { @Override public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT 'DIMENSION' FROM DUAL", + schema.getName() + ); + } + }, + VIEW("VIEW"), + TABLE("TABLE", "CASCADE CONSTRAINTS PURGE") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + + StringBuilder tablesQuery = new StringBuilder(); + tablesQuery.append("WITH TABLES AS (\n" + + " SELECT TABLE_NAME, OWNER\n" + + " FROM ALL_TABLES\n" + + " WHERE OWNER = ?\n" + + " AND (IOT_TYPE IS NULL OR IOT_TYPE NOT LIKE '%OVERFLOW%')\n"); + + tablesQuery.append(")\n" + + "SELECT TABLES.TABLE_NAME\n" + + "FROM TABLES\n" + + "WHERE NOT EXISTS (\n" + + " SELECT 1\n" + + " FROM ALL_QUEUE_TABLES\n" + + " WHERE ALL_QUEUE_TABLES.OWNER = TABLES.OWNER\n" + + " AND ALL_QUEUE_TABLES.QUEUE_TABLE = TABLES.TABLE_NAME\n" + + ")"); + + String[] params = new String[1]; + Arrays.fill(params, schema.getName()); + + return jdbcTemplate.queryForStringList(tablesQuery.toString(), params); + } + }, + INDEX("INDEX") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT 'DIMENSION' FROM DUAL", - schema.getName() + "SELECT INDEX_NAME FROM ALL_INDEXES WHERE OWNER = ?" + + " AND INDEX_NAME NOT LIKE 'SYS_C%'" + + " AND UNIQUENESS <> 'UNIQUE'", + schema.getName() ); } }, + SEQUENCE("SEQUENCE"), + FUNCTION("FUNCTION"), + ; private final String name; @@ -340,24 +394,24 @@ public String toString() { } public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { return jdbcTemplate.queryForStringList( - "SELECT DISTINCT OBJECT_NAME FROM ALL_OBJECTS WHERE OWNER = ? AND OBJECT_TYPE = ?", - schema.getName(), this.getName() + "SELECT DISTINCT OBJECT_NAME FROM ALL_OBJECTS WHERE OWNER = ? AND OBJECT_TYPE = ?", + schema.getName(), this.getName() ); } public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema, String objectName) { + TiberoSchema schema, String objectName) { return "DROP " + this.getName() + " " + database.quote(schema.getName(), objectName) + - (StringUtils.hasText(dropOptions) ? " " + dropOptions : ""); + (StringUtils.hasText(dropOptions) ? " " + dropOptions : ""); } public void dropObjects(JdbcTemplate jdbcTemplate, TiberoDatabase database, - TiberoSchema schema) throws SQLException { + TiberoSchema schema) throws SQLException { for (String objectName : getObjectNames(jdbcTemplate, database, schema)) { jdbcTemplate.execute( - generateDropStatement(jdbcTemplate, database, schema, objectName)); + generateDropStatement(jdbcTemplate, database, schema, objectName)); } } @@ -370,36 +424,36 @@ private void warnUnsupported(String schemaName) { } public static Set getObjectTypeNames(JdbcTemplate jdbcTemplate, - TiberoDatabase database, TiberoSchema schema) throws SQLException { + TiberoDatabase database, TiberoSchema schema) throws SQLException { String query = - "SELECT DISTINCT OBJECT_TYPE FROM " + database.dbaOrAll("OBJECTS") + " WHERE OWNER = ? " - + - "UNION SELECT '" + MATERIALIZED_VIEW_LOG.getName() + "' FROM DUAL WHERE EXISTS(" + - "SELECT * FROM ALL_MVIEW_LOGS WHERE LOG_OWNER = ?) " - + - "UNION SELECT '" + QUEUE_TABLE.getName() + "' FROM DUAL WHERE EXISTS(" + - "SELECT * FROM ALL_QUEUE_TABLES WHERE OWNER = ?) " - + - "UNION SELECT '" + DATABASE_LINK.getName() + "' FROM DUAL WHERE EXISTS(" + - "SELECT * FROM " + database.dbaOrAll("DB_LINKS") + " WHERE OWNER = ?) " + - "UNION SELECT '" + CONTEXT.getName() + "' FROM DUAL WHERE EXISTS(" + - "SELECT * FROM V$CONTEXT WHERE NAMESPACE = ?) " - + - "UNION SELECT '" + CREDENTIAL.getName() + "' FROM DUAL " - + - "UNION SELECT '" + SCHEDULER_PROGRAM.getName() + "' FROM DUAL WHERE EXISTS(" + - "SELECT * FROM " + database.dbaOrAll(SCHEDULER_PROGRAM.getName()) + " WHERE OWNER = ?) " - + - "UNION SELECT '" + SCHEDULE.getName() + "' FROM DUAL WHERE EXISTS(" + - "SELECT * FROM " + database.dbaOrAll(SCHEDULE.getName()) + " WHERE OWNER = ?) " - + - "UNION SELECT '" + SCHEDULER_JOB.getName() + "' FROM DUAL WHERE EXISTS(" + - "SELECT * FROM " + database.dbaOrAll(SCHEDULER_JOB.getName()) + " WHERE OWNER = ?) " - + - "UNION SELECT '" + SCHEDULER_CHAIN.getName() + "' FROM DUAL WHERE EXISTS(" + - "SELECT * FROM " + database.dbaOrAll(SCHEDULER_CHAIN.getName()) + " WHERE OWNER_ID IN (" - + "SELECT DISTINCT USER_ID FROM ALL_USERS WHERE USERNAME = ?)" - + ") "; + "SELECT DISTINCT OBJECT_TYPE FROM " + database.dbaOrAll("OBJECTS") + " WHERE OWNER = ? " + + + "UNION SELECT '" + MATERIALIZED_VIEW_LOG.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM ALL_MVIEW_LOGS WHERE LOG_OWNER = ?) " + + + "UNION SELECT '" + QUEUE_TABLE.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM ALL_QUEUE_TABLES WHERE OWNER = ?) " + + + "UNION SELECT '" + DATABASE_LINK.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll("DB_LINKS") + " WHERE OWNER = ?) " + + "UNION SELECT '" + CONTEXT.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM V$CONTEXT WHERE NAMESPACE = ?) " + + + "UNION SELECT '" + CREDENTIAL.getName() + "' FROM DUAL " + + + "UNION SELECT '" + SCHEDULER_PROGRAM.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll(SCHEDULER_PROGRAM.getName()) + " WHERE OWNER = ?) " + + + "UNION SELECT '" + SCHEDULE.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll(SCHEDULE.getName()) + " WHERE OWNER = ?) " + + + "UNION SELECT '" + SCHEDULER_JOB.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll(SCHEDULER_JOB.getName()) + " WHERE OWNER = ?) " + + + "UNION SELECT '" + SCHEDULER_CHAIN.getName() + "' FROM DUAL WHERE EXISTS(" + + "SELECT * FROM " + database.dbaOrAll(SCHEDULER_CHAIN.getName()) + " WHERE OWNER_ID IN (" + + "SELECT DISTINCT USER_ID FROM ALL_USERS WHERE USERNAME = ?)" + + ") "; String[] params = new String[9]; Arrays.fill(params, schema.getName()); From 138bd4be0e3fad7075b8035c5a162af378efc3ee Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Thu, 1 Aug 2024 11:36:30 +0900 Subject: [PATCH 17/34] add TiberoSchema procedure, package, package_body, library --- .../flywaydb/community/database/tibero/TiberoSchema.java | 8 ++++++++ .../flywaydb/community/database/tibero/TiberoTable.java | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java index 1618ff7..0d40c1d 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java @@ -82,6 +82,10 @@ protected void doClean() throws SQLException { INDEX, SEQUENCE, FUNCTION, + PROCEDURE, + PACKAGE, + PACKAGE_BODY, + LIBRARY, ); for (ObjectType objectType : objectTypesToClean) { @@ -369,6 +373,10 @@ public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase dat }, SEQUENCE("SEQUENCE"), FUNCTION("FUNCTION"), + PROCEDURE("PROCEDURE"), + PACKAGE("PACKAGE"), + PACKAGE_BODY("PACKAGE BODY"), + LIBRARY("LIBRARY"), ; diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java index e7f0c4b..bd1acf5 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoTable.java @@ -26,6 +26,5 @@ protected boolean doExists() throws SQLException { protected void doLock() throws SQLException { jdbcTemplate.execute("LOCK TABLE " + this + " IN EXCLUSIVE MODE"); } -} } From d1031bdf14fcd339f129dca72c02ed69660bab0f Mon Sep 17 00:00:00 2001 From: w-seok Date: Thu, 1 Aug 2024 12:17:30 +0900 Subject: [PATCH 18/34] add TiberoSchema type, directory, synonym, database_link, credential, context --- .../database/tibero/TiberoSchema.java | 71 +++++++++++++++++-- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java index 0d40c1d..03a8460 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java @@ -1,6 +1,8 @@ package org.flywaydb.community.database.tibero; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.*; + import org.flywaydb.core.api.FlywayException; import org.flywaydb.core.internal.database.base.Schema; import org.flywaydb.core.internal.database.base.Table; @@ -13,13 +15,6 @@ import java.util.List; import java.util.Set; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.*; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.FUNCTION; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.INDEX; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SEQUENCE; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.TABLE; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.VIEW; - public class TiberoSchema extends Schema { public TiberoSchema(JdbcTemplate jdbcTemplate, TiberoDatabase database, String name) { @@ -86,6 +81,13 @@ protected void doClean() throws SQLException { PACKAGE, PACKAGE_BODY, LIBRARY, + TYPE, + DIRECTORY, + SYNONYM, + + // Object types with sensitive information (passwords), skip intentionally, print warning if found. + DATABASE_LINK, + CREDENTIAL ); for (ObjectType objectType : objectTypesToClean) { @@ -377,7 +379,62 @@ public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase dat PACKAGE("PACKAGE"), PACKAGE_BODY("PACKAGE BODY"), LIBRARY("LIBRARY"), + TYPE("TYPE", "FORCE"), + DIRECTORY("DIRECTORY"), + SYNONYM("SYNONYM", "FORCE"), + DATABASE_LINK("DATABASE LINK") { + @Override + public void dropObjects(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) { + super.warnUnsupported(database.quote(schema.getName())); + } + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT DB_LINK FROM " + database.dbaOrAll("DB_LINKS") + " WHERE OWNER = ?", + schema.getName() + ); + } + + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + return "DROP " + this.getName() + " " + + objectName; + } + }, + CREDENTIAL("CREDENTIAL") { + @Override + public void dropObjects(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) { + super.warnUnsupported(database.quote(schema.getName())); + } + + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + return "BEGIN DBMS_SCHEDULER.DROP_CREDENTIAL('" + database.quote(schema.getName(), + objectName) + "', FORCE => TRUE); END;"; + } + }, + CONTEXT("CONTEXT") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT NAMESPACE FROM " + database.dbaOrAll("CONTEXT") + " WHERE SCHEMA = ?", + schema.getName() + ); + } + + @Override + public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema, String objectName) { + return "DROP " + this.getName() + " " + database.quote(objectName); // no owner + } + }, ; private final String name; From c3e6687c97f25ffe07bc082b9318cb16076986c7 Mon Sep 17 00:00:00 2001 From: birdie Date: Mon, 26 Aug 2024 14:53:35 +0900 Subject: [PATCH 19/34] chore : change default schema --- .../flywaydb/community/database/tibero/TiberoDatabase.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java index e674dc4..13bae4a 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoDatabase.java @@ -116,13 +116,10 @@ boolean isDataDictViewAccessible(String name) throws SQLException { Set getSystemSchemas() throws SQLException { Set result = new HashSet<>(Arrays.asList( - "SYS", "SYSTEM", + "SYS", "SYSCAT", - "SYSMAN", - "SYSGIS", "OUTLN", - "TIBERO", - "TIBERO1" + "SYSGIS" )); result.addAll(getMainConnection().getJdbcTemplate().queryForStringList( From d45025094efe4ef644bc7256cc256ed7e32682c3 Mon Sep 17 00:00:00 2001 From: birdie Date: Wed, 14 Aug 2024 15:24:23 +0900 Subject: [PATCH 20/34] flyway for tibero baseline test --- flyway-database-tibero/pom.xml | 26 ++-- .../database/tibero/FlywaySchemaHistory.java | 64 ++++++++++ .../database/tibero/TiberoBaselineTest.java | 116 ++++++++++++++++++ 3 files changed, 199 insertions(+), 7 deletions(-) create mode 100644 flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywaySchemaHistory.java create mode 100644 flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java diff --git a/flyway-database-tibero/pom.xml b/flyway-database-tibero/pom.xml index bc85afe..f88f0b7 100644 --- a/flyway-database-tibero/pom.xml +++ b/flyway-database-tibero/pom.xml @@ -19,13 +19,25 @@ ${project.groupId} flyway-core - - - - - - - + + com.tmax.tibero + tibero-jdbc + 7 + system + ${basedir}/libs/tibero7-jdbc.jar + + + org.junit.jupiter + junit-jupiter-engine + 5.10.0 + test + + + org.assertj + assertj-core + 3.24.2 + test + diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywaySchemaHistory.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywaySchemaHistory.java new file mode 100644 index 0000000..d77a12d --- /dev/null +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywaySchemaHistory.java @@ -0,0 +1,64 @@ +package org.flywaydb.community.database.tibero; + +public class FlywaySchemaHistory { + + private int installedRank; + private int version; + private String description; + private String type; + private String script; + private long checkSum; + private boolean success; + + public FlywaySchemaHistory(int installedRank, int version, String description, String type, String script, + long checkSum, boolean success) { + this.installedRank = installedRank; + this.version = version; + this.description = description; + this.type = type; + this.script = script; + this.checkSum = checkSum; + this.success = success; + } + + public int getInstalledRank() { + return installedRank; + } + + public int getVersion() { + return version; + } + + public String getDescription() { + return description; + } + + public String getType() { + return type; + } + + public String getScript() { + return script; + } + + public long getCheckSum() { + return checkSum; + } + + public boolean isSuccess() { + return success; + } + + @Override + public String toString() { + return "FlywaySchemaHistory{" + + "installedRank=" + installedRank + + ", version=" + version + + ", description='" + description + '\'' + + ", type='" + type + '\'' + + ", script='" + script + '\'' + + ", checkSum=" + checkSum + + ", success=" + success + + '}'; + } +} \ No newline at end of file diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java new file mode 100644 index 0000000..d59795e --- /dev/null +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java @@ -0,0 +1,116 @@ +package org.flywaydb.community.database.tibero; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import org.flywaydb.core.Flyway; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class TiberoBaselineTest { + @AfterEach + void clear() throws SQLException { + try (Connection connection = DriverManager + .getConnection("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero")) { + + try (Statement statement = connection.createStatement()) { + statement.execute("DROP TABLE flyway_users"); + statement.execute("DROP TABLE TIBERO.\"flyway_schema_history\""); + } + } + } + + + @Test + void baselineTest() throws SQLException { + + // create default table + try (Connection connection = DriverManager + .getConnection("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero")) { + + try (Statement statement = connection.createStatement()) { + + statement.execute( + "create table flyway_users ( " + + " id int primary key , " + + " name varchar2(255) " + + ");" + ); + } + } + + Flyway flyway = Flyway.configure() + .locations("classpath:db/migration") + .dataSource("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero") + .baselineVersion("1") + .load(); + + flyway.baseline(); + + List baselineTables = new ArrayList<>(); + + // check that the baseline was successful + try (Connection connection = DriverManager + .getConnection("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero")) { + + try (Statement statement = connection.createStatement()) { + ResultSet rs = statement.executeQuery( + "SELECT table_name " + + "FROM all_tables " + + "WHERE owner = 'TIBERO'" + ); + + while (rs.next()) { + String tableName = rs.getString("table_name"); + baselineTables.add(tableName); + } + } + } + + // check flyway schema history + FlywaySchemaHistory history = null; + try (Connection connection = DriverManager + .getConnection("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero")) { + + try (Statement statement = connection.createStatement()) { + ResultSet rs = statement.executeQuery( + "SELECT * " + + "FROM TIBERO.\"flyway_schema_history\"" + ); + + while (rs.next()) { + int installedRank = rs.getInt("installed_rank"); + int version = rs.getInt("version"); + String description = rs.getString("description"); + String type = rs.getString("type"); + String script = rs.getString("script"); + long checkSum = rs.getLong("checksum"); + boolean success = rs.getBoolean("success"); + + history = new FlywaySchemaHistory(installedRank, version, + description, type, script, checkSum, success); + } + } + } + + FlywaySchemaHistory finalHistory = history; + + assertAll( + () -> assertThat(finalHistory).isNotNull(), + () -> assertThat(finalHistory.getInstalledRank()).isEqualTo(1), + () -> assertThat(finalHistory.getVersion()).isEqualTo(1), + () -> assertThat(finalHistory.getDescription()).isEqualTo("<< Flyway Baseline >>"), + () -> assertThat(finalHistory.getType()).isEqualTo("BASELINE"), + () -> assertThat(finalHistory.getScript()).isEqualTo("<< Flyway Baseline >>"), + () -> assertThat(finalHistory.isSuccess()).isTrue(), + () -> assertThat(baselineTables).contains("flyway_schema_history") + ); + } +} \ No newline at end of file From b10dc11e9adc9aeb7e5807931fad6d59bd9d7e0c Mon Sep 17 00:00:00 2001 From: birdie Date: Fri, 16 Aug 2024 14:32:46 +0900 Subject: [PATCH 21/34] Separate Flyway creation logic --- .../database/tibero/FlywayForTibero.java | 34 +++++++++++++++++++ .../database/tibero/TiberoBaselineTest.java | 16 ++++----- 2 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java new file mode 100644 index 0000000..7c40027 --- /dev/null +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java @@ -0,0 +1,34 @@ +package org.flywaydb.community.database.tibero; + +import org.flywaydb.core.Flyway; + +public class FlywayForTibero { + + public static final String TIBERO_URL = "jdbc:tibero:thin:@localhost:8629:tibero"; + public static final String USER = "tibero"; + public static final String PASSWORD = "tibero"; + + /** + * Create a Flyway instance for Tibero cleanDisabled is false + * @param locations + * @return + */ + public static Flyway createFlyway(String locations) { + return createFlyway(locations, false); + } + + /** + * Create a Flyway instance for Tibero + * @param locations + * @param cleanDisabled + * @return + */ + public static Flyway createFlyway(String locations, boolean cleanDisabled) { + + return Flyway.configure() + .locations(locations) + .cleanDisabled(cleanDisabled) + .dataSource(TIBERO_URL, USER, PASSWORD) + .load(); + } +} diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java index d59795e..180823b 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java @@ -1,6 +1,7 @@ package org.flywaydb.community.database.tibero; import static org.assertj.core.api.Assertions.assertThat; +import static org.flywaydb.community.database.tibero.FlywayForTibero.*; import static org.junit.jupiter.api.Assertions.*; import java.sql.Connection; @@ -15,10 +16,11 @@ import org.junit.jupiter.api.Test; class TiberoBaselineTest { + @AfterEach void clear() throws SQLException { try (Connection connection = DriverManager - .getConnection("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero")) { + .getConnection(TIBERO_URL, USER, PASSWORD)) { try (Statement statement = connection.createStatement()) { statement.execute("DROP TABLE flyway_users"); @@ -33,7 +35,7 @@ void baselineTest() throws SQLException { // create default table try (Connection connection = DriverManager - .getConnection("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero")) { + .getConnection(TIBERO_URL, USER, PASSWORD)) { try (Statement statement = connection.createStatement()) { @@ -46,11 +48,7 @@ void baselineTest() throws SQLException { } } - Flyway flyway = Flyway.configure() - .locations("classpath:db/migration") - .dataSource("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero") - .baselineVersion("1") - .load(); + Flyway flyway = createFlyway("db/migration"); flyway.baseline(); @@ -58,7 +56,7 @@ void baselineTest() throws SQLException { // check that the baseline was successful try (Connection connection = DriverManager - .getConnection("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero")) { + .getConnection(TIBERO_URL, USER, PASSWORD)) { try (Statement statement = connection.createStatement()) { ResultSet rs = statement.executeQuery( @@ -77,7 +75,7 @@ void baselineTest() throws SQLException { // check flyway schema history FlywaySchemaHistory history = null; try (Connection connection = DriverManager - .getConnection("jdbc:tibero:thin:@localhost:8629:tibero", "tibero", "tibero")) { + .getConnection(TIBERO_URL, USER, PASSWORD)) { try (Statement statement = connection.createStatement()) { ResultSet rs = statement.executeQuery( From c120dc507bc5390528549a4098901a5a507bdb8a Mon Sep 17 00:00:00 2001 From: YGwan Date: Wed, 14 Aug 2024 18:17:39 +0900 Subject: [PATCH 22/34] add test_sql for validate test --- .../resources/db/migration-with-failed/V1__create_test.sql | 6 ++++++ .../src/test/resources/db/migration/V1__create_test.sql | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_test.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration/V1__create_test.sql diff --git a/flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_test.sql b/flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_test.sql new file mode 100644 index 0000000..0272473 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_test.sql @@ -0,0 +1,6 @@ +CREATE TABLE TEST +( + test_id VARCHAR2(255) PRIMARY KEY, + title VARCHAR2(255), + content VARCHAR2(4000) +); \ No newline at end of file diff --git a/flyway-database-tibero/src/test/resources/db/migration/V1__create_test.sql b/flyway-database-tibero/src/test/resources/db/migration/V1__create_test.sql new file mode 100644 index 0000000..f12249d --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration/V1__create_test.sql @@ -0,0 +1,6 @@ +CREATE TABLE TEST +( + test_id NUMBER(19) PRIMARY KEY, + title VARCHAR2(255), + content VARCHAR2(4000) +); \ No newline at end of file From bb9499ed4977bd80c1fcfdb32e5b1ed75118e6bb Mon Sep 17 00:00:00 2001 From: YGwan Date: Wed, 14 Aug 2024 18:18:07 +0900 Subject: [PATCH 23/34] add validate test --- .../tibero/TiberoFlywayValidateTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java new file mode 100644 index 0000000..7dd0946 --- /dev/null +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java @@ -0,0 +1,45 @@ +package org.flywaydb.community.database.tibero; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.flywaydb.community.database.tibero.FlywayForTibero.*; +import static org.junit.jupiter.api.Assertions.*; + +class TiberoFlywayValidateTest { + + @AfterEach + void clear() throws SQLException { + try (Connection connection = DriverManager + .getConnection(TIBERO_URL, USER, PASSWORD)) { + + try (Statement statement = connection.createStatement()) { + statement.execute("DROP TABLE TIBERO.\"flyway_schema_history\""); + statement.execute("DROP TABLE TEST"); + } + } + } + + @Test + void updateChecksumMigrationTest() { + + boolean success = createFlyway("classpath:db/migration").migrate().success; + + var flyway = createFlyway("classpath:db/migration-with-failed"); + + var validateResult = flyway.validateWithResult(); + + assertAll( + () -> assertThat(success).isTrue(), + () -> assertThat(validateResult.validationSuccessful).isFalse(), + () -> assertThat(validateResult.errorDetails).isNotNull(), + () -> assertThat(validateResult.invalidMigrations.get(0).description).isEqualTo("create test") + ); + } +} From 69b2592c3ed3473262e9f07ee4e55059777c2cc3 Mon Sep 17 00:00:00 2001 From: Bellroute Date: Wed, 14 Aug 2024 17:42:31 +0900 Subject: [PATCH 24/34] add info test --- .../database/tibero/TiberoBaselineTest.java | 10 ++- .../tibero/TiberoFlywayValidateTest.java | 4 +- .../database/tibero/TiberoInfoTest.java | 66 +++++++++++++++++++ .../V1__create_my_tables.sql | 4 ++ .../V2__create_my_users.sql | 5 ++ .../V3__create_my_posts.sql | 5 ++ 6 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoInfoTest.java create mode 100644 flyway-database-tibero/src/test/resources/db/migration-info-test/V1__create_my_tables.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration-info-test/V2__create_my_users.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration-info-test/V3__create_my_posts.sql diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java index 180823b..eb334d4 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java @@ -1,8 +1,11 @@ package org.flywaydb.community.database.tibero; import static org.assertj.core.api.Assertions.assertThat; -import static org.flywaydb.community.database.tibero.FlywayForTibero.*; -import static org.junit.jupiter.api.Assertions.*; +import static org.flywaydb.community.database.tibero.FlywayForTibero.PASSWORD; +import static org.flywaydb.community.database.tibero.FlywayForTibero.TIBERO_URL; +import static org.flywaydb.community.database.tibero.FlywayForTibero.USER; +import static org.flywaydb.community.database.tibero.FlywayForTibero.createFlyway; +import static org.junit.jupiter.api.Assertions.assertAll; import java.sql.Connection; import java.sql.DriverManager; @@ -13,6 +16,7 @@ import java.util.List; import org.flywaydb.core.Flyway; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class TiberoBaselineTest { @@ -29,8 +33,8 @@ void clear() throws SQLException { } } - @Test + @DisplayName("baseline test") void baselineTest() throws SQLException { // create default table diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java index 7dd0946..873e084 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java @@ -1,6 +1,7 @@ package org.flywaydb.community.database.tibero; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.sql.Connection; @@ -27,7 +28,8 @@ void clear() throws SQLException { } @Test - void updateChecksumMigrationTest() { + @DisplayName("validate test") + void validateTest() { boolean success = createFlyway("classpath:db/migration").migrate().success; diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoInfoTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoInfoTest.java new file mode 100644 index 0000000..4d87392 --- /dev/null +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoInfoTest.java @@ -0,0 +1,66 @@ +package org.flywaydb.community.database.tibero; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.flywaydb.community.database.tibero.FlywayForTibero.PASSWORD; +import static org.flywaydb.community.database.tibero.FlywayForTibero.TIBERO_URL; +import static org.flywaydb.community.database.tibero.FlywayForTibero.USER; +import static org.flywaydb.community.database.tibero.FlywayForTibero.createFlyway; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import org.flywaydb.core.api.MigrationInfo; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TiberoInfoTest { + + @AfterEach + void clear() throws SQLException { + try (Connection connection = DriverManager + .getConnection(TIBERO_URL, USER, PASSWORD)) { + + try (Statement statement = connection.createStatement()) { + statement.execute("DROP TABLE my_tables"); + statement.execute("DROP TABLE my_users"); + statement.execute("DROP TABLE my_posts"); + statement.execute("DROP TABLE TIBERO.\"flyway_schema_history\""); + } + } + } + + @BeforeEach + void setup() { + // migrate init for test "info" + } + + @Test + @DisplayName("info test") + void infoTest() { + + boolean success = createFlyway("classpath:db/migration-info-test").migrate().success; + + var flyway = createFlyway("classpath:db/migration-info-test"); + var info = flyway.info().all(); + + int actualNumOfVersion = info.length; + MigrationInfo history1 = info[0]; + MigrationInfo history2 = info[1]; + MigrationInfo history3 = info[2]; + + assertAll( + () -> assertThat(success).isTrue(), + () -> assertThat(actualNumOfVersion).isEqualTo(3), + () -> assertThat(Integer.parseInt(history1.getVersion().toString())).isEqualTo(1), + () -> assertThat(history1.getScript()).isEqualTo("V1__create_my_tables.sql"), + () -> assertThat(Integer.parseInt(history2.getVersion().toString())).isEqualTo(2), + () -> assertThat(history2.getScript()).isEqualTo("V2__create_my_users.sql"), + () -> assertThat(Integer.parseInt(history3.getVersion().toString())).isEqualTo(3), + () -> assertThat(history3.getScript()).isEqualTo("V3__create_my_posts.sql") + ); + } +} \ No newline at end of file diff --git a/flyway-database-tibero/src/test/resources/db/migration-info-test/V1__create_my_tables.sql b/flyway-database-tibero/src/test/resources/db/migration-info-test/V1__create_my_tables.sql new file mode 100644 index 0000000..34d4bca --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-info-test/V1__create_my_tables.sql @@ -0,0 +1,4 @@ +CREATE TABLE my_tables ( + id NUMBER PRIMARY KEY, + name VARCHAR2(50) +); diff --git a/flyway-database-tibero/src/test/resources/db/migration-info-test/V2__create_my_users.sql b/flyway-database-tibero/src/test/resources/db/migration-info-test/V2__create_my_users.sql new file mode 100644 index 0000000..8568a09 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-info-test/V2__create_my_users.sql @@ -0,0 +1,5 @@ +CREATE TABLE my_users ( + id NUMBER PRIMARY KEY, + name VARCHAR2(50), + age INT +); diff --git a/flyway-database-tibero/src/test/resources/db/migration-info-test/V3__create_my_posts.sql b/flyway-database-tibero/src/test/resources/db/migration-info-test/V3__create_my_posts.sql new file mode 100644 index 0000000..bb70e6a --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-info-test/V3__create_my_posts.sql @@ -0,0 +1,5 @@ +CREATE TABLE my_posts ( + id NUMBER PRIMARY KEY, + title VARCHAR2(50), + content VARCHAR2(255) +); From e083186e9c343ca4281ecb2b9cc6cd2ca91e0aad Mon Sep 17 00:00:00 2001 From: w-seok Date: Mon, 19 Aug 2024 09:15:14 +0900 Subject: [PATCH 25/34] add repair test --- .../database/tibero/FlywayForTibero.java | 1 + .../tibero/TiberoFlywayRepairTest.java | 82 +++++++++++++++++++ .../V2__create_failed_test.sql | 5 ++ 3 files changed, 88 insertions(+) create mode 100644 flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayRepairTest.java create mode 100644 flyway-database-tibero/src/test/resources/db/migration-with-failed/V2__create_failed_test.sql diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java index 7c40027..cf76e7d 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java @@ -5,6 +5,7 @@ public class FlywayForTibero { public static final String TIBERO_URL = "jdbc:tibero:thin:@localhost:8629:tibero"; + public static final String SCHEMA = "TIBERO"; public static final String USER = "tibero"; public static final String PASSWORD = "tibero"; diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayRepairTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayRepairTest.java new file mode 100644 index 0000000..cd11eb6 --- /dev/null +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayRepairTest.java @@ -0,0 +1,82 @@ +package org.flywaydb.community.database.tibero; + +import static org.flywaydb.community.database.tibero.FlywayForTibero.PASSWORD; +import static org.flywaydb.community.database.tibero.FlywayForTibero.SCHEMA; +import static org.flywaydb.community.database.tibero.FlywayForTibero.TIBERO_URL; +import static org.flywaydb.community.database.tibero.FlywayForTibero.USER; +import static org.flywaydb.community.database.tibero.FlywayForTibero.createFlyway; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import org.assertj.core.api.SoftAssertions; +import org.flywaydb.core.Flyway; +import org.flywaydb.core.api.FlywayException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TiberoFlywayRepairTest { + + @BeforeEach + @AfterEach + void cleanup() throws SQLException { + try (Connection connection = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT TABLE_NAME FROM USER_TABLES WHERE TABLESPACE_NAME = " + "'" + SCHEMA + "'")) { + + List tables = new ArrayList<>(); + while (resultSet.next()) { + tables.add(resultSet.getString("TABLE_NAME")); + } + + for (String tableName : tables) { + String dropTableQuery = "DROP TABLE \"" + tableName + "\" CASCADE CONSTRAINTS"; + statement.executeUpdate(dropTableQuery); + } + } + } + + @Test + @DisplayName("Repair test") + void repairFailedMigration() throws SQLException { + + SoftAssertions softAssertions = new SoftAssertions(); + + // 1. Attempt to run a failing migration + Flyway failedFlyway = createFlyway("classpath:db/migration-with-failed"); + softAssertions.assertThatThrownBy(failedFlyway::migrate).isInstanceOf(FlywayException.class); + + // 2. Verify the failed migration + try (Connection conn = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT COUNT(*) FROM TIBERO.\"flyway_schema_history\" WHERE \"success\" = 0")) { + + rs.next(); + + softAssertions.assertThat(rs.getInt(1)).isEqualTo(1); + } + + // 3. Execute Repair + failedFlyway.repair(); + + // 4. Verify that the failed migration has been removed after Repair + try (Connection conn = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery( + "SELECT COUNT(*) FROM TIBERO.\"flyway_schema_history\" WHERE \"success\" = 0")) { + rs.next(); + softAssertions.assertThat(rs.getInt(1)).isEqualTo(1); + } + + softAssertions.assertAll(); + } + +} diff --git a/flyway-database-tibero/src/test/resources/db/migration-with-failed/V2__create_failed_test.sql b/flyway-database-tibero/src/test/resources/db/migration-with-failed/V2__create_failed_test.sql new file mode 100644 index 0000000..cca1363 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-with-failed/V2__create_failed_test.sql @@ -0,0 +1,5 @@ +CREATE TABLE INVALID_TABLE +( + id INT PRIMARY KEY, + invalid_column INVALID_DATA_TYPE -- invalid type +); From 53af9dc012fdc36c4c6953a721d2267bf180a8af Mon Sep 17 00:00:00 2001 From: birdie Date: Mon, 19 Aug 2024 09:54:47 +0900 Subject: [PATCH 26/34] Adapted to team conventions --- ...est.java => TiberoFlywayBaselineTest.java} | 24 ++++++++++---- ...nfoTest.java => TiberoFlywayInfoTest.java} | 33 +++++++++++-------- .../tibero/TiberoFlywayRepairTest.java | 2 +- .../tibero/TiberoFlywayValidateTest.java | 24 ++++++++++---- 4 files changed, 55 insertions(+), 28 deletions(-) rename flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/{TiberoBaselineTest.java => TiberoFlywayBaselineTest.java} (81%) rename flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/{TiberoInfoTest.java => TiberoFlywayInfoTest.java} (68%) diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayBaselineTest.java similarity index 81% rename from flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java rename to flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayBaselineTest.java index eb334d4..5e22b4a 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoBaselineTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayBaselineTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.flywaydb.community.database.tibero.FlywayForTibero.PASSWORD; +import static org.flywaydb.community.database.tibero.FlywayForTibero.SCHEMA; import static org.flywaydb.community.database.tibero.FlywayForTibero.TIBERO_URL; import static org.flywaydb.community.database.tibero.FlywayForTibero.USER; import static org.flywaydb.community.database.tibero.FlywayForTibero.createFlyway; @@ -16,19 +17,28 @@ import java.util.List; import org.flywaydb.core.Flyway; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class TiberoBaselineTest { +class TiberoFlywayBaselineTest { + @BeforeEach @AfterEach - void clear() throws SQLException { - try (Connection connection = DriverManager - .getConnection(TIBERO_URL, USER, PASSWORD)) { + void cleanup() throws SQLException { + try (Connection connection = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT TABLE_NAME FROM USER_TABLES WHERE TABLESPACE_NAME = " + "'" + SCHEMA + "'")) { + + List tables = new ArrayList<>(); + while (resultSet.next()) { + tables.add(resultSet.getString("TABLE_NAME")); + } - try (Statement statement = connection.createStatement()) { - statement.execute("DROP TABLE flyway_users"); - statement.execute("DROP TABLE TIBERO.\"flyway_schema_history\""); + for (String tableName : tables) { + String dropTableQuery = "DROP TABLE \"" + tableName + "\" CASCADE CONSTRAINTS"; + statement.executeUpdate(dropTableQuery); } } } diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoInfoTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayInfoTest.java similarity index 68% rename from flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoInfoTest.java rename to flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayInfoTest.java index 4d87392..821ee34 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoInfoTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayInfoTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.flywaydb.community.database.tibero.FlywayForTibero.PASSWORD; +import static org.flywaydb.community.database.tibero.FlywayForTibero.SCHEMA; import static org.flywaydb.community.database.tibero.FlywayForTibero.TIBERO_URL; import static org.flywaydb.community.database.tibero.FlywayForTibero.USER; import static org.flywaydb.community.database.tibero.FlywayForTibero.createFlyway; @@ -9,33 +10,37 @@ import java.sql.Connection; import java.sql.DriverManager; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; import org.flywaydb.core.api.MigrationInfo; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class TiberoInfoTest { +class TiberoFlywayInfoTest { + @BeforeEach @AfterEach - void clear() throws SQLException { - try (Connection connection = DriverManager - .getConnection(TIBERO_URL, USER, PASSWORD)) { + void cleanup() throws SQLException { + try (Connection connection = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT TABLE_NAME FROM USER_TABLES WHERE TABLESPACE_NAME = " + "'" + SCHEMA + "'")) { - try (Statement statement = connection.createStatement()) { - statement.execute("DROP TABLE my_tables"); - statement.execute("DROP TABLE my_users"); - statement.execute("DROP TABLE my_posts"); - statement.execute("DROP TABLE TIBERO.\"flyway_schema_history\""); + List tables = new ArrayList<>(); + while (resultSet.next()) { + tables.add(resultSet.getString("TABLE_NAME")); } - } - } - @BeforeEach - void setup() { - // migrate init for test "info" + for (String tableName : tables) { + String dropTableQuery = "DROP TABLE \"" + tableName + "\" CASCADE CONSTRAINTS"; + statement.executeUpdate(dropTableQuery); + } + } } @Test diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayRepairTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayRepairTest.java index cd11eb6..843753f 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayRepairTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayRepairTest.java @@ -73,7 +73,7 @@ void repairFailedMigration() throws SQLException { ResultSet rs = stmt.executeQuery( "SELECT COUNT(*) FROM TIBERO.\"flyway_schema_history\" WHERE \"success\" = 0")) { rs.next(); - softAssertions.assertThat(rs.getInt(1)).isEqualTo(1); + softAssertions.assertThat(rs.getInt(1)).isEqualTo(0); } softAssertions.assertAll(); diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java index 873e084..c6e3a88 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java @@ -1,6 +1,10 @@ package org.flywaydb.community.database.tibero; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -15,14 +19,22 @@ class TiberoFlywayValidateTest { + @BeforeEach @AfterEach - void clear() throws SQLException { - try (Connection connection = DriverManager - .getConnection(TIBERO_URL, USER, PASSWORD)) { + void cleanup() throws SQLException { + try (Connection connection = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT TABLE_NAME FROM USER_TABLES WHERE TABLESPACE_NAME = " + "'" + SCHEMA + "'")) { + + List tables = new ArrayList<>(); + while (resultSet.next()) { + tables.add(resultSet.getString("TABLE_NAME")); + } - try (Statement statement = connection.createStatement()) { - statement.execute("DROP TABLE TIBERO.\"flyway_schema_history\""); - statement.execute("DROP TABLE TEST"); + for (String tableName : tables) { + String dropTableQuery = "DROP TABLE \"" + tableName + "\" CASCADE CONSTRAINTS"; + statement.executeUpdate(dropTableQuery); } } } From 677251ab00b480e507dfdc62e31ce28b5832469c Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Mon, 19 Aug 2024 11:01:59 +0900 Subject: [PATCH 27/34] migration test --- .../tibero/TiberoFlywayMigrationTest.java | 91 +++++++++++++++++++ .../db/migration-step-1/V1__create_tables.sql | 18 ++++ .../db/migration-step-2/V1__create_tables.sql | 18 ++++ .../db/migration-step-2/V2__insert_data.sql | 5 + .../V1__create_tables.sql | 18 ++++ .../migration-step-final/V2__insert_data.sql | 5 + .../db/migration-step-final/V3__add_index.sql | 2 + 7 files changed, 157 insertions(+) create mode 100644 flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java create mode 100644 flyway-database-tibero/src/test/resources/db/migration-step-1/V1__create_tables.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration-step-2/V1__create_tables.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration-step-2/V2__insert_data.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration-step-final/V1__create_tables.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration-step-final/V2__insert_data.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration-step-final/V3__add_index.sql diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java new file mode 100644 index 0000000..0d4dac7 --- /dev/null +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java @@ -0,0 +1,91 @@ +package org.flywaydb.community.database.tibero; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.flywaydb.community.database.tibero.FlywayForTibero.PASSWORD; +import static org.flywaydb.community.database.tibero.FlywayForTibero.SCHEMA; +import static org.flywaydb.community.database.tibero.FlywayForTibero.TIBERO_URL; +import static org.flywaydb.community.database.tibero.FlywayForTibero.USER; +import static org.flywaydb.community.database.tibero.FlywayForTibero.createFlyway; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + + +public class TiberoFlywayMigrationTest { + + private static final String[] EVOLUTION_SCHEMA_MIGRATION_DIRS = new String[]{ + "migration-step-1", "migration-step-2", "migration-step-final"}; + private static final String[] EVOLUTION_SCHEMA_MIGRATION_SCRIPT_NAMES = new String[]{ + "V1__create_tables.sql", "V2__insert_data.sql", "V3__add_index.sql"}; + + @BeforeEach + @AfterEach + void cleanup() throws SQLException { + try (Connection connection = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT TABLE_NAME FROM USER_TABLES WHERE TABLESPACE_NAME = " + "'" + SCHEMA + "'")) { + + List tables = new ArrayList<>(); + while (resultSet.next()) { + tables.add(resultSet.getString("TABLE_NAME")); + } + + for (String tableName : tables) { + String dropTableQuery = "DROP TABLE \"" + tableName + "\" CASCADE CONSTRAINTS"; + statement.executeUpdate(dropTableQuery); + } + } + } + + @Test + @DisplayName("migration simple test") + void migrationTest() { + assertThat(createFlyway("classpath:db/migration-final").migrate().success).isTrue(); + } + + @Test + @DisplayName("migration evolution test") + void evolutionSchemaTest() throws SQLException { + SoftAssertions softAssertions = new SoftAssertions(); + + for (String migrationDir : EVOLUTION_SCHEMA_MIGRATION_DIRS) { + assertThat(createFlyway("classpath:db/" + migrationDir).migrate().success).isTrue(); + } + + // 1. Verify that the flyway_schema_history table is properly logged after migration + try (Connection conn = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement stmt = conn.createStatement(); + ResultSet schema_history_cnt = stmt.executeQuery( + "SELECT COUNT(*) FROM TIBERO.\"flyway_schema_history\" WHERE \"success\" = 1")) { + + schema_history_cnt.next(); + softAssertions.assertThat(schema_history_cnt.getInt(1)).isEqualTo(3); + } + + // 2. Verify script names + try (Connection conn = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement stmt = conn.createStatement(); + ResultSet script_names = stmt.executeQuery( + "SELECT \"script\" FROM TIBERO.\"flyway_schema_history\" WHERE \"success\" = 1")) { + while (script_names.next()) { + softAssertions.assertThat(script_names.getString(1)) + .containsAnyOf(EVOLUTION_SCHEMA_MIGRATION_SCRIPT_NAMES); + } + } + + softAssertions.assertAll(); + } + + +} diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-1/V1__create_tables.sql b/flyway-database-tibero/src/test/resources/db/migration-step-1/V1__create_tables.sql new file mode 100644 index 0000000..4f297c3 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-step-1/V1__create_tables.sql @@ -0,0 +1,18 @@ +CREATE TABLE "MY_USERS" ( + "ID" NUMBER(38, 0) NOT NULL, + "NAME" VARCHAR(255) NULL, + "AGE" NUMBER +); + +ALTER TABLE "MY_USERS" + ADD CONSTRAINT "PK_MY_USERS" PRIMARY KEY ("ID"); + +CREATE TABLE "MY_POSTS" ( + "ID" NUMBER(38, 0) NOT NULL, + "USER_ID" NUMBER(38, 0) NOT NULL, + "TITLE" VARCHAR(255) NULL, + "CONTENT" VARCHAR(255) +); + +ALTER TABLE "MY_POSTS" + ADD CONSTRAINT "PK_MY_POSTS" PRIMARY KEY ("ID"); diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-2/V1__create_tables.sql b/flyway-database-tibero/src/test/resources/db/migration-step-2/V1__create_tables.sql new file mode 100644 index 0000000..4f297c3 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-step-2/V1__create_tables.sql @@ -0,0 +1,18 @@ +CREATE TABLE "MY_USERS" ( + "ID" NUMBER(38, 0) NOT NULL, + "NAME" VARCHAR(255) NULL, + "AGE" NUMBER +); + +ALTER TABLE "MY_USERS" + ADD CONSTRAINT "PK_MY_USERS" PRIMARY KEY ("ID"); + +CREATE TABLE "MY_POSTS" ( + "ID" NUMBER(38, 0) NOT NULL, + "USER_ID" NUMBER(38, 0) NOT NULL, + "TITLE" VARCHAR(255) NULL, + "CONTENT" VARCHAR(255) +); + +ALTER TABLE "MY_POSTS" + ADD CONSTRAINT "PK_MY_POSTS" PRIMARY KEY ("ID"); diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-2/V2__insert_data.sql b/flyway-database-tibero/src/test/resources/db/migration-step-2/V2__insert_data.sql new file mode 100644 index 0000000..64fa6c5 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-step-2/V2__insert_data.sql @@ -0,0 +1,5 @@ +INSERT INTO MY_USERS (ID, NAME, AGE) + VALUES(1, 'HANI', 27); + +INSERT INTO MY_POSTS (ID, USER_ID, TITLE, CONTENT) + VALUES(1, 1, 'my first post', 'this is my first post'); diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-final/V1__create_tables.sql b/flyway-database-tibero/src/test/resources/db/migration-step-final/V1__create_tables.sql new file mode 100644 index 0000000..4f297c3 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-step-final/V1__create_tables.sql @@ -0,0 +1,18 @@ +CREATE TABLE "MY_USERS" ( + "ID" NUMBER(38, 0) NOT NULL, + "NAME" VARCHAR(255) NULL, + "AGE" NUMBER +); + +ALTER TABLE "MY_USERS" + ADD CONSTRAINT "PK_MY_USERS" PRIMARY KEY ("ID"); + +CREATE TABLE "MY_POSTS" ( + "ID" NUMBER(38, 0) NOT NULL, + "USER_ID" NUMBER(38, 0) NOT NULL, + "TITLE" VARCHAR(255) NULL, + "CONTENT" VARCHAR(255) +); + +ALTER TABLE "MY_POSTS" + ADD CONSTRAINT "PK_MY_POSTS" PRIMARY KEY ("ID"); diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-final/V2__insert_data.sql b/flyway-database-tibero/src/test/resources/db/migration-step-final/V2__insert_data.sql new file mode 100644 index 0000000..64fa6c5 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-step-final/V2__insert_data.sql @@ -0,0 +1,5 @@ +INSERT INTO MY_USERS (ID, NAME, AGE) + VALUES(1, 'HANI', 27); + +INSERT INTO MY_POSTS (ID, USER_ID, TITLE, CONTENT) + VALUES(1, 1, 'my first post', 'this is my first post'); diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-final/V3__add_index.sql b/flyway-database-tibero/src/test/resources/db/migration-step-final/V3__add_index.sql new file mode 100644 index 0000000..5ebf4f9 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-step-final/V3__add_index.sql @@ -0,0 +1,2 @@ +CREATE INDEX MY_USERS_NAME_INDEX ON MY_USERS (NAME); +CREATE INDEX MY_POSTS_TITLE_INDEX ON MY_POSTS (TITLE); \ No newline at end of file From c393b8af7731a502ce8c77f0e20abfef6dc27967 Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Mon, 19 Aug 2024 11:12:15 +0900 Subject: [PATCH 28/34] =?UTF-8?q?simple=20test=20SoftAssertions=EB=A1=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../community/database/tibero/TiberoFlywayMigrationTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java index 0d4dac7..c473981 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java @@ -51,7 +51,8 @@ void cleanup() throws SQLException { @Test @DisplayName("migration simple test") void migrationTest() { - assertThat(createFlyway("classpath:db/migration-final").migrate().success).isTrue(); + SoftAssertions softAssertions = new SoftAssertions(); + softAssertions.assertThat(createFlyway("classpath:db/migration-final").migrate().success).isTrue(); } @Test From 2a56b3f3b609b956401f02dc91d5e38859e766fd Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Mon, 19 Aug 2024 14:53:30 +0900 Subject: [PATCH 29/34] =?UTF-8?q?simple=20test=20SoftAssertions=EB=A1=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=952?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../community/database/tibero/TiberoFlywayMigrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java index c473981..d97ca77 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java @@ -61,7 +61,7 @@ void evolutionSchemaTest() throws SQLException { SoftAssertions softAssertions = new SoftAssertions(); for (String migrationDir : EVOLUTION_SCHEMA_MIGRATION_DIRS) { - assertThat(createFlyway("classpath:db/" + migrationDir).migrate().success).isTrue(); + softAssertions.assertThat(createFlyway("classpath:db/" + migrationDir).migrate().success).isTrue(); } // 1. Verify that the flyway_schema_history table is properly logged after migration From 580a73d1d66f1eb1ecd0f71afddb0cf0f911999d Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Mon, 19 Aug 2024 15:43:23 +0900 Subject: [PATCH 30/34] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EA=B0=9C=ED=96=89=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../community/database/tibero/TiberoFlywayMigrationTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java index d97ca77..86398f1 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java @@ -87,6 +87,4 @@ void evolutionSchemaTest() throws SQLException { softAssertions.assertAll(); } - - } From 0538f5e5e5ab8cf737d3600546fa4970b373bf73 Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Tue, 27 Aug 2024 15:52:54 +0900 Subject: [PATCH 31/34] =?UTF-8?q?clean=20test=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SEQUENCE, INDEX, SCHEDULER, SYNONYMS 등 clean test를 위한 SQL 추가 (V3__create_objects.sql) - test 작성 - sql 패키지 변경으로 인한 변경사항 적용 --- .../database/tibero/TiberoSchema.java | 51 ++++++++--- .../tibero/TiberoFlywayCleanTest.java | 89 +++++++++++++++++++ .../tibero/TiberoFlywayMigrationTest.java | 9 +- .../tibero/TiberoFlywayValidateTest.java | 2 +- .../V1__create_tables.sql | 26 ++++++ .../V2__insert_data.sql | 0 .../V3__create_objects.sql | 56 ++++++++++++ .../db/migration-step-1/V1__create_tables.sql | 22 +++-- .../db/migration-step-2/V1__create_tables.sql | 18 ---- .../V1__create_tables.sql | 18 ---- .../db/migration-step-final/V3__add_index.sql | 2 - .../V1__create_tables.sql | 26 ++++++ .../migration-with-failed/V1__create_test.sql | 6 -- .../V2__insert_data.sql | 0 ...ed_test.sql => V3__create_failed_test.sql} | 0 .../db/migration/V1__create_tables.sql | 26 ++++++ .../db/migration/V1__create_test.sql | 6 -- .../db/migration/V2__insert_data.sql | 5 ++ 18 files changed, 289 insertions(+), 73 deletions(-) create mode 100644 flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java create mode 100644 flyway-database-tibero/src/test/resources/db/migration-clean-test/V1__create_tables.sql rename flyway-database-tibero/src/test/resources/db/{migration-step-2 => migration-clean-test}/V2__insert_data.sql (100%) create mode 100644 flyway-database-tibero/src/test/resources/db/migration-clean-test/V3__create_objects.sql delete mode 100644 flyway-database-tibero/src/test/resources/db/migration-step-2/V1__create_tables.sql delete mode 100644 flyway-database-tibero/src/test/resources/db/migration-step-final/V1__create_tables.sql delete mode 100644 flyway-database-tibero/src/test/resources/db/migration-step-final/V3__add_index.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_tables.sql delete mode 100644 flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_test.sql rename flyway-database-tibero/src/test/resources/db/{migration-step-final => migration-with-failed}/V2__insert_data.sql (100%) rename flyway-database-tibero/src/test/resources/db/migration-with-failed/{V2__create_failed_test.sql => V3__create_failed_test.sql} (100%) create mode 100644 flyway-database-tibero/src/test/resources/db/migration/V1__create_tables.sql delete mode 100644 flyway-database-tibero/src/test/resources/db/migration/V1__create_test.sql create mode 100644 flyway-database-tibero/src/test/resources/db/migration/V2__insert_data.sql diff --git a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java index 03a8460..a1a9f7a 100644 --- a/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java +++ b/flyway-database-tibero/src/main/java/org/flywaydb/community/database/tibero/TiberoSchema.java @@ -1,19 +1,41 @@ package org.flywaydb.community.database.tibero; -import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.*; - -import org.flywaydb.core.api.FlywayException; -import org.flywaydb.core.internal.database.base.Schema; -import org.flywaydb.core.internal.database.base.Table; -import org.flywaydb.core.internal.jdbc.JdbcTemplate; -import org.flywaydb.core.internal.util.StringUtils; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.CREDENTIAL; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.DATABASE_LINK; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.DIMENSION; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.DIRECTORY; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.FUNCTION; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.INDEX; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.LIBRARY; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.MATERIALIZED_VIEW; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.MATERIALIZED_VIEW_LOG; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.PACKAGE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.PACKAGE_BODY; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.PROCEDURE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.QUEUE_TABLE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULER_CHAIN; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULER_JOB; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SCHEDULER_PROGRAM; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SEQUENCE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SQL_TRANSLATION_PROFILE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.SYNONYM; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.TABLE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.TRIGGER; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.TYPE; +import static org.flywaydb.community.database.tibero.TiberoSchema.ObjectType.VIEW; import java.sql.SQLException; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import org.flywaydb.core.api.FlywayException; +import org.flywaydb.core.internal.database.base.Schema; +import org.flywaydb.core.internal.database.base.Table; +import org.flywaydb.core.internal.jdbc.JdbcTemplate; +import org.flywaydb.core.internal.util.StringUtils; public class TiberoSchema extends Schema { @@ -88,7 +110,7 @@ protected void doClean() throws SQLException { // Object types with sensitive information (passwords), skip intentionally, print warning if found. DATABASE_LINK, CREDENTIAL - ); + ); for (ObjectType objectType : objectTypesToClean) { if (objectTypeNames.contains(objectType.getName())) { @@ -302,7 +324,16 @@ public String generateDropStatement(JdbcTemplate jdbcTemplate, TiberoDatabase da } }, - MATERIALIZED_VIEW("MATERIALIZED VIEW", "PRESERVE TABLE"), + MATERIALIZED_VIEW("MATERIALIZED VIEW", "PRESERVE TABLE") { + @Override + public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase database, + TiberoSchema schema) throws SQLException { + return jdbcTemplate.queryForStringList( + "SELECT MVIEW_NAME FROM ALL_MVIEWS WHERE OWNER = ?", + schema.getName() + ); + } + }, MATERIALIZED_VIEW_LOG("MATERIALIZED VIEW LOG") { @Override @@ -381,7 +412,7 @@ public List getObjectNames(JdbcTemplate jdbcTemplate, TiberoDatabase dat LIBRARY("LIBRARY"), TYPE("TYPE", "FORCE"), DIRECTORY("DIRECTORY"), - SYNONYM("SYNONYM", "FORCE"), + SYNONYM("SYNONYM"), DATABASE_LINK("DATABASE LINK") { @Override public void dropObjects(JdbcTemplate jdbcTemplate, TiberoDatabase database, diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java new file mode 100644 index 0000000..5a374b3 --- /dev/null +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java @@ -0,0 +1,89 @@ +package org.flywaydb.community.database.tibero; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.flywaydb.community.database.tibero.FlywayForTibero.PASSWORD; +import static org.flywaydb.community.database.tibero.FlywayForTibero.SCHEMA; +import static org.flywaydb.community.database.tibero.FlywayForTibero.TIBERO_URL; +import static org.flywaydb.community.database.tibero.FlywayForTibero.USER; +import static org.flywaydb.community.database.tibero.FlywayForTibero.createFlyway; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import org.assertj.core.api.SoftAssertions; +import org.flywaydb.core.Flyway; +import org.flywaydb.core.api.output.CleanResult; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TiberoFlywayCleanTest { + + private static final String[] OBJECTS_INFO_TABLES = new String[]{ + "ALL_TABLES", "ALL_SYNONYMS", "ALL_VIEWS", "ALL_SCHEDULER_CHAINS", + "ALL_SCHEDULER_PROGRAMS", "ALL_SCHEDULER_SCHEDULES"}; + + @BeforeEach + @AfterEach + void cleanup() throws SQLException { + createFlyway("classpath:db/migration-clean-test").clean(); + } + +// @BeforeEach // TODO : 지워줄 방법이 없다.. +// void clear() throws SQLException { +// try (Connection connection = DriverManager +// .getConnection(TIBERO_URL, USER, PASSWORD)) { +// +// try (Statement statement = connection.createStatement()) { +// // PSM compile error 혹은 없으면 예외를 던져버림.. +// statement.execute("CALL DBMS_SCHEDULER.CREATE_PROGRAM('MY_PROGRAM')"); +// +// } +// } +// } + + @Test + @DisplayName("clean test") + void cleanTest() throws SQLException { + SoftAssertions softAssertions = new SoftAssertions(); + + Flyway flyway = createFlyway("classpath:db/migration-clean-test"); + boolean success = flyway.migrate().success; + CleanResult cleanResult = flyway.clean(); + + // 1. Verify created objects were properly dropped + try (Connection conn = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + Statement stmt = conn.createStatement(); + ResultSet objectCnt = stmt.executeQuery(getCountObjectsQuery(SCHEMA))) { + + objectCnt.next(); + softAssertions.assertThat(objectCnt.getInt(1)).isEqualTo(0); + } + + assertAll( + () -> assertThat(success).isTrue(), + () -> assertThat(cleanResult.schemasCleaned).contains(SCHEMA) + + ); + } + + private String getCountObjectsQuery(String schema) { + StringBuilder query = new StringBuilder(); + + query.append("SELECT COUNT(*) FROM ( "); + query.append("SELECT SEQUENCE_OWNER FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER = '" + schema + "'"); + + Arrays.stream(OBJECTS_INFO_TABLES) + .forEach(table -> query.append( + String.format(" UNION ALL SELECT OWNER FROM %s WHERE OWNER = '%s'", table, schema))); + + query.append(");"); + + return query.toString(); + } +} diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java index 86398f1..592e208 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayMigrationTest.java @@ -1,6 +1,5 @@ package org.flywaydb.community.database.tibero; -import static org.assertj.core.api.Assertions.assertThat; import static org.flywaydb.community.database.tibero.FlywayForTibero.PASSWORD; import static org.flywaydb.community.database.tibero.FlywayForTibero.SCHEMA; import static org.flywaydb.community.database.tibero.FlywayForTibero.TIBERO_URL; @@ -24,9 +23,9 @@ public class TiberoFlywayMigrationTest { private static final String[] EVOLUTION_SCHEMA_MIGRATION_DIRS = new String[]{ - "migration-step-1", "migration-step-2", "migration-step-final"}; + "migration-step-1", "migration"}; private static final String[] EVOLUTION_SCHEMA_MIGRATION_SCRIPT_NAMES = new String[]{ - "V1__create_tables.sql", "V2__insert_data.sql", "V3__add_index.sql"}; + "V1__create_tables.sql", "V2__insert_data.sql"}; @BeforeEach @AfterEach @@ -52,7 +51,7 @@ void cleanup() throws SQLException { @DisplayName("migration simple test") void migrationTest() { SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(createFlyway("classpath:db/migration-final").migrate().success).isTrue(); + softAssertions.assertThat(createFlyway("classpath:db/migration").migrate().success).isTrue(); } @Test @@ -71,7 +70,7 @@ void evolutionSchemaTest() throws SQLException { "SELECT COUNT(*) FROM TIBERO.\"flyway_schema_history\" WHERE \"success\" = 1")) { schema_history_cnt.next(); - softAssertions.assertThat(schema_history_cnt.getInt(1)).isEqualTo(3); + softAssertions.assertThat(schema_history_cnt.getInt(1)).isEqualTo(2); } // 2. Verify script names diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java index c6e3a88..f0f0f96 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayValidateTest.java @@ -53,7 +53,7 @@ void validateTest() { () -> assertThat(success).isTrue(), () -> assertThat(validateResult.validationSuccessful).isFalse(), () -> assertThat(validateResult.errorDetails).isNotNull(), - () -> assertThat(validateResult.invalidMigrations.get(0).description).isEqualTo("create test") + () -> assertThat(validateResult.invalidMigrations.get(0).description).isEqualTo("create failed test") ); } } diff --git a/flyway-database-tibero/src/test/resources/db/migration-clean-test/V1__create_tables.sql b/flyway-database-tibero/src/test/resources/db/migration-clean-test/V1__create_tables.sql new file mode 100644 index 0000000..c6f38f7 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-clean-test/V1__create_tables.sql @@ -0,0 +1,26 @@ +CREATE TABLE "MY_USERS" ( + "ID" NUMBER(38, 0) NOT NULL, + "NAME" VARCHAR(255) NULL, + "AGE" NUMBER +); + +ALTER TABLE "MY_USERS" + ADD CONSTRAINT "PK_MY_USERS" PRIMARY KEY ("ID"); +ALTER TABLE "MY_USERS" + ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; +ALTER TABLE "MY_USERS" + ADD UPDATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; + +CREATE TABLE "MY_POSTS" ( + "ID" NUMBER(38, 0) NOT NULL, + "USER_ID" NUMBER(38, 0) NOT NULL, + "TITLE" VARCHAR(255) NULL, + "CONTENT" VARCHAR(255) +); + +ALTER TABLE "MY_POSTS" + ADD CONSTRAINT "PK_MY_POSTS" PRIMARY KEY ("ID"); +ALTER TABLE "MY_POSTS" + ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; +ALTER TABLE "MY_POSTS" + ADD UPDATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-2/V2__insert_data.sql b/flyway-database-tibero/src/test/resources/db/migration-clean-test/V2__insert_data.sql similarity index 100% rename from flyway-database-tibero/src/test/resources/db/migration-step-2/V2__insert_data.sql rename to flyway-database-tibero/src/test/resources/db/migration-clean-test/V2__insert_data.sql diff --git a/flyway-database-tibero/src/test/resources/db/migration-clean-test/V3__create_objects.sql b/flyway-database-tibero/src/test/resources/db/migration-clean-test/V3__create_objects.sql new file mode 100644 index 0000000..9cdcbf3 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-clean-test/V3__create_objects.sql @@ -0,0 +1,56 @@ +-- create view +CREATE TABLE CONTRACT +(age NUMBER, sex NUMBER, salary NUMBER, + workplace VARCHAR(30)); + +CREATE VIEW CONTRACT_VIEW AS + SELECT age, sex, salary * 1000 salary_won + FROM contract + WHERE workplace = 'Seoul'; + +-- create index +CREATE INDEX MY_USERS_NAME_INDEX ON MY_USERS (NAME); + +-- create sequence +CREATE SEQUENCE "TEMP_SEQ" INCREMENT BY 1 START WITH 1 ORDER; + +-- crate materialized view +CREATE TABLE MV_TABLE AS ( + SELECT MOD(level, 100) a, level*10 b FROM dual CONNECT BY level<=100); + +CREATE MATERIALIZED VIEW MV ENABLE QUERY rewrite AS + SELECT SUM(a+b) s, COUNT(b+a) c FROM MV_TABLE; + +-- create queue table +CALL DBMS_AQADM.CREATE_QUEUE_TABLE('MY_QUEUE_TABLE', 'RAW'); + +-- create scheduler Program +CALL DBMS_SCHEDULER.CREATE_PROGRAM(program_name => 'MY_PROGRAM', + program_type => 'PSM_BLOCK', + program_action => 'my_job;'); + +-- create schedule +CALL DBMS_SCHEDULER.CREATE_SCHEDULE( + schedule_name => 'MY_SCHEDULE', + repeat_interval => 'FREQ=HOURLY; BYHOUR=1,2,3; BYMINUTE=0; BYSECOND=30'); + +-- create scheduler Chain +CALL DBMS_SCHEDULER.CREATE_CHAIN(chain_name => 'MY_SCHEDULE_CHAIN', + rule_set_name => NULL, + evaluation_interval => NULL, + comments => 'my first job chain'); + +-- -- create scheduler Chain Rule +-- CALL DBMS_SCHEDULER.DEFINE_CHAIN_RULE ( +-- 'MY_SCHEDULE_CHAIN_RULE', +-- '1=1', +-- 'start step1', +-- 'RULE1'); +-- +-- -- create scheduler Chain Step +-- CALL DBMS_SCHEDULER.DEFINE_CHAIN_STEP ( +-- 'MY_SCHEDULE_CHAIN_STEP', +-- 'STEP1', +-- 'example_program'); + +CREATE OR REPLACE SYNONYM my_synonym FOR tibero.emp; \ No newline at end of file diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-1/V1__create_tables.sql b/flyway-database-tibero/src/test/resources/db/migration-step-1/V1__create_tables.sql index 4f297c3..c6f38f7 100644 --- a/flyway-database-tibero/src/test/resources/db/migration-step-1/V1__create_tables.sql +++ b/flyway-database-tibero/src/test/resources/db/migration-step-1/V1__create_tables.sql @@ -1,18 +1,26 @@ CREATE TABLE "MY_USERS" ( - "ID" NUMBER(38, 0) NOT NULL, - "NAME" VARCHAR(255) NULL, - "AGE" NUMBER + "ID" NUMBER(38, 0) NOT NULL, + "NAME" VARCHAR(255) NULL, + "AGE" NUMBER ); ALTER TABLE "MY_USERS" ADD CONSTRAINT "PK_MY_USERS" PRIMARY KEY ("ID"); +ALTER TABLE "MY_USERS" + ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; +ALTER TABLE "MY_USERS" + ADD UPDATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; CREATE TABLE "MY_POSTS" ( - "ID" NUMBER(38, 0) NOT NULL, - "USER_ID" NUMBER(38, 0) NOT NULL, - "TITLE" VARCHAR(255) NULL, - "CONTENT" VARCHAR(255) + "ID" NUMBER(38, 0) NOT NULL, + "USER_ID" NUMBER(38, 0) NOT NULL, + "TITLE" VARCHAR(255) NULL, + "CONTENT" VARCHAR(255) ); ALTER TABLE "MY_POSTS" ADD CONSTRAINT "PK_MY_POSTS" PRIMARY KEY ("ID"); +ALTER TABLE "MY_POSTS" + ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; +ALTER TABLE "MY_POSTS" + ADD UPDATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-2/V1__create_tables.sql b/flyway-database-tibero/src/test/resources/db/migration-step-2/V1__create_tables.sql deleted file mode 100644 index 4f297c3..0000000 --- a/flyway-database-tibero/src/test/resources/db/migration-step-2/V1__create_tables.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE "MY_USERS" ( - "ID" NUMBER(38, 0) NOT NULL, - "NAME" VARCHAR(255) NULL, - "AGE" NUMBER -); - -ALTER TABLE "MY_USERS" - ADD CONSTRAINT "PK_MY_USERS" PRIMARY KEY ("ID"); - -CREATE TABLE "MY_POSTS" ( - "ID" NUMBER(38, 0) NOT NULL, - "USER_ID" NUMBER(38, 0) NOT NULL, - "TITLE" VARCHAR(255) NULL, - "CONTENT" VARCHAR(255) -); - -ALTER TABLE "MY_POSTS" - ADD CONSTRAINT "PK_MY_POSTS" PRIMARY KEY ("ID"); diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-final/V1__create_tables.sql b/flyway-database-tibero/src/test/resources/db/migration-step-final/V1__create_tables.sql deleted file mode 100644 index 4f297c3..0000000 --- a/flyway-database-tibero/src/test/resources/db/migration-step-final/V1__create_tables.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE "MY_USERS" ( - "ID" NUMBER(38, 0) NOT NULL, - "NAME" VARCHAR(255) NULL, - "AGE" NUMBER -); - -ALTER TABLE "MY_USERS" - ADD CONSTRAINT "PK_MY_USERS" PRIMARY KEY ("ID"); - -CREATE TABLE "MY_POSTS" ( - "ID" NUMBER(38, 0) NOT NULL, - "USER_ID" NUMBER(38, 0) NOT NULL, - "TITLE" VARCHAR(255) NULL, - "CONTENT" VARCHAR(255) -); - -ALTER TABLE "MY_POSTS" - ADD CONSTRAINT "PK_MY_POSTS" PRIMARY KEY ("ID"); diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-final/V3__add_index.sql b/flyway-database-tibero/src/test/resources/db/migration-step-final/V3__add_index.sql deleted file mode 100644 index 5ebf4f9..0000000 --- a/flyway-database-tibero/src/test/resources/db/migration-step-final/V3__add_index.sql +++ /dev/null @@ -1,2 +0,0 @@ -CREATE INDEX MY_USERS_NAME_INDEX ON MY_USERS (NAME); -CREATE INDEX MY_POSTS_TITLE_INDEX ON MY_POSTS (TITLE); \ No newline at end of file diff --git a/flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_tables.sql b/flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_tables.sql new file mode 100644 index 0000000..c6f38f7 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_tables.sql @@ -0,0 +1,26 @@ +CREATE TABLE "MY_USERS" ( + "ID" NUMBER(38, 0) NOT NULL, + "NAME" VARCHAR(255) NULL, + "AGE" NUMBER +); + +ALTER TABLE "MY_USERS" + ADD CONSTRAINT "PK_MY_USERS" PRIMARY KEY ("ID"); +ALTER TABLE "MY_USERS" + ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; +ALTER TABLE "MY_USERS" + ADD UPDATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; + +CREATE TABLE "MY_POSTS" ( + "ID" NUMBER(38, 0) NOT NULL, + "USER_ID" NUMBER(38, 0) NOT NULL, + "TITLE" VARCHAR(255) NULL, + "CONTENT" VARCHAR(255) +); + +ALTER TABLE "MY_POSTS" + ADD CONSTRAINT "PK_MY_POSTS" PRIMARY KEY ("ID"); +ALTER TABLE "MY_POSTS" + ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; +ALTER TABLE "MY_POSTS" + ADD UPDATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; diff --git a/flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_test.sql b/flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_test.sql deleted file mode 100644 index 0272473..0000000 --- a/flyway-database-tibero/src/test/resources/db/migration-with-failed/V1__create_test.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE TEST -( - test_id VARCHAR2(255) PRIMARY KEY, - title VARCHAR2(255), - content VARCHAR2(4000) -); \ No newline at end of file diff --git a/flyway-database-tibero/src/test/resources/db/migration-step-final/V2__insert_data.sql b/flyway-database-tibero/src/test/resources/db/migration-with-failed/V2__insert_data.sql similarity index 100% rename from flyway-database-tibero/src/test/resources/db/migration-step-final/V2__insert_data.sql rename to flyway-database-tibero/src/test/resources/db/migration-with-failed/V2__insert_data.sql diff --git a/flyway-database-tibero/src/test/resources/db/migration-with-failed/V2__create_failed_test.sql b/flyway-database-tibero/src/test/resources/db/migration-with-failed/V3__create_failed_test.sql similarity index 100% rename from flyway-database-tibero/src/test/resources/db/migration-with-failed/V2__create_failed_test.sql rename to flyway-database-tibero/src/test/resources/db/migration-with-failed/V3__create_failed_test.sql diff --git a/flyway-database-tibero/src/test/resources/db/migration/V1__create_tables.sql b/flyway-database-tibero/src/test/resources/db/migration/V1__create_tables.sql new file mode 100644 index 0000000..c6f38f7 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration/V1__create_tables.sql @@ -0,0 +1,26 @@ +CREATE TABLE "MY_USERS" ( + "ID" NUMBER(38, 0) NOT NULL, + "NAME" VARCHAR(255) NULL, + "AGE" NUMBER +); + +ALTER TABLE "MY_USERS" + ADD CONSTRAINT "PK_MY_USERS" PRIMARY KEY ("ID"); +ALTER TABLE "MY_USERS" + ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; +ALTER TABLE "MY_USERS" + ADD UPDATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; + +CREATE TABLE "MY_POSTS" ( + "ID" NUMBER(38, 0) NOT NULL, + "USER_ID" NUMBER(38, 0) NOT NULL, + "TITLE" VARCHAR(255) NULL, + "CONTENT" VARCHAR(255) +); + +ALTER TABLE "MY_POSTS" + ADD CONSTRAINT "PK_MY_POSTS" PRIMARY KEY ("ID"); +ALTER TABLE "MY_POSTS" + ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; +ALTER TABLE "MY_POSTS" + ADD UPDATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP; diff --git a/flyway-database-tibero/src/test/resources/db/migration/V1__create_test.sql b/flyway-database-tibero/src/test/resources/db/migration/V1__create_test.sql deleted file mode 100644 index f12249d..0000000 --- a/flyway-database-tibero/src/test/resources/db/migration/V1__create_test.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE TEST -( - test_id NUMBER(19) PRIMARY KEY, - title VARCHAR2(255), - content VARCHAR2(4000) -); \ No newline at end of file diff --git a/flyway-database-tibero/src/test/resources/db/migration/V2__insert_data.sql b/flyway-database-tibero/src/test/resources/db/migration/V2__insert_data.sql new file mode 100644 index 0000000..64fa6c5 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/db/migration/V2__insert_data.sql @@ -0,0 +1,5 @@ +INSERT INTO MY_USERS (ID, NAME, AGE) + VALUES(1, 'HANI', 27); + +INSERT INTO MY_POSTS (ID, USER_ID, TITLE, CONTENT) + VALUES(1, 1, 'my first post', 'this is my first post'); From 85bed4f3569d439024ac371c9456d7894e5457d6 Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Fri, 30 Aug 2024 13:35:53 +0900 Subject: [PATCH 32/34] =?UTF-8?q?Clean=20test=20setUp=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20Scheduler=20?= =?UTF-8?q?=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_schema 생성 후 Clean test 를 진행하는 방식으로 수정 --- .../tibero/TiberoFlywayCleanTest.java | 58 ++++++++++--------- .../V3__create_objects.sql | 33 ++++++----- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java index 5a374b3..f22c60e 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java @@ -1,11 +1,7 @@ package org.flywaydb.community.database.tibero; import static org.assertj.core.api.Assertions.assertThat; -import static org.flywaydb.community.database.tibero.FlywayForTibero.PASSWORD; -import static org.flywaydb.community.database.tibero.FlywayForTibero.SCHEMA; import static org.flywaydb.community.database.tibero.FlywayForTibero.TIBERO_URL; -import static org.flywaydb.community.database.tibero.FlywayForTibero.USER; -import static org.flywaydb.community.database.tibero.FlywayForTibero.createFlyway; import static org.junit.jupiter.api.Assertions.assertAll; import java.sql.Connection; @@ -17,49 +13,60 @@ import org.assertj.core.api.SoftAssertions; import org.flywaydb.core.Flyway; import org.flywaydb.core.api.output.CleanResult; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class TiberoFlywayCleanTest { + private static final String TEST_USER = "HANI"; + private static final String TEST_PASSWORD = "PASSWORD"; + private static final String[] OBJECTS_INFO_TABLES = new String[]{ "ALL_TABLES", "ALL_SYNONYMS", "ALL_VIEWS", "ALL_SCHEDULER_CHAINS", "ALL_SCHEDULER_PROGRAMS", "ALL_SCHEDULER_SCHEDULES"}; @BeforeEach - @AfterEach - void cleanup() throws SQLException { - createFlyway("classpath:db/migration-clean-test").clean(); + void setUp() throws SQLException { + try (Connection connection = DriverManager + .getConnection(TIBERO_URL, "sys", "tibero")) { + try (Statement statement = connection.createStatement()) { + + // 1. check if test schema exists + ResultSet resultSet = statement.executeQuery( + "SELECT username FROM dba_users WHERE username = '" + TEST_USER + "'"); + + // 1-1. if exists, drop test schema + if (resultSet.isBeforeFirst()) { + statement.execute("DROP USER " + TEST_USER + " CASCADE"); + } + + // 2. create test schema to test clean + statement.execute( + "CREATE USER " + TEST_USER + " IDENTIFIED BY " + TEST_PASSWORD + " DEFAULT TABLESPACE TIBERO"); + statement.execute("GRANT RESOURCE, CONNECT, DBA TO " + TEST_USER); + } + } } -// @BeforeEach // TODO : 지워줄 방법이 없다.. -// void clear() throws SQLException { -// try (Connection connection = DriverManager -// .getConnection(TIBERO_URL, USER, PASSWORD)) { -// -// try (Statement statement = connection.createStatement()) { -// // PSM compile error 혹은 없으면 예외를 던져버림.. -// statement.execute("CALL DBMS_SCHEDULER.CREATE_PROGRAM('MY_PROGRAM')"); -// -// } -// } -// } - @Test @DisplayName("clean test") void cleanTest() throws SQLException { SoftAssertions softAssertions = new SoftAssertions(); - Flyway flyway = createFlyway("classpath:db/migration-clean-test"); + Flyway flyway = Flyway.configure() + .locations("classpath:db/migration-clean-test") + .cleanDisabled(false) + .dataSource(TIBERO_URL, TEST_USER, TEST_PASSWORD) + .load(); + boolean success = flyway.migrate().success; CleanResult cleanResult = flyway.clean(); // 1. Verify created objects were properly dropped - try (Connection conn = DriverManager.getConnection(TIBERO_URL, USER, PASSWORD); + try (Connection conn = DriverManager.getConnection(TIBERO_URL, TEST_USER, TEST_PASSWORD); Statement stmt = conn.createStatement(); - ResultSet objectCnt = stmt.executeQuery(getCountObjectsQuery(SCHEMA))) { + ResultSet objectCnt = stmt.executeQuery(getCountObjectsQuery(TEST_USER))) { objectCnt.next(); softAssertions.assertThat(objectCnt.getInt(1)).isEqualTo(0); @@ -67,8 +74,7 @@ void cleanTest() throws SQLException { assertAll( () -> assertThat(success).isTrue(), - () -> assertThat(cleanResult.schemasCleaned).contains(SCHEMA) - + () -> assertThat(cleanResult.schemasCleaned).contains(TEST_USER) ); } diff --git a/flyway-database-tibero/src/test/resources/db/migration-clean-test/V3__create_objects.sql b/flyway-database-tibero/src/test/resources/db/migration-clean-test/V3__create_objects.sql index 9cdcbf3..4fc18bc 100644 --- a/flyway-database-tibero/src/test/resources/db/migration-clean-test/V3__create_objects.sql +++ b/flyway-database-tibero/src/test/resources/db/migration-clean-test/V3__create_objects.sql @@ -24,22 +24,22 @@ CREATE MATERIALIZED VIEW MV ENABLE QUERY rewrite AS -- create queue table CALL DBMS_AQADM.CREATE_QUEUE_TABLE('MY_QUEUE_TABLE', 'RAW'); --- create scheduler Program -CALL DBMS_SCHEDULER.CREATE_PROGRAM(program_name => 'MY_PROGRAM', - program_type => 'PSM_BLOCK', - program_action => 'my_job;'); - --- create schedule -CALL DBMS_SCHEDULER.CREATE_SCHEDULE( - schedule_name => 'MY_SCHEDULE', - repeat_interval => 'FREQ=HOURLY; BYHOUR=1,2,3; BYMINUTE=0; BYSECOND=30'); - --- create scheduler Chain -CALL DBMS_SCHEDULER.CREATE_CHAIN(chain_name => 'MY_SCHEDULE_CHAIN', - rule_set_name => NULL, - evaluation_interval => NULL, - comments => 'my first job chain'); - +-- -- create scheduler Program +-- CALL DBMS_SCHEDULER.CREATE_PROGRAM(program_name => 'MY_PROGRAM', +-- program_type => 'PSM_BLOCK', +-- program_action => 'my_job;'); +-- +-- -- create schedule +-- CALL DBMS_SCHEDULER.CREATE_SCHEDULE( +-- schedule_name => 'MY_SCHEDULE', +-- repeat_interval => 'FREQ=HOURLY; BYHOUR=1,2,3; BYMINUTE=0; BYSECOND=30'); +-- +-- -- create scheduler Chain +-- CALL DBMS_SCHEDULER.CREATE_CHAIN(chain_name => 'MY_SCHEDULE_CHAIN', +-- rule_set_name => NULL, +-- evaluation_interval => NULL, +-- comments => 'my first job chain'); +-- -- -- create scheduler Chain Rule -- CALL DBMS_SCHEDULER.DEFINE_CHAIN_RULE ( -- 'MY_SCHEDULE_CHAIN_RULE', @@ -53,4 +53,5 @@ CALL DBMS_SCHEDULER.CREATE_CHAIN(chain_name => 'MY_SCHEDULE_CHAIN', -- 'STEP1', -- 'example_program'); +-- create synonym CREATE OR REPLACE SYNONYM my_synonym FOR tibero.emp; \ No newline at end of file From d00a192e19221a3515c32fe5f3cf014595199d0d Mon Sep 17 00:00:00 2001 From: seunghan0421 Date: Mon, 2 Sep 2024 14:55:58 +0900 Subject: [PATCH 33/34] =?UTF-8?q?softAssertions.assertAll()=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../community/database/tibero/TiberoFlywayCleanTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java index f22c60e..e538d8f 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TiberoFlywayCleanTest.java @@ -76,6 +76,8 @@ void cleanTest() throws SQLException { () -> assertThat(success).isTrue(), () -> assertThat(cleanResult.schemasCleaned).contains(TEST_USER) ); + + softAssertions.assertAll(); } private String getCountObjectsQuery(String schema) { From 366f0686b54d0d763800c358509f4512c56ad367 Mon Sep 17 00:00:00 2001 From: w-seok Date: Mon, 9 Sep 2024 14:28:21 +0900 Subject: [PATCH 34/34] =?UTF-8?q?test=20=ED=99=98=EA=B2=BD=20local=20datab?= =?UTF-8?q?ase=EC=97=90=EC=84=9C=20testContainer=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flyway-database-tibero/pom.xml | 12 ++++++ .../database/tibero/FlywayForTibero.java | 8 ++-- .../tibero/TestContainerBaseTests.java | 38 +++++++++++++++++++ .../test/resources/docker/docker-compose.yml | 10 +++++ .../src/test/resources/docker/license.xml | 14 +++++++ 5 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TestContainerBaseTests.java create mode 100755 flyway-database-tibero/src/test/resources/docker/docker-compose.yml create mode 100644 flyway-database-tibero/src/test/resources/docker/license.xml diff --git a/flyway-database-tibero/pom.xml b/flyway-database-tibero/pom.xml index f88f0b7..ae05070 100644 --- a/flyway-database-tibero/pom.xml +++ b/flyway-database-tibero/pom.xml @@ -38,6 +38,18 @@ 3.24.2 test + + org.testcontainers + testcontainers + 1.18.0 + test + + + org.testcontainers + junit-jupiter + 1.18.0 + test + diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java index cf76e7d..89d2db8 100644 --- a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/FlywayForTibero.java @@ -2,12 +2,12 @@ import org.flywaydb.core.Flyway; -public class FlywayForTibero { +class FlywayForTibero extends TestContainerBaseTests { - public static final String TIBERO_URL = "jdbc:tibero:thin:@localhost:8629:tibero"; + public static final String TIBERO_URL = getJdbcUrl(); public static final String SCHEMA = "TIBERO"; - public static final String USER = "tibero"; - public static final String PASSWORD = "tibero"; + public static final String USER = getUsername(); + public static final String PASSWORD = getPassword(); /** * Create a Flyway instance for Tibero cleanDisabled is false diff --git a/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TestContainerBaseTests.java b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TestContainerBaseTests.java new file mode 100644 index 0000000..e8cbf38 --- /dev/null +++ b/flyway-database-tibero/src/test/java/org/flywaydb/community/database/tibero/TestContainerBaseTests.java @@ -0,0 +1,38 @@ +package org.flywaydb.community.database.tibero; + +import java.io.File; +import java.time.Duration; + +import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.junit.jupiter.Container; + +abstract class TestContainerBaseTests { + + @Container + public static DockerComposeContainer environment = + new DockerComposeContainer<>(new File("src/test/resources/docker/docker-compose.yml")) + .withExposedService("tibero-test", 8629, + Wait.forLogMessage(".*database system is ready to accept connections.*", 1) + .withStartupTimeout(Duration.ofMinutes(5))); + + static { + environment.start(); + } + + protected static String getJdbcUrl() { + return String.format("jdbc:tibero:thin:@%s:%d:tibero", + environment.getServiceHost("tibero-test", 8629), + environment.getServicePort("tibero-test", 8629)); + } + + protected static String getUsername() { + return "tibero"; + } + + protected static String getPassword() { + return "tibero"; + } +} + + diff --git a/flyway-database-tibero/src/test/resources/docker/docker-compose.yml b/flyway-database-tibero/src/test/resources/docker/docker-compose.yml new file mode 100755 index 0000000..6334116 --- /dev/null +++ b/flyway-database-tibero/src/test/resources/docker/docker-compose.yml @@ -0,0 +1,10 @@ +services: + tibero-test: + image: ghcr.io/tibero-support/tibero7 + platform: linux/amd64 + ports: + - "8629" + hostname: localhost + volumes: + - ./license.xml:/tibero7/license/license.xml + diff --git a/flyway-database-tibero/src/test/resources/docker/license.xml b/flyway-database-tibero/src/test/resources/docker/license.xml new file mode 100644 index 0000000..cd2079e --- /dev/null +++ b/flyway-database-tibero/src/test/resources/docker/license.xml @@ -0,0 +1,14 @@ + + + + Tibero + 1725250710 + 2024/09/02 + localhost + standard + demo + 183 + localhost + xeTJu5Y1eUEr4RE2fKh5FFWRaNPbQ6WxuVHzJwQetUI= + +