diff --git a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java index 517fe77ff757..da57494bb763 100644 --- a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java +++ b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java @@ -2796,6 +2796,12 @@ public Optional getMaterializedView(Connect return catalog.getMaterializedView(session, viewName); } + @Override + public boolean isMaterializedView(ConnectorSession session, SchemaTableName viewName) + { + return catalog.isMaterializedView(session, viewName); + } + @Override public void renameMaterializedView(ConnectorSession session, SchemaTableName source, SchemaTableName target) { diff --git a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/TrinoCatalog.java b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/TrinoCatalog.java index afd25eab19a2..9f00ebd855b6 100644 --- a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/TrinoCatalog.java +++ b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/TrinoCatalog.java @@ -159,6 +159,8 @@ void createMaterializedView( Optional getMaterializedView(ConnectorSession session, SchemaTableName viewName); + boolean isMaterializedView(ConnectorSession session, SchemaTableName viewName); + void renameMaterializedView(ConnectorSession session, SchemaTableName source, SchemaTableName target); void updateColumnComment(ConnectorSession session, SchemaTableName schemaTableName, ColumnIdentity columnIdentity, Optional comment); diff --git a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/glue/TrinoGlueCatalog.java b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/glue/TrinoGlueCatalog.java index 5a1a03a13d78..ddd0ceaf5633 100644 --- a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/glue/TrinoGlueCatalog.java +++ b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/glue/TrinoGlueCatalog.java @@ -1246,6 +1246,28 @@ protected Optional doGetMaterializedView(Co return createMaterializedViewDefinition(session, viewName, table); } + @Override + public boolean isMaterializedView(ConnectorSession session, SchemaTableName viewName) + { + ConnectorMaterializedViewDefinition materializedViewDefinition = materializedViewCache.get(viewName); + if (materializedViewDefinition != null) { + return true; + } + + if (tableMetadataCache.containsKey(viewName) || viewCache.containsKey(viewName)) { + // Entries in these caches are not materialized views. + return false; + } + + Optional maybeTable = getTableAndCacheMetadata(session, viewName); + if (maybeTable.isEmpty()) { + return false; + } + + com.amazonaws.services.glue.model.Table table = maybeTable.get(); + return isTrinoMaterializedView(getTableType(table), getTableParameters(table)); + } + private Optional createMaterializedViewDefinition( ConnectorSession session, SchemaTableName viewName, diff --git a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/hms/TrinoHiveCatalog.java b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/hms/TrinoHiveCatalog.java index c6234c1cf018..6f9a26be7927 100644 --- a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/hms/TrinoHiveCatalog.java +++ b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/hms/TrinoHiveCatalog.java @@ -663,6 +663,18 @@ protected Optional doGetMaterializedView(Co storageTableName)); } + @Override + public boolean isMaterializedView(ConnectorSession session, SchemaTableName viewName) + { + Optional tableOptional = metastore.getTable(viewName.getSchemaName(), viewName.getTableName()); + if (tableOptional.isEmpty()) { + return false; + } + + io.trino.plugin.hive.metastore.Table table = tableOptional.get(); + return isTrinoMaterializedView(table.getTableType(), table.getParameters()); + } + @Override public void renameMaterializedView(ConnectorSession session, SchemaTableName source, SchemaTableName target) { diff --git a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/jdbc/TrinoJdbcCatalog.java b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/jdbc/TrinoJdbcCatalog.java index 920be5a5dede..d723fd7a710e 100644 --- a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/jdbc/TrinoJdbcCatalog.java +++ b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/jdbc/TrinoJdbcCatalog.java @@ -412,6 +412,12 @@ public Optional getMaterializedView(Connect return Optional.empty(); } + @Override + public boolean isMaterializedView(ConnectorSession session, SchemaTableName viewName) + { + return false; + } + @Override public void renameMaterializedView(ConnectorSession session, SchemaTableName source, SchemaTableName target) { diff --git a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/nessie/TrinoNessieCatalog.java b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/nessie/TrinoNessieCatalog.java index 7f4a8872a18b..294ceea68985 100644 --- a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/nessie/TrinoNessieCatalog.java +++ b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/nessie/TrinoNessieCatalog.java @@ -375,6 +375,12 @@ public Optional getMaterializedView(Connect return Optional.empty(); } + @Override + public boolean isMaterializedView(ConnectorSession session, SchemaTableName viewName) + { + return false; + } + @Override protected Optional doGetMaterializedView(ConnectorSession session, SchemaTableName schemaViewName) { diff --git a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/rest/TrinoRestCatalog.java b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/rest/TrinoRestCatalog.java index 57f41315f343..27a4d714f26a 100644 --- a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/rest/TrinoRestCatalog.java +++ b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/catalog/rest/TrinoRestCatalog.java @@ -415,6 +415,12 @@ public Optional getMaterializedView(Connect return Optional.empty(); } + @Override + public boolean isMaterializedView(ConnectorSession session, SchemaTableName viewName) + { + return false; + } + @Override public void renameMaterializedView(ConnectorSession session, SchemaTableName source, SchemaTableName target) { diff --git a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergConnectorSmokeTest.java b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergConnectorSmokeTest.java index 257d3bba5ce1..ecdcdd3c8e0f 100644 --- a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergConnectorSmokeTest.java +++ b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergConnectorSmokeTest.java @@ -519,6 +519,24 @@ public void testDropTableWithMissingMetadataFile() assertFalse(fileSystem.listFiles(tableLocation).hasNext(), "Table location should not exist"); } + @Test + public void testDropMaterializedViewWithMissingMetadataFile() + throws Exception + { + String viewName = "test_drop_mv_with_missing_metadata_file_" + randomNameSuffix(); + assertUpdate("CREATE MATERIALIZED VIEW " + viewName + " AS SELECT 1 x, 'INDIA' y"); + + Location metadataLocation = Location.of(getMetadataLocation(viewName)); + + // Delete current metadata file + fileSystem.deleteFile(metadataLocation); + assertFalse(fileSystem.newInputFile(metadataLocation).exists(), "Current metadata file should not exist"); + + // try to drop mv + assertUpdate("DROP MATERIALIZED VIEW " + viewName); + assertFalse(getQueryRunner().tableExists(getSession(), viewName)); + } + @Test public void testDropTableWithMissingSnapshotFile() throws Exception diff --git a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergMinioConnectorSmokeTest.java b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergMinioConnectorSmokeTest.java index d60cbc15378f..3801e9eb5073 100644 --- a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergMinioConnectorSmokeTest.java +++ b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergMinioConnectorSmokeTest.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -232,13 +233,17 @@ protected void dropTableFromMetastore(String tableName) @Override protected String getMetadataLocation(String tableName) { - HiveMetastore metastore = new BridgingHiveMetastore( + Map parameters = new BridgingHiveMetastore( testingThriftHiveMetastoreBuilder() .metastoreClient(hiveMinioDataLake.getHiveHadoop().getHiveMetastoreEndpoint()) - .build()); - return metastore + .build()) .getTable(schemaName, tableName).orElseThrow() - .getParameters().get("metadata_location"); + .getParameters(); + return Optional.ofNullable(parameters.get("storage_table")) + // this is a materialized view: + .map(this::getMetadataLocation) + // this is a plain table: + .orElseGet(() -> parameters.get("metadata_location")); } @Override diff --git a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/TestIcebergConnectorSmokeTest.java b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/TestIcebergConnectorSmokeTest.java index 99a4c1d96595..b1a197ca65ae 100644 --- a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/TestIcebergConnectorSmokeTest.java +++ b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/TestIcebergConnectorSmokeTest.java @@ -24,6 +24,8 @@ import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; import static com.google.common.io.MoreFiles.deleteRecursively; import static com.google.common.io.RecursiveDeleteOption.ALLOW_INSECURE; @@ -80,9 +82,14 @@ protected void dropTableFromMetastore(String tableName) @Override protected String getMetadataLocation(String tableName) { - return metastore + Map parameters = metastore .getTable(getSession().getSchema().orElseThrow(), tableName).orElseThrow() - .getParameters().get("metadata_location"); + .getParameters(); + return Optional.ofNullable(parameters.get("storage_table")) + // this is a materialized view: + .map(this::getMetadataLocation) + // this is a plain table: + .orElseGet(() -> parameters.get("metadata_location")); } @Override diff --git a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/TestIcebergMetastoreAccessOperations.java b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/TestIcebergMetastoreAccessOperations.java index 6cdee6b0bfa4..eca6731c61f0 100644 --- a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/TestIcebergMetastoreAccessOperations.java +++ b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/TestIcebergMetastoreAccessOperations.java @@ -219,7 +219,7 @@ public void testDropMaterializedView() assertMetastoreInvocations("DROP MATERIALIZED VIEW test_drop_mview_view", ImmutableMultiset.builder() - .addCopies(GET_TABLE, 2) + .add(GET_TABLE) .addCopies(DROP_TABLE, 2) .build()); } diff --git a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/jdbc/TestIcebergJdbcCatalogConnectorSmokeTest.java b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/jdbc/TestIcebergJdbcCatalogConnectorSmokeTest.java index 5a9aef435698..6efb3c334953 100644 --- a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/jdbc/TestIcebergJdbcCatalogConnectorSmokeTest.java +++ b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/jdbc/TestIcebergJdbcCatalogConnectorSmokeTest.java @@ -182,4 +182,11 @@ protected boolean isFileSorted(Location path, String sortColumnName) } return checkOrcFileSorting(fileSystem, path, sortColumnName); } + + @Override + public void testDropMaterializedViewWithMissingMetadataFile() + { + assertThatThrownBy(super::testDropMaterializedViewWithMissingMetadataFile) + .hasMessageMatching("createMaterializedView is not supported for Iceberg JDBC catalogs"); + } } diff --git a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/nessie/TestIcebergNessieCatalogConnectorSmokeTest.java b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/nessie/TestIcebergNessieCatalogConnectorSmokeTest.java index 33d74c92741c..805501b06373 100644 --- a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/nessie/TestIcebergNessieCatalogConnectorSmokeTest.java +++ b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/nessie/TestIcebergNessieCatalogConnectorSmokeTest.java @@ -224,6 +224,13 @@ public void testDropTableWithMissingMetadataFile() .hasMessageMatching("metadata location for register_table is not supported"); } + @Override + public void testDropMaterializedViewWithMissingMetadataFile() + { + assertThatThrownBy(super::testDropMaterializedViewWithMissingMetadataFile) + .hasMessageMatching("createMaterializedView is not supported for Iceberg Nessie catalogs"); + } + @Override public void testDropTableWithMissingSnapshotFile() { diff --git a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/rest/TestIcebergTrinoRestCatalogConnectorSmokeTest.java b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/rest/TestIcebergTrinoRestCatalogConnectorSmokeTest.java index 29ff135aea4c..c45d7aca01ec 100644 --- a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/rest/TestIcebergTrinoRestCatalogConnectorSmokeTest.java +++ b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/rest/TestIcebergTrinoRestCatalogConnectorSmokeTest.java @@ -234,6 +234,13 @@ public void testDropTableWithMissingMetadataFile() .hasMessageMatching("Failed to load table: (.*)"); } + @Override + public void testDropMaterializedViewWithMissingMetadataFile() + { + assertThatThrownBy(super::testDropMaterializedViewWithMissingMetadataFile) + .hasMessageMatching("createMaterializedView is not supported for Iceberg REST catalog"); + } + @Override public void testDropTableWithMissingSnapshotFile() {