From 8e83af8c8bb0a7e1cfe376a5be6bc5e21ab907bb Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Tue, 19 Sep 2023 08:47:54 +0200 Subject: [PATCH] [jOOQ/jOOQ#9483] Support materialized views in Diff --- .../java/org/jooq/MigrationConfiguration.java | 34 +++++++++++++++++++ jOOQ/src/main/java/org/jooq/impl/Diff.java | 31 +++++++++++------ .../main/java/org/jooq/impl/Interpreter.java | 26 +++++++++++--- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/MigrationConfiguration.java b/jOOQ/src/main/java/org/jooq/MigrationConfiguration.java index 2ade8581ec..62cfa888da 100644 --- a/jOOQ/src/main/java/org/jooq/MigrationConfiguration.java +++ b/jOOQ/src/main/java/org/jooq/MigrationConfiguration.java @@ -57,6 +57,7 @@ public final class MigrationConfiguration { private final boolean dropTableCascade; private final boolean alterTableDropCascade; private final boolean createOrReplaceView; + private final boolean createOrReplaceMaterializedView; private final boolean respectColumnOrder; /** @@ -70,6 +71,7 @@ public final class MigrationConfiguration { false, false, false, + false, false ); } @@ -81,6 +83,7 @@ public final class MigrationConfiguration { boolean dropTableCascade, boolean alterTableDropCascade, boolean createOrReplaceView, + boolean createOrReplaceMaterializedView, boolean respectColumnOrder ) { this.alterTableAddMultiple = alterTableAddMultiple; @@ -89,6 +92,7 @@ public final class MigrationConfiguration { this.dropTableCascade = dropTableCascade; this.alterTableDropCascade = alterTableDropCascade; this.createOrReplaceView = createOrReplaceView; + this.createOrReplaceMaterializedView = createOrReplaceMaterializedView; this.respectColumnOrder = respectColumnOrder; } @@ -112,6 +116,7 @@ public final class MigrationConfiguration { dropTableCascade, alterTableDropCascade, createOrReplaceView, + createOrReplaceMaterializedView, respectColumnOrder ); } @@ -136,6 +141,7 @@ public final class MigrationConfiguration { dropTableCascade, alterTableDropCascade, createOrReplaceView, + createOrReplaceMaterializedView, respectColumnOrder ); } @@ -160,6 +166,7 @@ public final class MigrationConfiguration { dropTableCascade, alterTableDropCascade, createOrReplaceView, + createOrReplaceMaterializedView, respectColumnOrder ); } @@ -184,6 +191,7 @@ public final class MigrationConfiguration { newDropTableCascade, alterTableDropCascade, createOrReplaceView, + createOrReplaceMaterializedView, respectColumnOrder ); } @@ -208,6 +216,7 @@ public final class MigrationConfiguration { dropTableCascade, newAlterTableDropCascade, createOrReplaceView, + createOrReplaceMaterializedView, respectColumnOrder ); } @@ -230,6 +239,30 @@ public final class MigrationConfiguration { dropTableCascade, alterTableDropCascade, newCreateOrReplaceView, + createOrReplaceMaterializedView, + respectColumnOrder + ); + } + + /** + * Whether the materialized views should be (create-or-)replaced or dropped and re-created. + */ + public final boolean createOrReplaceMaterializedView() { + return createOrReplaceMaterializedView; + } + + /** + * Whether the materialized views should be (create-or-)replaced or dropped and re-created. + */ + public final MigrationConfiguration createOrReplaceMaterializedView(boolean newCreateOrReplaceMaterializedView) { + return new MigrationConfiguration( + alterTableAddMultiple, + alterTableDropMultiple, + dropSchemaCascade, + dropTableCascade, + alterTableDropCascade, + createOrReplaceView, + newCreateOrReplaceMaterializedView, respectColumnOrder ); } @@ -252,6 +285,7 @@ public final class MigrationConfiguration { dropTableCascade, alterTableDropCascade, createOrReplaceView, + createOrReplaceMaterializedView, newRespectColumnOrder ); } diff --git a/jOOQ/src/main/java/org/jooq/impl/Diff.java b/jOOQ/src/main/java/org/jooq/impl/Diff.java index a151461cd1..de7e48a24d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Diff.java +++ b/jOOQ/src/main/java/org/jooq/impl/Diff.java @@ -44,6 +44,8 @@ import static org.jooq.SQLDialect.IGNITE; import static org.jooq.SQLDialect.MARIADB; // ... import static org.jooq.SQLDialect.MYSQL; +import static org.jooq.TableOptions.TableType.MATERIALIZED_VIEW; +import static org.jooq.TableOptions.TableType.VIEW; import static org.jooq.impl.Comparators.CHECK_COMP; import static org.jooq.impl.Comparators.FOREIGN_KEY_COMP; import static org.jooq.impl.Comparators.INDEX_COMP; @@ -114,7 +116,10 @@ final class Diff { Diff(Configuration configuration, MigrationConfiguration migrateConf, Meta meta1, Meta meta2) { this.migrateConf = migrateConf; - this.exportConf = new DDLExportConfiguration().createOrReplaceView(migrateConf.createOrReplaceView()); + this.exportConf = new DDLExportConfiguration() + .createOrReplaceView(migrateConf.createOrReplaceView()) + .createOrReplaceMaterializedView(migrateConf.createOrReplaceMaterializedView()); + this.ctx = configuration.dsl(); this.meta1 = meta1; this.meta2 = meta2; @@ -255,8 +260,10 @@ final class Diff { if (r.droppedFks.add(fk) && !migrateConf.dropTableCascade()) r.queries.add(ctx.alterTable(fk.getTable()).dropForeignKey(fk.constraint())); - if (t.getTableType().isView()) + if (t.getTableType() == VIEW) r.queries.add(ctx.dropView(t)); + else if (t.getTableType() == MATERIALIZED_VIEW) + r.queries.add(ctx.dropMaterializedView(t)); else if (t.getTableType() == TableType.TEMPORARY) r.queries.add(ctx.dropTemporaryTable(t)); else @@ -269,19 +276,21 @@ final class Diff { private final Merge> MERGE_TABLE = new Merge>() { @Override public void merge(DiffResult r, Table t1, Table t2) { - boolean v1 = t1.getTableType().isView(); - boolean v2 = t2.getTableType().isView(); + boolean m1 = t1.getTableType() == MATERIALIZED_VIEW; + boolean m2 = t2.getTableType() == MATERIALIZED_VIEW; + boolean v1 = t1.getTableType() == VIEW; + boolean v2 = t2.getTableType() == VIEW; - if (v1 && v2) { + if (v1 && v2 || m1 && m2) { if (!Arrays.equals(t1.fields(), t2.fields()) || t2.getOptions().select() != null && !t2.getOptions().select().equals(t1.getOptions().select()) || t2.getOptions().source() != null && !t2.getOptions().source().equals(t1.getOptions().source())) { - replaceView(r, t1, t2); + replaceView(r, t1, t2, true); return; } } - else if (v1 != v2) { - replaceView(r, t1, t2); + else if (v1 != v2 || m1 != m2) { + replaceView(r, t1, t2, false); return; } else { @@ -306,8 +315,10 @@ final class Diff { r.queries.add(ctx.commentOnTable(t2).is(c2)); } - private void replaceView(DiffResult r, Table v1, Table v2) { - if (!migrateConf.createOrReplaceView()) + private void replaceView(DiffResult r, Table v1, Table v2, boolean canReplace) { + if (!canReplace + || v2.getTableType() == VIEW && !migrateConf.createOrReplaceView() + || v2.getTableType() == MATERIALIZED_VIEW && !migrateConf.createOrReplaceMaterializedView()) dropTable().drop(r, v1); createTable().create(r, v2); diff --git a/jOOQ/src/main/java/org/jooq/impl/Interpreter.java b/jOOQ/src/main/java/org/jooq/impl/Interpreter.java index 54e7d3abf5..185d1f326b 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Interpreter.java +++ b/jOOQ/src/main/java/org/jooq/impl/Interpreter.java @@ -806,8 +806,10 @@ final class Interpreter { MutableTable existing = schema.table(table); if (existing != null) { - if (!existing.options.type().isView()) + if (existing.options.type() != VIEW && !query.$materialized()) throw objectNotView(table); + else if (existing.options.type() != MATERIALIZED_VIEW && query.$materialized()) + throw objectNotMaterializedView(table); else if (query.$orReplace()) drop(schema.tables, existing, RESTRICT); else if (!query.$ifNotExists()) @@ -834,7 +836,10 @@ final class Interpreter { MutableTable existing = schema.table(table); if (existing == null) { if (!query.$ifExists()) - throw viewNotExists(table); + if (query.$materialized()) + throw materializedViewNotExists(table); + else + throw viewNotExists(table); return; } @@ -858,7 +863,10 @@ final class Interpreter { MutableTable existing = schema.table(table); if (existing == null) { if (!query.$ifExists()) - throw viewNotExists(table); + if (query.$materialized()) + throw materializedViewNotExists(table); + else + throw viewNotExists(table); return; } @@ -1197,10 +1205,18 @@ final class Interpreter { return new DataDefinitionException("View does not exist: " + view.getQualifiedName()); } + private static final DataDefinitionException materializedViewNotExists(Table view) { + return new DataDefinitionException("Materialized view does not exist: " + view.getQualifiedName()); + } + private static final DataDefinitionException viewAlreadyExists(Table view) { return new DataDefinitionException("View already exists: " + view.getQualifiedName()); } + private static final DataDefinitionException materializedViewAlreadyExists(Table view) { + return new DataDefinitionException("Materialized view already exists: " + view.getQualifiedName()); + } + private static final DataDefinitionException columnAlreadyExists(Name name) { return new DataDefinitionException("Column already exists: " + name); } @@ -1363,8 +1379,10 @@ final class Interpreter { } private static final DataDefinitionException alreadyExists(Table t, MutableTable mt) { - if (mt.options.type().isView()) + if (mt.options.type() == VIEW) return viewAlreadyExists(t); + else if (mt.options.type() == MATERIALIZED_VIEW) + return materializedViewAlreadyExists(t); else return alreadyExists(t); }