diff --git a/core/trino-main/src/main/java/io/trino/execution/DropTableTask.java b/core/trino-main/src/main/java/io/trino/execution/DropTableTask.java index 6cac86863f40..f66474975100 100644 --- a/core/trino-main/src/main/java/io/trino/execution/DropTableTask.java +++ b/core/trino-main/src/main/java/io/trino/execution/DropTableTask.java @@ -18,8 +18,8 @@ import io.trino.execution.warnings.WarningCollector; import io.trino.metadata.Metadata; import io.trino.metadata.QualifiedObjectName; -import io.trino.metadata.RedirectionAwareTableHandle; import io.trino.security.AccessControl; +import io.trino.spi.connector.TableNotFoundException; import io.trino.sql.tree.DropTable; import io.trino.sql.tree.Expression; @@ -76,17 +76,17 @@ public ListenableFuture execute( "Table '%s' does not exist, but a view with that name exists. Did you mean DROP VIEW %s?", originalTableName, originalTableName); } - RedirectionAwareTableHandle redirectionAwareTableHandle = metadata.getRedirectionAwareTableHandle(session, originalTableName); - if (redirectionAwareTableHandle.getTableHandle().isEmpty()) { + QualifiedObjectName targetTable = metadata.getRedirectedTableName(session, originalTableName); + + try { + accessControl.checkCanDropTable(session.toSecurityContext(), targetTable); + metadata.dropTable(session, targetTable); + } + catch (TableNotFoundException e) { if (!statement.isExists()) { throw semanticException(TABLE_NOT_FOUND, statement, "Table '%s' does not exist", originalTableName); } - return immediateVoidFuture(); } - QualifiedObjectName tableName = redirectionAwareTableHandle.getRedirectedTableName().orElse(originalTableName); - accessControl.checkCanDropTable(session.toSecurityContext(), tableName); - - metadata.dropTable(session, redirectionAwareTableHandle.getTableHandle().get(), tableName.asCatalogSchemaTableName()); return immediateVoidFuture(); } diff --git a/core/trino-main/src/main/java/io/trino/metadata/Metadata.java b/core/trino-main/src/main/java/io/trino/metadata/Metadata.java index 8c6838fd1449..ba1bb0a72acf 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/Metadata.java +++ b/core/trino-main/src/main/java/io/trino/metadata/Metadata.java @@ -264,9 +264,18 @@ Optional getTableHandleForExecute( * Drops the specified table * * @throws RuntimeException if the table cannot be dropped or table handle is no longer valid + * + * @deprecated use {@link #dropTable(Session, QualifiedObjectName)} */ void dropTable(Session session, TableHandle tableHandle, CatalogSchemaTableName tableName); + /** + * Drops the specified table + * + * @throws RuntimeException if the table cannot be dropped + */ + void dropTable(Session session, QualifiedObjectName tableName); + /** * Truncates the specified table */ @@ -708,6 +717,11 @@ default boolean isMaterializedView(Session session, QualifiedObjectName viewName */ RedirectionAwareTableHandle getRedirectionAwareTableHandle(Session session, QualifiedObjectName tableName, Optional startVersion, Optional endVersion); + /** + * Get the table name after performing redirection. + */ + QualifiedObjectName getRedirectedTableName(Session session, QualifiedObjectName tableName); + /** * Returns true if the connector reports number of written bytes for an existing table. Otherwise, it returns false. */ diff --git a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java index dc1436a04e3b..d9be73dd783b 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java +++ b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java @@ -799,6 +799,20 @@ public void dropTable(Session session, TableHandle tableHandle, CatalogSchemaTab } } + @Override + public void dropTable(Session session, QualifiedObjectName tableName) + { + CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, tableName.getCatalogName()); + ConnectorSession connectorSession = session.toConnectorSession(catalogMetadata.getCatalogHandle()); + ConnectorMetadata metadata = catalogMetadata.getMetadata(session); + + metadata.dropTable(connectorSession, tableName.asSchemaTableName()); + + if (catalogMetadata.getSecurityManagement() == SYSTEM) { + systemSecurityMetadata.tableDropped(session, tableName.asCatalogSchemaTableName()); + } + } + @Override public void truncateTable(Session session, TableHandle tableHandle) { @@ -1486,7 +1500,8 @@ public Optional applyTableScanRedirect(Sessi return metadata.applyTableScanRedirect(connectorSession, tableHandle.getConnectorHandle()); } - private QualifiedObjectName getRedirectedTableName(Session session, QualifiedObjectName originalTableName) + @Override + public QualifiedObjectName getRedirectedTableName(Session session, QualifiedObjectName originalTableName) { requireNonNull(session, "session is null"); requireNonNull(originalTableName, "originalTableName is null"); diff --git a/core/trino-main/src/main/java/io/trino/testing/TestingMetadata.java b/core/trino-main/src/main/java/io/trino/testing/TestingMetadata.java index 27f174bc7da5..0b3276c4ea22 100644 --- a/core/trino-main/src/main/java/io/trino/testing/TestingMetadata.java +++ b/core/trino-main/src/main/java/io/trino/testing/TestingMetadata.java @@ -186,7 +186,13 @@ public void createTable(ConnectorSession session, ConnectorTableMetadata tableMe @Override public void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle) { - tables.remove(getTableName(tableHandle)); + dropTable(session, getTableName(tableHandle)); + } + + @Override + public void dropTable(ConnectorSession session, SchemaTableName tableName) + { + tables.remove(tableName); } @Override diff --git a/core/trino-main/src/test/java/io/trino/connector/MockConnector.java b/core/trino-main/src/test/java/io/trino/connector/MockConnector.java index 7fbe7b4fa551..0a3bddf59217 100644 --- a/core/trino-main/src/test/java/io/trino/connector/MockConnector.java +++ b/core/trino-main/src/test/java/io/trino/connector/MockConnector.java @@ -577,6 +577,9 @@ public void createTable(ConnectorSession session, ConnectorTableMetadata tableMe @Override public void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle) {} + @Override + public void dropTable(ConnectorSession session, SchemaTableName tableName) {} + @Override public void renameTable(ConnectorSession session, ConnectorTableHandle tableHandle, SchemaTableName newTableName) {} diff --git a/core/trino-main/src/test/java/io/trino/execution/BaseDataDefinitionTaskTest.java b/core/trino-main/src/test/java/io/trino/execution/BaseDataDefinitionTaskTest.java index 66d5813a5da6..1d769bc83bfe 100644 --- a/core/trino-main/src/test/java/io/trino/execution/BaseDataDefinitionTaskTest.java +++ b/core/trino-main/src/test/java/io/trino/execution/BaseDataDefinitionTaskTest.java @@ -26,6 +26,7 @@ import io.trino.metadata.MaterializedViewPropertyManager; import io.trino.metadata.MetadataManager; import io.trino.metadata.QualifiedObjectName; +import io.trino.metadata.QualifiedTablePrefix; import io.trino.metadata.ResolvedFunction; import io.trino.metadata.TableHandle; import io.trino.metadata.TableMetadata; @@ -43,6 +44,7 @@ import io.trino.spi.connector.ConnectorTableMetadata; import io.trino.spi.connector.MaterializedViewNotFoundException; import io.trino.spi.connector.SchemaTableName; +import io.trino.spi.connector.TableNotFoundException; import io.trino.spi.connector.TestingColumnHandle; import io.trino.spi.function.OperatorType; import io.trino.spi.resourcegroups.ResourceGroupId; @@ -318,6 +320,15 @@ public void dropTable(Session session, TableHandle tableHandle, CatalogSchemaTab tables.remove(tableName.getSchemaTableName()); } + @Override + public void dropTable(Session session, QualifiedObjectName tableName) + { + SchemaTableName schemaTableName = tableName.asSchemaTableName(); + if (tables.remove(schemaTableName) == null) { + throw new TableNotFoundException(schemaTableName); + } + } + @Override public void renameTable(Session session, TableHandle tableHandle, CatalogSchemaTableName currentTableName, QualifiedObjectName newTableName) { @@ -380,6 +391,18 @@ private SchemaTableName getTableName(TableHandle tableHandle) return ((TestingTableHandle) tableHandle.getConnectorHandle()).getTableName(); } + @Override + public List listTables(Session session, QualifiedTablePrefix prefix) + { + return tables.keySet().stream().map(table -> QualifiedObjectName.convertFromSchemaTableName(TEST_CATALOG_NAME).apply(table)).toList(); + } + + @Override + public QualifiedObjectName getRedirectedTableName(Session session, QualifiedObjectName tableName) + { + return tableName; + } + @Override public Map getColumnHandles(Session session, TableHandle tableHandle) { diff --git a/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java b/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java index 29a9a513d2c3..88b4effc8ef2 100644 --- a/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java +++ b/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java @@ -336,6 +336,12 @@ public void dropTable(Session session, TableHandle tableHandle, CatalogSchemaTab throw new UnsupportedOperationException(); } + @Override + public void dropTable(Session session, QualifiedObjectName tableName) + { + throw new UnsupportedOperationException(); + } + @Override public void truncateTable(Session session, TableHandle tableHandle) { @@ -878,6 +884,12 @@ public RedirectionAwareTableHandle getRedirectionAwareTableHandle(Session sessio throw new UnsupportedOperationException(); } + @Override + public QualifiedObjectName getRedirectedTableName(Session session, QualifiedObjectName tableName) + { + throw new UnsupportedOperationException(); + } + @Override public boolean supportsReportingWrittenBytes(Session session, TableHandle tableHandle) { diff --git a/core/trino-main/src/test/java/io/trino/metadata/CountingAccessMetadata.java b/core/trino-main/src/test/java/io/trino/metadata/CountingAccessMetadata.java index d296d4034bef..432129bd6826 100644 --- a/core/trino-main/src/test/java/io/trino/metadata/CountingAccessMetadata.java +++ b/core/trino-main/src/test/java/io/trino/metadata/CountingAccessMetadata.java @@ -340,6 +340,12 @@ public void dropTable(Session session, TableHandle tableHandle, CatalogSchemaTab delegate.dropTable(session, tableHandle, tableName); } + @Override + public void dropTable(Session session, QualifiedObjectName tableName) + { + delegate.dropTable(session, tableName); + } + @Override public void truncateTable(Session session, TableHandle tableHandle) { @@ -857,6 +863,12 @@ public RedirectionAwareTableHandle getRedirectionAwareTableHandle(Session sessio return delegate.getRedirectionAwareTableHandle(session, tableName, startVersion, endVersion); } + @Override + public QualifiedObjectName getRedirectedTableName(Session session, QualifiedObjectName tableName) + { + return delegate.getRedirectedTableName(session, tableName); + } + @Override public boolean supportsReportingWrittenBytes(Session session, TableHandle tableHandle) { diff --git a/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorMetadata.java b/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorMetadata.java index d1612a635b5d..1933d45772fe 100644 --- a/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorMetadata.java +++ b/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorMetadata.java @@ -357,11 +357,24 @@ default void createTable(ConnectorSession session, ConnectorTableMetadata tableM throw new TrinoException(NOT_SUPPORTED, "This connector does not support creating tables"); } + /** + * Drops the specified table + * + * @throws RuntimeException if the table cannot be dropped + */ + default void dropTable(ConnectorSession session, SchemaTableName schemaTableName) + { + dropTable(session, getTableHandle(session, schemaTableName)); + } + /** * Drops the specified table * * @throws RuntimeException if the table cannot be dropped or table handle is no longer valid + * + * @deprecated use {@link #dropTable(ConnectorSession, SchemaTableName)} */ + @Deprecated default void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle) { throw new TrinoException(NOT_SUPPORTED, "This connector does not support dropping tables"); diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/classloader/ClassLoaderSafeConnectorMetadata.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/classloader/ClassLoaderSafeConnectorMetadata.java index 812e9f9027ae..e1e9a75b5dfc 100644 --- a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/classloader/ClassLoaderSafeConnectorMetadata.java +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/classloader/ClassLoaderSafeConnectorMetadata.java @@ -393,6 +393,14 @@ public void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle } } + @Override + public void dropTable(ConnectorSession session, SchemaTableName tableName) + { + try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(classLoader)) { + delegate.dropTable(session, tableName); + } + } + @Override public void truncateTable(ConnectorSession session, ConnectorTableHandle tableHandle) { diff --git a/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeMetadata.java b/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeMetadata.java index 4cf9e88bdad8..ab0a4d5a6373 100644 --- a/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeMetadata.java +++ b/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeMetadata.java @@ -172,6 +172,7 @@ import static io.trino.plugin.deltalake.DeltaLakeColumnType.SYNTHESIZED; import static io.trino.plugin.deltalake.DeltaLakeErrorCode.DELTA_LAKE_BAD_WRITE; import static io.trino.plugin.deltalake.DeltaLakeErrorCode.DELTA_LAKE_INVALID_SCHEMA; +import static io.trino.plugin.deltalake.DeltaLakeErrorCode.DELTA_LAKE_INVALID_TABLE; import static io.trino.plugin.deltalake.DeltaLakeSessionProperties.getHiveCatalogName; import static io.trino.plugin.deltalake.DeltaLakeSessionProperties.isCollectExtendedStatisticsColumnStatisticsOnWrite; import static io.trino.plugin.deltalake.DeltaLakeSessionProperties.isExtendedStatisticsEnabled; @@ -415,8 +416,10 @@ public DeltaLakeTableHandle getTableHandle(ConnectorSession session, SchemaTable } TableSnapshot tableSnapshot = metastore.getSnapshot(dataTableName, session); - Optional metadata = metastore.getMetadata(tableSnapshot, session); - metadata.ifPresent(metadataEntry -> verifySupportedColumnMapping(getColumnMappingMode(metadataEntry))); + MetadataEntry metadata = metastore.getMetadata(tableSnapshot, session) + .orElseThrow(() -> new TrinoException(DELTA_LAKE_INVALID_TABLE, "Metadata not found in transaction log for table " + tableName)); + + verifySupportedColumnMapping(getColumnMappingMode(metadata)); return new DeltaLakeTableHandle( dataTableName.getSchemaName(), dataTableName.getTableName(), @@ -1766,12 +1769,16 @@ public Optional getInfo(ConnectorTableHandle table) @Override public void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle) { - DeltaLakeTableHandle handle = (DeltaLakeTableHandle) tableHandle; + dropTable(session, ((DeltaLakeTableHandle) tableHandle).getSchemaTableName()); + } - Table table = metastore.getTable(handle.getSchemaName(), handle.getTableName()) - .orElseThrow(() -> new TableNotFoundException(handle.getSchemaTableName())); + @Override + public void dropTable(ConnectorSession session, SchemaTableName schemaTableName) + { + Table table = metastore.getTable(schemaTableName.getSchemaName(), schemaTableName.getTableName()) + .orElseThrow(() -> new TableNotFoundException(schemaTableName)); - metastore.dropTable(session, handle.getSchemaName(), handle.getTableName(), table.getTableType().equals(MANAGED_TABLE.toString())); + metastore.dropTable(session, schemaTableName.getSchemaName(), schemaTableName.getTableName(), table.getTableType().equals(MANAGED_TABLE.toString())); } @Override @@ -2030,7 +2037,7 @@ public Optional> applyFilter(C tableName.getSchemaName(), tableName.getTableName(), tableHandle.getLocation(), - Optional.of(tableHandle.getMetadataEntry()), + tableHandle.getMetadataEntry(), // Do not simplify the enforced constraint, the connector is guaranteeing the constraint will be applied as is. // The unenforced constraint will still be checked by the engine. tableHandle.getEnforcedPartitionConstraint() @@ -2157,7 +2164,7 @@ public ConnectorAnalyzeMetadata getStatisticsCollectionMetadata(ConnectorSession handle.getSchemaTableName().getSchemaName(), handle.getSchemaTableName().getTableName(), handle.getLocation(), - Optional.of(metadata), + metadata, TupleDomain.all(), TupleDomain.all(), Optional.empty(), diff --git a/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeTableHandle.java b/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeTableHandle.java index 82ec0f446af4..55e3abccdb3d 100644 --- a/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeTableHandle.java +++ b/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeTableHandle.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.airlift.units.DataSize; import io.trino.plugin.deltalake.transactionlog.MetadataEntry; -import io.trino.spi.TrinoException; import io.trino.spi.connector.ColumnHandle; import io.trino.spi.connector.ConnectorTableHandle; import io.trino.spi.connector.SchemaTableName; @@ -30,7 +29,6 @@ import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; -import static io.trino.plugin.deltalake.DeltaLakeErrorCode.DELTA_LAKE_INVALID_SCHEMA; import static io.trino.plugin.deltalake.DeltaLakeTableHandle.WriteType.UPDATE; import static java.util.Objects.requireNonNull; @@ -47,7 +45,7 @@ public enum WriteType private final String schemaName; private final String tableName; private final String location; - private final Optional metadataEntry; + private final MetadataEntry metadataEntry; private final TupleDomain enforcedPartitionConstraint; private final TupleDomain nonPartitionConstraint; private final Optional writeType; @@ -72,7 +70,7 @@ public DeltaLakeTableHandle( @JsonProperty("schemaName") String schemaName, @JsonProperty("tableName") String tableName, @JsonProperty("location") String location, - @JsonProperty("metadataEntry") Optional metadataEntry, + @JsonProperty("metadataEntry") MetadataEntry metadataEntry, @JsonProperty("enforcedPartitionConstraint") TupleDomain enforcedPartitionConstraint, @JsonProperty("nonPartitionConstraint") TupleDomain nonPartitionConstraint, @JsonProperty("writeType") Optional writeType, @@ -105,7 +103,7 @@ public DeltaLakeTableHandle( String schemaName, String tableName, String location, - Optional metadataEntry, + MetadataEntry metadataEntry, TupleDomain enforcedPartitionConstraint, TupleDomain nonPartitionConstraint, Optional writeType, @@ -143,7 +141,7 @@ public DeltaLakeTableHandle withProjectedColumns(Set projectedColu getSchemaName(), getTableName(), getLocation(), - Optional.of(getMetadataEntry()), + getMetadataEntry(), getEnforcedPartitionConstraint(), getNonPartitionConstraint(), getWriteType(), @@ -196,7 +194,7 @@ public String getLocation() @JsonProperty public MetadataEntry getMetadataEntry() { - return metadataEntry.orElseThrow(() -> new TrinoException(DELTA_LAKE_INVALID_SCHEMA, "Metadata not found in transaction log for " + tableName)); + return metadataEntry; } @JsonProperty diff --git a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeMetadata.java b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeMetadata.java index dc221fde2597..eee6d1cd5edb 100644 --- a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeMetadata.java +++ b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeMetadata.java @@ -313,32 +313,6 @@ public void testGetInsertLayoutTableUnpartitioned() .isNotPresent(); } - @Test - public void testGetInsertLayoutTableNotFound() - { - SchemaTableName schemaTableName = newMockSchemaTableName(); - - DeltaLakeTableHandle missingTableHandle = new DeltaLakeTableHandle( - schemaTableName.getSchemaName(), - schemaTableName.getTableName(), - getTableLocation(schemaTableName), - Optional.empty(), - TupleDomain.none(), - TupleDomain.none(), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty(), - Optional.empty(), - 0, - false); - - assertThatThrownBy(() -> deltaLakeMetadataFactory.create(SESSION.getIdentity()) - .getInsertLayout(SESSION, missingTableHandle)) - .isInstanceOf(TrinoException.class) - .hasMessage("Metadata not found in transaction log for " + schemaTableName.getTableName()); - } - @DataProvider public Object[][] testApplyProjectionProvider() { @@ -505,9 +479,9 @@ private static List createNewColumnAssignments(Map createMetadataEntry() + private static MetadataEntry createMetadataEntry() { - return Optional.of(new MetadataEntry( + return new MetadataEntry( "test_id", "test_name", "test_description", @@ -515,7 +489,7 @@ private static Optional createMetadataEntry() "test_schema", ImmutableList.of("test_partition_column"), ImmutableMap.of("test_configuration_key", "test_configuration_value"), - 1)); + 1); } private String getTableLocation(SchemaTableName schemaTableName) diff --git a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeSplitManager.java b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeSplitManager.java index 5fceb69352a2..80d79176615c 100644 --- a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeSplitManager.java +++ b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeSplitManager.java @@ -68,7 +68,7 @@ public class TestDeltaLakeSplitManager "schema", "table", "location", - Optional.of(metadataEntry), + metadataEntry, TupleDomain.all(), TupleDomain.all(), Optional.empty(), diff --git a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestTransactionLogAccess.java b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestTransactionLogAccess.java index 52ae8b3b20c3..b4b2a44a1702 100644 --- a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestTransactionLogAccess.java +++ b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestTransactionLogAccess.java @@ -133,11 +133,20 @@ private void setupTransactionLogAccess(String tableName, String tableLocation, D accessTrackingFileSystemFactory, new ParquetReaderConfig()); + String schemaName = "schema"; DeltaLakeTableHandle tableHandle = new DeltaLakeTableHandle( - "schema", + schemaName, tableName, "location", - Optional.empty(), // ignored + new MetadataEntry( + "id", + tableName, + "a table", + new MetadataEntry.Format("provider", ImmutableMap.of()), + schemaName, + ImmutableList.of(), + ImmutableMap.of(), + 0L), TupleDomain.none(), TupleDomain.none(), Optional.empty(), diff --git a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/metastore/TestDeltaLakeMetastoreStatistics.java b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/metastore/TestDeltaLakeMetastoreStatistics.java index 41887cbfc7c9..4c71580fb6f5 100644 --- a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/metastore/TestDeltaLakeMetastoreStatistics.java +++ b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/metastore/TestDeltaLakeMetastoreStatistics.java @@ -151,7 +151,7 @@ private DeltaLakeTableHandle registerTable(String tableName, String directoryNam "db_name", tableName, "location", - Optional.of(new MetadataEntry("id", "test", "description", null, "", ImmutableList.of(), ImmutableMap.of(), 0)), + new MetadataEntry("id", "test", "description", null, "", ImmutableList.of(), ImmutableMap.of(), 0), TupleDomain.all(), TupleDomain.all(), Optional.empty(), @@ -281,7 +281,7 @@ public void testStatisticsMultipleFiles() tableHandle.getSchemaName(), tableHandle.getTableName(), tableHandle.getLocation(), - Optional.of(tableHandle.getMetadataEntry()), + tableHandle.getMetadataEntry(), TupleDomain.all(), TupleDomain.withColumnDomains(ImmutableMap.of((DeltaLakeColumnHandle) COLUMN_HANDLE, Domain.singleValue(DOUBLE, 42.0))), tableHandle.getWriteType(), @@ -305,7 +305,7 @@ public void testStatisticsNoRecords() tableHandle.getSchemaName(), tableHandle.getTableName(), tableHandle.getLocation(), - Optional.of(tableHandle.getMetadataEntry()), + tableHandle.getMetadataEntry(), TupleDomain.none(), TupleDomain.all(), tableHandle.getWriteType(), @@ -319,7 +319,7 @@ public void testStatisticsNoRecords() tableHandle.getSchemaName(), tableHandle.getTableName(), tableHandle.getLocation(), - Optional.of(tableHandle.getMetadataEntry()), + tableHandle.getMetadataEntry(), TupleDomain.all(), TupleDomain.none(), tableHandle.getWriteType(), diff --git a/plugin/trino-geospatial/src/test/java/io/trino/plugin/geospatial/BenchmarkSpatialJoin.java b/plugin/trino-geospatial/src/test/java/io/trino/plugin/geospatial/BenchmarkSpatialJoin.java index 0e6a43fb8f66..d882faa59c21 100644 --- a/plugin/trino-geospatial/src/test/java/io/trino/plugin/geospatial/BenchmarkSpatialJoin.java +++ b/plugin/trino-geospatial/src/test/java/io/trino/plugin/geospatial/BenchmarkSpatialJoin.java @@ -16,7 +16,6 @@ import com.google.common.collect.ImmutableMap; import io.trino.metadata.Metadata; import io.trino.metadata.QualifiedObjectName; -import io.trino.metadata.TableHandle; import io.trino.plugin.memory.MemoryConnectorFactory; import io.trino.testing.LocalQueryRunner; import io.trino.testing.MaterializedResult; @@ -36,7 +35,6 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -47,7 +45,6 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.openjdk.jmh.annotations.Mode.AverageTime; import static org.openjdk.jmh.annotations.Scope.Thread; -import static org.testng.Assert.assertTrue; @SuppressWarnings("MethodMayBeStatic") @State(Thread) @@ -109,10 +106,7 @@ public void dropPointsTable() { queryRunner.inTransaction(queryRunner.getDefaultSession(), transactionSession -> { Metadata metadata = queryRunner.getMetadata(); - QualifiedObjectName tableName = QualifiedObjectName.valueOf("memory.default.points"); - Optional tableHandle = metadata.getTableHandle(transactionSession, tableName); - assertTrue(tableHandle.isPresent(), "Table memory.default.points does not exist"); - metadata.dropTable(transactionSession, tableHandle.get(), tableName.asCatalogSchemaTableName()); + metadata.dropTable(transactionSession, QualifiedObjectName.valueOf("memory.default.points")); return null; }); } diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveMetadata.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveMetadata.java index b39428bcd7d2..7d38259ad82a 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveMetadata.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveMetadata.java @@ -1462,11 +1462,16 @@ public void setColumnComment(ConnectorSession session, ConnectorTableHandle tabl @Override public void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle) { - HiveTableHandle handle = (HiveTableHandle) tableHandle; - if (metastore.getTable(handle.getSchemaName(), handle.getTableName()).isEmpty()) { - throw new TableNotFoundException(handle.getSchemaTableName()); + dropTable(session, ((HiveTableHandle) tableHandle).getSchemaTableName()); + } + + @Override + public void dropTable(ConnectorSession session, SchemaTableName schemaTableName) + { + if (metastore.getTable(schemaTableName.getSchemaName(), schemaTableName.getTableName()).isEmpty()) { + throw new TableNotFoundException(schemaTableName); } - metastore.dropTable(session, handle.getSchemaName(), handle.getTableName()); + metastore.dropTable(session, schemaTableName.getSchemaName(), schemaTableName.getTableName()); } @Override 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 b9a0e745238c..f12f36485f58 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 @@ -144,6 +144,7 @@ import org.apache.iceberg.types.Types.StringType; import org.apache.iceberg.types.Types.StructType; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.UncheckedIOException; import java.time.Instant; @@ -372,6 +373,15 @@ public IcebergTableHandle getTableHandle( catch (TableNotFoundException e) { return null; } + catch (RuntimeException e) { + if (e.getCause() != null) { + if (e.getCause() instanceof FileNotFoundException + || e.getCause().getMessage().contains("The specified key does not exist")) { + throw new TrinoException(ICEBERG_INVALID_METADATA, "Metadata not found in metadata location for table " + tableName, e); + } + } + throw e; + } Optional tableSnapshotId; Schema tableSchema; @@ -1491,7 +1501,13 @@ public Optional getInfo(ConnectorTableHandle tableHandle) @Override public void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle) { - catalog.dropTable(session, ((IcebergTableHandle) tableHandle).getSchemaTableName()); + dropTable(session, ((IcebergTableHandle) tableHandle).getSchemaTableName()); + } + + @Override + public void dropTable(ConnectorSession session, SchemaTableName schemaTableName) + { + catalog.dropTable(session, schemaTableName); } @Override 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 dee3ce1cdcba..7858e388c8fb 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 @@ -97,6 +97,7 @@ import static io.trino.plugin.hive.util.HiveUtil.isIcebergTable; import static io.trino.plugin.iceberg.IcebergErrorCode.ICEBERG_BAD_DATA; import static io.trino.plugin.iceberg.IcebergErrorCode.ICEBERG_CATALOG_ERROR; +import static io.trino.plugin.iceberg.IcebergErrorCode.ICEBERG_INVALID_METADATA; import static io.trino.plugin.iceberg.IcebergMaterializedViewAdditionalProperties.STORAGE_SCHEMA; import static io.trino.plugin.iceberg.IcebergMaterializedViewDefinition.encodeMaterializedViewData; import static io.trino.plugin.iceberg.IcebergMaterializedViewDefinition.fromConnectorMaterializedViewDefinition; @@ -356,16 +357,53 @@ public Table loadTable(ConnectorSession session, SchemaTableName table) @Override public void dropTable(ConnectorSession session, SchemaTableName schemaTableName) { - BaseTable table = (BaseTable) loadTable(session, schemaTableName); - validateTableCanBeDropped(table); + com.amazonaws.services.glue.model.Table metastoreTable; + try { + metastoreTable = stats.getGetTable().call(() -> glueClient + .getTable(new GetTableRequest() + .withDatabaseName(schemaTableName.getSchemaName()) + .withName(schemaTableName.getTableName())) + .getTable()); + } + catch (EntityNotFoundException e) { + throw new TableNotFoundException(schemaTableName, e); + } + + BaseTable table = null; + try { + table = (BaseTable) loadTable(session, schemaTableName); + } + catch (RuntimeException e) { + LOG.warn(e, "Failed to load table " + schemaTableName); + } + + if (table != null) { + validateTableCanBeDropped(table); + } + + String metadataLocation = metastoreTable.getParameters().get(METADATA_LOCATION_PROP); + + if (metadataLocation == null) { + throw new TrinoException(ICEBERG_INVALID_METADATA, format("Table %s is missing [%s] property", schemaTableName, METADATA_LOCATION_PROP)); + } + try { deleteTable(schemaTableName.getSchemaName(), schemaTableName.getTableName()); } catch (AmazonServiceException e) { throw new TrinoException(HIVE_METASTORE_ERROR, e); } - dropTableData(table.io(), table.operations().current()); - deleteTableDirectory(fileSystemFactory.create(session), schemaTableName, table.location()); + + if (table != null) { + try { + dropTableData(table.io(), table.operations().current()); + } + catch (RuntimeException e) { + LOG.warn(e, "Failed to delete data files referenced by TableMetadata for table " + schemaTableName); + } + } + String tableLocation = metadataLocation.replaceFirst("/[^/]*/[^/]*$", ""); + deleteTableDirectory(fileSystemFactory.create(session), schemaTableName, tableLocation); } @Override 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 c43f7874a0ba..878525fecbea 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 @@ -323,19 +323,37 @@ public List listTables(ConnectorSession session, Optional new TableNotFoundException(schemaTableName)); + + BaseTable table = null; + try { + table = (BaseTable) loadTable(session, schemaTableName); + } + catch (RuntimeException e) { + log.warn(e, "Failed to load table " + schemaTableName); + } + + if (table != null) { + validateTableCanBeDropped(table); + } + metastore.dropTable( schemaTableName.getSchemaName(), schemaTableName.getTableName(), false /* do not delete data */); - // Use the Iceberg routine for dropping the table data because the data files - // of the Iceberg table may be located in different locations - dropTableData(table.io(), metadata); + + if (table != null) { + try { + // Use the Iceberg routine for dropping the table data because the data files + // of the Iceberg table may be located in different locations + dropTableData(table.io(), table.operations().current()); + } + catch (RuntimeException e) { + log.warn(e, "Failed to delete data files referenced by TableMetadata for table " + schemaTableName); + } + } deleteTableDirectory(fileSystemFactory.create(session), schemaTableName, metastoreTable.getStorage().getLocation()); } 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 584d2d42b645..f8bed6ec07db 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 @@ -15,10 +15,18 @@ import com.google.common.collect.ImmutableList; import io.trino.Session; +import io.trino.filesystem.FileIterator; +import io.trino.filesystem.TrinoFileSystem; +import io.trino.filesystem.hdfs.HdfsFileSystemFactory; +import io.trino.plugin.iceberg.fileio.ForwardingFileIo; import io.trino.testing.BaseConnectorSmokeTest; import io.trino.testing.TestingConnectorBehavior; +import io.trino.testing.TestingConnectorSession; import io.trino.testing.sql.TestTable; import org.apache.iceberg.FileFormat; +import org.apache.iceberg.TableMetadata; +import org.apache.iceberg.TableMetadataParser; +import org.apache.iceberg.io.FileIO; import org.testng.annotations.Test; import java.util.List; @@ -29,6 +37,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static io.airlift.concurrent.MoreFutures.getFutureValue; +import static io.trino.plugin.hive.HiveTestUtils.HDFS_ENVIRONMENT; import static io.trino.plugin.iceberg.IcebergTestUtils.withSmallRowGroups; import static io.trino.testing.TestingAccessControlManager.TestingPrivilegeType.DROP_TABLE; import static io.trino.testing.TestingAccessControlManager.privilege; @@ -38,16 +47,19 @@ import static java.util.concurrent.Executors.newFixedThreadPool; import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; public abstract class BaseIcebergConnectorSmokeTest extends BaseConnectorSmokeTest { protected final FileFormat format; + private final TrinoFileSystem trinoFileSystem; public BaseIcebergConnectorSmokeTest(FileFormat format) { this.format = requireNonNull(format, "format is null"); + this.trinoFileSystem = new HdfsFileSystemFactory(HDFS_ENVIRONMENT).create(TestingConnectorSession.SESSION); } @SuppressWarnings("DuplicateBranchesInSwitch") @@ -429,6 +441,87 @@ public void testUnregisterTableAccessControl() assertUpdate("DROP TABLE " + tableName); } + @Test + public void testDropTableWithMissingMetadataFile() + throws Exception + { + String tableName = "test_drop_table_with_missing_metadata_file_" + randomNameSuffix(); + assertUpdate("CREATE TABLE " + tableName + " AS SELECT 1 x, 'INDIA' y", 1); + + String metadataLocation = getMetadataLocation(tableName); + + // Delete current metadata file + trinoFileSystem.deleteFile(metadataLocation); + assertThat(trinoFileSystem.newInputFile(metadataLocation).exists()).as("Current metadata file should not exist").isFalse(); + + // try to drop table + assertUpdate("DROP TABLE " + tableName); + assertFalse(getQueryRunner().tableExists(getSession(), tableName)); + } + + @Test + public void testDropTableWithMissingSnaphsotFile() + throws Exception + { + String tableName = "test_drop_table_with_missing_snapshot_file_" + randomNameSuffix(); + assertUpdate("CREATE TABLE " + tableName + " AS SELECT 1 x, 'INDIA' y", 1); + + String metadataLocation = getMetadataLocation(tableName); + TableMetadata tableMetadata = TableMetadataParser.read(new ForwardingFileIo(trinoFileSystem), metadataLocation); + String currentSnapshotFile = tableMetadata.currentSnapshot().manifestListLocation(); + + // Delete current snapshot file + trinoFileSystem.deleteFile(currentSnapshotFile); + assertThat(trinoFileSystem.newInputFile(currentSnapshotFile).exists()).as("Current snapshot file should not exist").isFalse(); + + // try to drop table + assertUpdate("DROP TABLE " + tableName); + assertFalse(getQueryRunner().tableExists(getSession(), tableName)); + } + + @Test + public void testDropTableWithMissingManifestListFile() + throws Exception + { + String tableName = "test_drop_table_with_missing_manifest_list_file_" + randomNameSuffix(); + assertUpdate("CREATE TABLE " + tableName + " AS SELECT 1 x, 'INDIA' y", 1); + + String metadataLocation = getMetadataLocation(tableName); + FileIO fileIo = new ForwardingFileIo(trinoFileSystem); + TableMetadata tableMetadata = TableMetadataParser.read(fileIo, metadataLocation); + String manifestListFile = tableMetadata.currentSnapshot().allManifests(fileIo).get(0).path(); + + // Delete Manifest List file + trinoFileSystem.deleteFile(manifestListFile); + assertThat(trinoFileSystem.newInputFile(manifestListFile).exists()).as("Manifest list file should not exist").isFalse(); + + // try to drop table + assertUpdate("DROP TABLE " + tableName); + assertFalse(getQueryRunner().tableExists(getSession(), tableName)); + } + + @Test + public void testDropTableWithMissingDataFile() + throws Exception + { + String tableName = "test_drop_table_with_missing_data_file_" + randomNameSuffix(); + assertUpdate("CREATE TABLE " + tableName + " AS SELECT 1 x, 'INDIA' y", 1); + + String tableLocation = getTableLocation(tableName); + String tableDataPath = String.format("%s/%s", tableLocation, "data"); + FileIterator fileIterator = trinoFileSystem.listFiles(tableDataPath); + assertTrue(fileIterator.hasNext()); + String dataFile = fileIterator.next().path(); + + // Delete data file + trinoFileSystem.deleteFile(dataFile); + assertThat(trinoFileSystem.newInputFile(dataFile).exists()).as("Data list file should not exist").isFalse(); + + // try to drop table + assertUpdate("DROP TABLE " + tableName); + assertFalse(getQueryRunner().tableExists(getSession(), tableName)); + } + @Test public void testCreateTableWithNonExistingSchemaVerifyLocation() { diff --git a/testing/trino-benchmark/src/test/java/io/trino/benchmark/MemoryLocalQueryRunner.java b/testing/trino-benchmark/src/test/java/io/trino/benchmark/MemoryLocalQueryRunner.java index d1caf805a36d..0100f2e8fe51 100644 --- a/testing/trino-benchmark/src/test/java/io/trino/benchmark/MemoryLocalQueryRunner.java +++ b/testing/trino-benchmark/src/test/java/io/trino/benchmark/MemoryLocalQueryRunner.java @@ -23,6 +23,8 @@ import io.trino.execution.TaskStateMachine; import io.trino.memory.MemoryPool; import io.trino.memory.QueryContext; +import io.trino.metadata.Metadata; +import io.trino.metadata.QualifiedObjectName; import io.trino.operator.Driver; import io.trino.operator.TaskContext; import io.trino.plugin.memory.MemoryConnectorFactory; @@ -119,6 +121,13 @@ private static LocalQueryRunner createMemoryLocalQueryRunner(Session session) return localQueryRunner; } + public void dropTable(String tableName) + { + Session session = localQueryRunner.getDefaultSession(); + Metadata metadata = localQueryRunner.getMetadata(); + metadata.dropTable(session, QualifiedObjectName.valueOf(tableName)); + } + @Override public void close() { diff --git a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveRedirectionToIceberg.java b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveRedirectionToIceberg.java index 417ea40c43cd..bb2039d1534b 100644 --- a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveRedirectionToIceberg.java +++ b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveRedirectionToIceberg.java @@ -13,15 +13,21 @@ */ package io.trino.tests.product.hive; +import io.trino.plugin.hive.metastore.thrift.ThriftMetastoreClient; +import io.trino.tempto.AfterTestWithContext; import io.trino.tempto.BeforeTestWithContext; import io.trino.tempto.ProductTest; import io.trino.tempto.assertions.QueryAssert; +import io.trino.tempto.hadoop.hdfs.HdfsClient; import io.trino.tempto.query.QueryResult; +import org.apache.thrift.TException; import org.assertj.core.api.AbstractStringAssert; import org.assertj.core.api.Assertions; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import javax.inject.Inject; + import static com.google.common.collect.ImmutableList.toImmutableList; import static io.trino.tempto.assertions.QueryAssert.Row.row; import static io.trino.tempto.assertions.QueryAssert.assertQueryFailure; @@ -30,6 +36,7 @@ import static io.trino.testing.TestingNames.randomNameSuffix; import static io.trino.tests.product.TestGroups.HIVE_ICEBERG_REDIRECTIONS; import static io.trino.tests.product.TestGroups.PROFILE_SPECIFIC_TESTS; +import static io.trino.tests.product.iceberg.util.IcebergTestUtils.stripNamenodeURI; import static io.trino.tests.product.utils.QueryExecutors.onTrino; import static java.lang.String.format; import static java.sql.JDBCType.VARCHAR; @@ -37,12 +44,27 @@ public class TestHiveRedirectionToIceberg extends ProductTest { + @Inject + private HdfsClient hdfsClient; + @Inject + private TestHiveMetastoreClientFactory testHiveMetastoreClientFactory; + private ThriftMetastoreClient metastoreClient; + @BeforeTestWithContext public void createAdditionalSchema() + throws TException { + this.metastoreClient = testHiveMetastoreClientFactory.createMetastoreClient(); onTrino().executeQuery("CREATE SCHEMA IF NOT EXISTS hive.nondefaultschema"); } + @AfterTestWithContext + public void tearDown() + { + metastoreClient.close(); + metastoreClient = null; + } + @Test(groups = {HIVE_ICEBERG_REDIRECTIONS, PROFILE_SPECIFIC_TESTS}) public void testRedirect() { @@ -614,6 +636,32 @@ public void testDeny() onTrino().executeQuery("DROP TABLE " + icebergTableName); } + @Test(groups = {HIVE_ICEBERG_REDIRECTIONS, PROFILE_SPECIFIC_TESTS}) + public void testDropTableWithMissingMetadataFile() + throws TException + { + String tableName = "test_drop_table_with_missing_metadata_file_" + randomNameSuffix(); + String hiveTableName = "hive.default." + tableName; + String icebergTableName = "iceberg.default." + tableName; + + createIcebergTable(icebergTableName, false); + + assertResultsEqual( + onTrino().executeQuery("TABLE " + hiveTableName), + onTrino().executeQuery("TABLE " + icebergTableName)); + + String metadataLocation = stripNamenodeURI(metastoreClient.getTable("default", tableName).getParameters().get("metadata_location")); + + // Delete current metadata file + hdfsClient.delete(metadataLocation); + Assertions.assertThat(hdfsClient.exist(metadataLocation)).as("Current metadata file should not exist").isFalse(); + + // try to drop table + onTrino().executeQuery("DROP TABLE " + hiveTableName); + assertQueryFailure(() -> onTrino().executeQuery("TABLE " + icebergTableName)) + .hasMessageMatching("\\QQuery failed (#\\E\\S+\\Q): line 1:1: Table '" + icebergTableName + "' does not exist"); + } + private static void createIcebergTable(String tableName, boolean partitioned) { createIcebergTable(tableName, partitioned, true); diff --git a/testing/trino-product-tests/src/main/java/io/trino/tests/product/iceberg/TestIcebergSparkCompatibility.java b/testing/trino-product-tests/src/main/java/io/trino/tests/product/iceberg/TestIcebergSparkCompatibility.java index 7aa06fd4af19..88eec943e342 100644 --- a/testing/trino-product-tests/src/main/java/io/trino/tests/product/iceberg/TestIcebergSparkCompatibility.java +++ b/testing/trino-product-tests/src/main/java/io/trino/tests/product/iceberg/TestIcebergSparkCompatibility.java @@ -982,7 +982,7 @@ public void testCreateAndDropTableWithSameLocationFailsOnTrino(int specVersion) onTrino().executeQuery(format("DROP TABLE %s", trinoTableName(tableSameLocation1))); assertQueryFailure(() -> onTrino().executeQuery(format("SELECT * FROM %s", trinoTableName(tableSameLocation2)))) - .hasMessageMatching(".*Failed to open input stream for file.*"); + .hasMessageMatching(".*Metadata not found in metadata location for table (.*).*"); // Can't clean up tableSameLocation2 as all data and metadata has been removed }