From 284606e2071ef679eb0a492361c677af1e6577fc Mon Sep 17 00:00:00 2001
From: Jan Volf <1275348+javolek@users.noreply.github.com>
Date: Tue, 23 Apr 2024 10:49:56 +0200
Subject: [PATCH 1/2] Crate Database support Extension implementation
---
flyway-database-crate/pom.xml | 43 +++++++++++++
.../database/CrateDatabaseExtension.java | 24 +++++++
.../database/crate/CrateConnection.java | 22 +++++++
.../database/crate/CrateDatabase.java | 64 +++++++++++++++++++
.../database/crate/CrateDatabaseType.java | 57 +++++++++++++++++
.../community/database/crate/CrateParser.java | 11 ++++
.../community/database/crate/CrateSchema.java | 64 +++++++++++++++++++
.../community/database/crate/CrateTable.java | 29 +++++++++
.../org.flywaydb.core.extensibility.Plugin | 1 +
.../community/database/crate/version.txt | 1 +
pom.xml | 1 +
11 files changed, 317 insertions(+)
create mode 100644 flyway-database-crate/pom.xml
create mode 100644 flyway-database-crate/src/main/java/org/flywaydb/community/database/CrateDatabaseExtension.java
create mode 100644 flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateConnection.java
create mode 100644 flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateDatabase.java
create mode 100644 flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateDatabaseType.java
create mode 100644 flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateParser.java
create mode 100644 flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateSchema.java
create mode 100644 flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateTable.java
create mode 100644 flyway-database-crate/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin
create mode 100644 flyway-database-crate/src/main/resources/org/flywaydb/community/database/crate/version.txt
diff --git a/flyway-database-crate/pom.xml b/flyway-database-crate/pom.xml
new file mode 100644
index 0000000..f659f4b
--- /dev/null
+++ b/flyway-database-crate/pom.xml
@@ -0,0 +1,43 @@
+
+
+ 4.0.0
+
+ org.flywaydb
+ flyway-community-db-support
+ 10.11.0
+
+
+ flyway-database-crate
+ ${project.artifactId}
+
+
+
+ ${project.groupId}
+ flyway-core
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ maven-resources-plugin
+
+
+ maven-jar-plugin
+
+
+
+
\ No newline at end of file
diff --git a/flyway-database-crate/src/main/java/org/flywaydb/community/database/CrateDatabaseExtension.java b/flyway-database-crate/src/main/java/org/flywaydb/community/database/CrateDatabaseExtension.java
new file mode 100644
index 0000000..008f1b3
--- /dev/null
+++ b/flyway-database-crate/src/main/java/org/flywaydb/community/database/CrateDatabaseExtension.java
@@ -0,0 +1,24 @@
+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;
+
+public class CrateDatabaseExtension implements PluginMetadata {
+ public String getDescription() {
+ return "Community-contributed Crate database support extension " + readVersion() + " by JaVol";
+ }
+
+ public static String readVersion() {
+ try {
+ return FileUtils.copyToString(
+ CrateDatabaseExtension.class.getClassLoader().getResourceAsStream("org/flywaydb/community/database/crate/version.txt"),
+ StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ throw new FlywayException("Unable to read extension version: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateConnection.java b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateConnection.java
new file mode 100644
index 0000000..ca30560
--- /dev/null
+++ b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateConnection.java
@@ -0,0 +1,22 @@
+package org.flywaydb.community.database.crate;
+
+import org.flywaydb.core.internal.database.base.Connection;
+import org.flywaydb.core.internal.database.base.Schema;
+
+import java.sql.SQLException;
+
+public class CrateConnection extends Connection {
+ public CrateConnection(CrateDatabase database, java.sql.Connection connection) {
+ super(database, connection);
+ }
+
+ @Override
+ protected String getCurrentSchemaNameOrSearchPath() throws SQLException {
+ return jdbcTemplate.queryForString("SELECT current_schema");
+ }
+
+ @Override
+ public Schema getSchema(String name) {
+ return new CrateSchema(jdbcTemplate, database, name);
+ }
+}
diff --git a/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateDatabase.java b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateDatabase.java
new file mode 100644
index 0000000..b4ec47c
--- /dev/null
+++ b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateDatabase.java
@@ -0,0 +1,64 @@
+package org.flywaydb.community.database.crate;
+
+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;
+
+import java.sql.Connection;
+
+public class CrateDatabase extends Database {
+
+ public CrateDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
+ super(configuration, jdbcConnectionFactory, statementInterceptor);
+ }
+
+ @Override
+ protected CrateConnection doGetConnection(Connection connection) {
+ return new CrateConnection(this, connection);
+ }
+
+ @Override
+ public void ensureSupported(Configuration configuration) {
+ // NOOP
+ }
+
+ @Override
+ public boolean supportsDdlTransactions() {
+ return false;
+ }
+
+ @Override
+ public String getBooleanTrue() {
+ return "TRUE";
+ }
+
+ @Override
+ public String getBooleanFalse() {
+ return "FALSE";
+ }
+
+ @Override
+ public boolean catalogIsSchema() {
+ return false;
+ }
+
+ @Override
+ public String getRawCreateScript(Table table, boolean baseline) {
+ return "CREATE TABLE " + table + """
+ (
+ installed_rank INT NOT NULL PRIMARY KEY,
+ version VARCHAR(50),
+ description VARCHAR(200) NOT NULL,
+ type VARCHAR(20) NOT NULL,
+ script VARCHAR(1000) NOT NULL,
+ checksum INTEGER,
+ installed_by varchar(100) NOT NULL,
+ installed_on TIMESTAMP NOT NULL DEFAULT now(),
+ execution_time INTEGER NOT NULL,
+ success BOOLEAN NOT NULL
+ );
+ """ + (baseline ? getBaselineStatement(table) + ";\n" : "");
+ }
+}
diff --git a/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateDatabaseType.java b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateDatabaseType.java
new file mode 100644
index 0000000..41e09fe
--- /dev/null
+++ b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateDatabaseType.java
@@ -0,0 +1,57 @@
+package org.flywaydb.community.database.crate;
+
+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;
+
+import java.sql.Connection;
+import java.sql.Types;
+
+public class CrateDatabaseType extends BaseDatabaseType implements CommunityDatabaseType {
+ @Override
+ public String getName() {
+ return "CrateDB";
+ }
+
+ @Override
+ public int getNullType() {
+ return Types.NULL;
+ }
+
+ @Override
+ public boolean handlesJDBCUrl(String url) {
+ return url.startsWith("jdbc:postgresql:");
+ }
+
+ @Override
+ public String getDriverClass(String url, ClassLoader classLoader) {
+ return "org.postgresql.Driver";
+ }
+
+ @Override
+ public boolean handlesDatabaseProductNameAndVersion(String databaseProductName, String databaseProductVersion, Connection connection) {
+ return databaseProductName.contains("PostgreSQL");
+ }
+
+ @Override
+ public Database createDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
+ return new CrateDatabase(configuration, jdbcConnectionFactory, statementInterceptor);
+ }
+
+ @Override
+ public Parser createParser(Configuration configuration, ResourceProvider resourceProvider, ParsingContext parsingContext) {
+ return new CrateParser(configuration, parsingContext);
+ }
+
+ @Override
+ public int getPriority() {
+ // have a precedence over standard PostgreSQL
+ return 1;
+ }
+}
diff --git a/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateParser.java b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateParser.java
new file mode 100644
index 0000000..f87a480
--- /dev/null
+++ b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateParser.java
@@ -0,0 +1,11 @@
+package org.flywaydb.community.database.crate;
+
+import org.flywaydb.core.api.configuration.Configuration;
+import org.flywaydb.core.internal.parser.Parser;
+import org.flywaydb.core.internal.parser.ParsingContext;
+
+public class CrateParser extends Parser {
+ public CrateParser(Configuration configuration, ParsingContext parsingContext) {
+ super(configuration, parsingContext, 3);
+ }
+}
diff --git a/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateSchema.java b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateSchema.java
new file mode 100644
index 0000000..c331cd4
--- /dev/null
+++ b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateSchema.java
@@ -0,0 +1,64 @@
+package org.flywaydb.community.database.crate;
+
+import org.flywaydb.core.internal.database.base.Schema;
+import org.flywaydb.core.internal.database.base.Table;
+import org.flywaydb.core.internal.jdbc.JdbcTemplate;
+
+import java.sql.SQLException;
+import java.util.List;
+
+public class CrateSchema extends Schema {
+ public CrateSchema(JdbcTemplate jdbcTemplate, CrateDatabase database, String name) {
+ super(jdbcTemplate, database, name);
+ }
+
+ @Override
+ protected boolean doExists() throws SQLException {
+ return jdbcTemplate.queryForInt("SELECT COUNT() FROM information_schema.schemata WHERE schema_name = ?",
+ name) > 0;
+ }
+
+ @Override
+ protected boolean doEmpty() throws SQLException {
+ return jdbcTemplate.queryForInt("""
+ SELECT COUNT() FROM (
+ SELECT table_name FROM information_schema.tables WHERE table_schema = ? UNION
+ SELECT table_name FROM information_schema.views WHERE table_schema = ? UNION
+ SELECT rountine_name FROM information_schema.routines WHERE routine_schema = ?
+ ) objs""",
+ name, name, name) == 0;
+ }
+
+ @Override
+ protected void doCreate() throws SQLException {
+ // schema cannot be explicitly created
+ // NOOP
+ }
+
+ @Override
+ protected void doDrop() throws SQLException {
+ // schema cannot be explicitly removed
+ // NOOP
+ }
+
+ @Override
+ protected void doClean() throws SQLException {
+
+ }
+
+ @Override
+ protected CrateTable[] doAllTables() throws SQLException {
+ return jdbcTemplate
+ .queryForStringList("SELECT table_name FROM information_schema.tables WHERE table_schema = ?",
+ name)
+ .stream()
+ .map( tableName -> new CrateTable(jdbcTemplate, database, this, tableName) )
+ .toArray(CrateTable[]::new);
+ }
+
+ @Override
+ public Table getTable(String tableName) {
+ return new CrateTable(jdbcTemplate, database, this, tableName);
+ }
+
+}
diff --git a/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateTable.java b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateTable.java
new file mode 100644
index 0000000..0637006
--- /dev/null
+++ b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateTable.java
@@ -0,0 +1,29 @@
+package org.flywaydb.community.database.crate;
+
+import org.flywaydb.core.internal.database.base.Table;
+import org.flywaydb.core.internal.jdbc.JdbcTemplate;
+
+import java.sql.SQLException;
+
+public class CrateTable extends Table {
+ public CrateTable(JdbcTemplate jdbcTemplate, CrateDatabase database, CrateSchema schema, String name) {
+ super(jdbcTemplate, database, schema, name);
+ }
+
+ @Override
+ protected void doDrop() throws SQLException {
+ jdbcTemplate.execute("DROP TABLE " + this);
+ }
+
+ @Override
+ protected boolean doExists() throws SQLException {
+ return jdbcTemplate.queryForInt(
+ "SELECT COUNT() FROM information_schema.tables WHERE table_schema = ? AND table_name = ?",
+ schema.getName(), name) > 0;
+ }
+
+ @Override
+ protected void doLock() throws SQLException {
+ // NOOP - There is no support for locking in CrateDB
+ }
+}
diff --git a/flyway-database-crate/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin b/flyway-database-crate/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin
new file mode 100644
index 0000000..6b5adcc
--- /dev/null
+++ b/flyway-database-crate/src/main/resources/META-INF/services/org.flywaydb.core.extensibility.Plugin
@@ -0,0 +1 @@
+org.flywaydb.community.database.crate.CrateDatabaseType
diff --git a/flyway-database-crate/src/main/resources/org/flywaydb/community/database/crate/version.txt b/flyway-database-crate/src/main/resources/org/flywaydb/community/database/crate/version.txt
new file mode 100644
index 0000000..1785151
--- /dev/null
+++ b/flyway-database-crate/src/main/resources/org/flywaydb/community/database/crate/version.txt
@@ -0,0 +1 @@
+${pom.version}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index d8a0157..f26f015 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,6 +37,7 @@
flyway-database-yugabytedb
flyway-database-clickhouse
flyway-database-oceanbase
+ flyway-database-crate
From 89590b004dd7186ada4e91cb03cfed516aa28557 Mon Sep 17 00:00:00 2001
From: Jan Volf <1275348+javolek@users.noreply.github.com>
Date: Wed, 24 Apr 2024 11:54:35 +0200
Subject: [PATCH 2/2] fixed schema object selection, implementing cleaning of
database schema
---
.../community/database/crate/CrateSchema.java | 30 +++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateSchema.java b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateSchema.java
index c331cd4..be20455 100644
--- a/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateSchema.java
+++ b/flyway-database-crate/src/main/java/org/flywaydb/community/database/crate/CrateSchema.java
@@ -22,9 +22,9 @@ protected boolean doExists() throws SQLException {
protected boolean doEmpty() throws SQLException {
return jdbcTemplate.queryForInt("""
SELECT COUNT() FROM (
- SELECT table_name FROM information_schema.tables WHERE table_schema = ? UNION
+ SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_schema = ? UNION
SELECT table_name FROM information_schema.views WHERE table_schema = ? UNION
- SELECT rountine_name FROM information_schema.routines WHERE routine_schema = ?
+ SELECT routine_name FROM information_schema.routines WHERE routine_schema = ?
) objs""",
name, name, name) == 0;
}
@@ -43,7 +43,33 @@ protected void doDrop() throws SQLException {
@Override
protected void doClean() throws SQLException {
+ // drop views
+ List dropViewStatements = jdbcTemplate.queryForStringList(
+ "SELECT table_name FROM information_schema.views WHERE table_schema = ?", name)
+ .stream().map(viewName -> "DROP VIEW IF EXISTS "+database.quote(name, viewName)).toList();
+ for (String stmt : dropViewStatements) {
+ jdbcTemplate.execute(stmt);
+ }
+ // drop tables
+ List dropTableStatements = jdbcTemplate.queryForStringList(
+ "SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_schema = ?", name)
+ .stream().map(tableName -> "DROP TABLE IF EXISTS "+database.quote(name, tableName)).toList();
+ for (String stmt : dropTableStatements) {
+ jdbcTemplate.execute(stmt);
+ }
+
+ // drop functions
+ List dropFunctionStatements = jdbcTemplate.queryForList(
+ "SELECT routine_name, specific_name FROM information_schema.routines WHERE routine_schema = ?", name)
+ .stream().map(result -> {
+ String fnName = result.get("routine_name");
+ String fnArgs = result.get("specific_name").substring(fnName.length());
+ return "DROP FUNCTION IF EXISTS " + database.quote(name, fnName) + fnArgs;
+ }).toList();
+ for (String stmt : dropFunctionStatements) {
+ jdbcTemplate.execute(stmt);
+ }
}
@Override