diff --git a/client/trino-jdbc/src/test/java/io/trino/jdbc/TestTrinoDatabaseMetaData.java b/client/trino-jdbc/src/test/java/io/trino/jdbc/TestTrinoDatabaseMetaData.java index 7ce476f211a2..584fe873db70 100644 --- a/client/trino-jdbc/src/test/java/io/trino/jdbc/TestTrinoDatabaseMetaData.java +++ b/client/trino-jdbc/src/test/java/io/trino/jdbc/TestTrinoDatabaseMetaData.java @@ -1116,8 +1116,7 @@ public void testGetTablesMetadataCalls() databaseMetaData -> databaseMetaData.getTables(null, null, null, null), list("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE")), ImmutableMultiset.builder() - .add("ConnectorMetadata.listViews") - .add("ConnectorMetadata.listTables") + .add("ConnectorMetadata.getRelationTypes") .build()); // Equality predicate on catalog name @@ -1127,8 +1126,7 @@ public void testGetTablesMetadataCalls() databaseMetaData -> databaseMetaData.getTables(COUNTING_CATALOG, null, null, null), list("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE")), ImmutableMultiset.builder() - .add("ConnectorMetadata.listViews") - .add("ConnectorMetadata.listTables") + .add("ConnectorMetadata.getRelationTypes") .build()); // Equality predicate on schema name @@ -1142,8 +1140,7 @@ public void testGetTablesMetadataCalls() .map(schemaTableName -> list(COUNTING_CATALOG, schemaTableName.getSchemaName(), schemaTableName.getTableName(), "TABLE")) .collect(toImmutableList()), ImmutableMultiset.builder() - .add("ConnectorMetadata.listViews(schema=test_schema1)") - .add("ConnectorMetadata.listTables(schema=test_schema1)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema1)") .build()); // LIKE predicate on schema name @@ -1157,8 +1154,7 @@ public void testGetTablesMetadataCalls() .map(schemaTableName -> list(COUNTING_CATALOG, schemaTableName.getSchemaName(), schemaTableName.getTableName(), "TABLE")) .collect(toImmutableList()), ImmutableMultiset.builder() - .add("ConnectorMetadata.listViews") - .add("ConnectorMetadata.listTables") + .add("ConnectorMetadata.getRelationTypes") .build()); // Equality predicate on table name @@ -1171,8 +1167,7 @@ public void testGetTablesMetadataCalls() list(COUNTING_CATALOG, "test_schema1", "test_table1", "TABLE"), list(COUNTING_CATALOG, "test_schema2", "test_table1", "TABLE")), ImmutableMultiset.builder() - .add("ConnectorMetadata.listViews") - .add("ConnectorMetadata.listTables") + .add("ConnectorMetadata.getRelationTypes") .build()); // LIKE predicate on table name @@ -1185,8 +1180,7 @@ public void testGetTablesMetadataCalls() list(COUNTING_CATALOG, "test_schema1", "test_table1", "TABLE"), list(COUNTING_CATALOG, "test_schema2", "test_table1", "TABLE")), ImmutableMultiset.builder() - .add("ConnectorMetadata.listViews") - .add("ConnectorMetadata.listTables") + .add("ConnectorMetadata.getRelationTypes") .build()); // Equality predicate on schema name and table name @@ -1197,8 +1191,8 @@ public void testGetTablesMetadataCalls() list("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE")), list(list(COUNTING_CATALOG, "test_schema1", "test_table1", "TABLE")), ImmutableMultiset.builder() - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table1)", 5) - .addCopies("ConnectorMetadata.getView(schema=test_schema1, table=test_table1)", 2) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table1)", 4) + .add("ConnectorMetadata.getView(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.getMaterializedView(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.redirectTable(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.getTableHandle(schema=test_schema1, table=test_table1)") @@ -1212,8 +1206,7 @@ public void testGetTablesMetadataCalls() list("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE")), list(list(COUNTING_CATALOG, "test_schema1", "test_table1", "TABLE")), ImmutableMultiset.builder() - .add("ConnectorMetadata.listViews") - .add("ConnectorMetadata.listTables") + .add("ConnectorMetadata.getRelationTypes") .build()); // catalog does not exist @@ -1530,8 +1523,7 @@ private void testAssumeLiteralMetadataCalls(String escapeLiteralParameter) .map(schemaTableName -> list(COUNTING_CATALOG, schemaTableName.getSchemaName(), schemaTableName.getTableName(), "TABLE")) .collect(toImmutableList()), ImmutableMultiset.builder() - .add("ConnectorMetadata.listViews(schema=test_schema1)") - .add("ConnectorMetadata.listTables(schema=test_schema1)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema1)") .build()); // getTables's schema and table name patterns treated as literals @@ -1542,8 +1534,8 @@ private void testAssumeLiteralMetadataCalls(String escapeLiteralParameter) list("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE")), list(list(COUNTING_CATALOG, "test_schema1", "test_table1", "TABLE")), ImmutableMultiset.builder() - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table1)", 5) - .addCopies("ConnectorMetadata.getView(schema=test_schema1, table=test_table1)", 2) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table1)", 4) + .add("ConnectorMetadata.getView(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.getMaterializedView(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.redirectTable(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.getTableHandle(schema=test_schema1, table=test_table1)") @@ -1557,8 +1549,7 @@ private void testAssumeLiteralMetadataCalls(String escapeLiteralParameter) list("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE")), list(), ImmutableMultiset.builder() - .add("ConnectorMetadata.listViews(schema=test_schema_)") - .add("ConnectorMetadata.listTables(schema=test_schema_)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema_)") .build()); // getColumns's schema and table name patterns treated as literals diff --git a/core/trino-main/src/main/java/io/trino/connector/informationschema/InformationSchemaPageSource.java b/core/trino-main/src/main/java/io/trino/connector/informationschema/InformationSchemaPageSource.java index 521369d5c7cc..143cc6493c63 100644 --- a/core/trino-main/src/main/java/io/trino/connector/informationschema/InformationSchemaPageSource.java +++ b/core/trino-main/src/main/java/io/trino/connector/informationschema/InformationSchemaPageSource.java @@ -26,6 +26,7 @@ import io.trino.spi.connector.ColumnHandle; import io.trino.spi.connector.ColumnMetadata; import io.trino.spi.connector.ConnectorPageSource; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.security.AccessDeniedException; import io.trino.spi.security.GrantInfo; @@ -37,6 +38,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Optional; import java.util.OptionalLong; import java.util.Queue; @@ -52,12 +54,12 @@ import static io.trino.SystemSessionProperties.isOmitDateTimeTypePrecision; import static io.trino.connector.informationschema.InformationSchemaMetadata.defaultPrefixes; import static io.trino.connector.informationschema.InformationSchemaMetadata.isTablesEnumeratingTable; +import static io.trino.metadata.MetadataListing.getRelationTypes; import static io.trino.metadata.MetadataListing.getViews; import static io.trino.metadata.MetadataListing.listSchemas; import static io.trino.metadata.MetadataListing.listTableColumns; import static io.trino.metadata.MetadataListing.listTablePrivileges; import static io.trino.metadata.MetadataListing.listTables; -import static io.trino.metadata.MetadataListing.listViews; import static io.trino.spi.security.PrincipalType.USER; import static io.trino.spi.type.TypeUtils.writeNativeValue; import static io.trino.type.TypeUtils.getDisplayLabel; @@ -245,7 +247,7 @@ private void buildPages() private void addColumnsRecords(QualifiedTablePrefix prefix) { - for (Map.Entry> entry : listTableColumns(session, metadata, accessControl, prefix).entrySet()) { + for (Entry> entry : listTableColumns(session, metadata, accessControl, prefix).entrySet()) { SchemaTableName tableName = entry.getKey(); long ordinalPosition = 1; @@ -275,16 +277,24 @@ private void addColumnsRecords(QualifiedTablePrefix prefix) private void addTablesRecords(QualifiedTablePrefix prefix) { - Set tables = listTables(session, metadata, accessControl, prefix); boolean needsTableType = requiredColumns.contains("table_type"); - Set views = Set.of(); + Set relations; + Set views; if (needsTableType) { - // TODO introduce a dedicated method for getting relations with their type from the connector, instead of calling (potentially much more expensive) getViews - views = listViews(session, metadata, accessControl, prefix); + Map relationTypes = getRelationTypes(session, metadata, accessControl, prefix); + relations = relationTypes.keySet(); + views = relationTypes.entrySet().stream() + .filter(entry -> entry.getValue() == RelationType.VIEW) + .map(Entry::getKey) + .collect(toImmutableSet()); + } + else { + relations = listTables(session, metadata, accessControl, prefix); + views = Set.of(); } // TODO (https://github.com/trinodb/trino/issues/8207) define a type for materialized views - for (SchemaTableName name : tables) { + for (SchemaTableName name : relations) { String type = null; if (needsTableType) { // if table and view names overlap, the view wins @@ -304,7 +314,7 @@ private void addTablesRecords(QualifiedTablePrefix prefix) private void addViewsRecords(QualifiedTablePrefix prefix) { - for (Map.Entry entry : getViews(session, metadata, accessControl, prefix).entrySet()) { + for (Entry entry : getViews(session, metadata, accessControl, prefix).entrySet()) { addRecord( prefix.getCatalogName(), entry.getKey().getSchemaName(), diff --git a/core/trino-main/src/main/java/io/trino/connector/system/jdbc/TableJdbcTable.java b/core/trino-main/src/main/java/io/trino/connector/system/jdbc/TableJdbcTable.java index 320172490d1f..45413ef690b5 100644 --- a/core/trino-main/src/main/java/io/trino/connector/system/jdbc/TableJdbcTable.java +++ b/core/trino-main/src/main/java/io/trino/connector/system/jdbc/TableJdbcTable.java @@ -26,19 +26,18 @@ import io.trino.spi.connector.InMemoryRecordSet; import io.trino.spi.connector.InMemoryRecordSet.Builder; import io.trino.spi.connector.RecordCursor; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.predicate.Domain; import io.trino.spi.predicate.TupleDomain; import java.util.Optional; -import java.util.Set; import static io.trino.connector.system.jdbc.FilterUtil.isImpossibleObjectName; import static io.trino.connector.system.jdbc.FilterUtil.tablePrefix; import static io.trino.connector.system.jdbc.FilterUtil.tryGetSingleVarcharValue; +import static io.trino.metadata.MetadataListing.getRelationTypes; import static io.trino.metadata.MetadataListing.listCatalogNames; -import static io.trino.metadata.MetadataListing.listTables; -import static io.trino.metadata.MetadataListing.listViews; import static io.trino.metadata.MetadataUtil.TableMetadataBuilder.tableMetadataBuilder; import static io.trino.spi.type.VarcharType.VARCHAR; import static java.util.Objects.requireNonNull; @@ -104,13 +103,12 @@ public RecordCursor cursor(ConnectorTransactionHandle transactionHandle, Connect for (String catalog : listCatalogNames(session, metadata, accessControl, catalogDomain)) { QualifiedTablePrefix prefix = tablePrefix(catalog, schemaFilter, tableFilter); - Set views = listViews(session, metadata, accessControl, prefix); - for (SchemaTableName name : listTables(session, metadata, accessControl, prefix)) { - boolean isView = views.contains(name); + getRelationTypes(session, metadata, accessControl, prefix).forEach((name, type) -> { + boolean isView = type == RelationType.VIEW; if ((includeTables && !isView) || (includeViews && isView)) { table.addRow(tableRow(catalog, name, isView ? "VIEW" : "TABLE")); } - } + }); } return table.build().cursor(); } 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 e55b75efa63a..bb2cad83e056 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 @@ -37,6 +37,7 @@ import io.trino.spi.connector.MaterializedViewFreshness; import io.trino.spi.connector.ProjectionApplicationResult; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.RowChangeParadigm; import io.trino.spi.connector.SampleApplicationResult; import io.trino.spi.connector.SampleType; @@ -164,6 +165,12 @@ Optional getTableHandleForExecute( */ List listTables(Session session, QualifiedTablePrefix prefix); + /** + * Get the relation names that match the specified table prefix (never null). + * This includes all relations (e.g. tables, views, materialized views). + */ + Map getRelationTypes(Session session, QualifiedTablePrefix prefix); + /** * Gets all of the columns on the specified table, or an empty map if the columns cannot be enumerated. * diff --git a/core/trino-main/src/main/java/io/trino/metadata/MetadataListing.java b/core/trino-main/src/main/java/io/trino/metadata/MetadataListing.java index f72cb857704c..8088d145a927 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/MetadataListing.java +++ b/core/trino-main/src/main/java/io/trino/metadata/MetadataListing.java @@ -22,6 +22,7 @@ import io.trino.spi.TrinoException; import io.trino.spi.connector.CatalogHandle; import io.trino.spi.connector.ColumnMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableColumnsMetadata; import io.trino.spi.predicate.Domain; @@ -46,6 +47,7 @@ import static io.trino.connector.system.jdbc.FilterUtil.tryGetSingleVarcharValue; import static io.trino.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR; import static io.trino.spi.StandardErrorCode.TABLE_REDIRECTION_ERROR; +import static java.util.function.Function.identity; public final class MetadataListing { @@ -133,22 +135,29 @@ private static Set doListTables(Session session, Metadata metad return accessControl.filterTables(session.toSecurityContext(), prefix.getCatalogName(), tableNames); } - public static Set listViews(Session session, Metadata metadata, AccessControl accessControl, QualifiedTablePrefix prefix) + public static Map getRelationTypes(Session session, Metadata metadata, AccessControl accessControl, QualifiedTablePrefix prefix) { try { - return doListViews(session, metadata, accessControl, prefix); + return doGetRelationTypes(session, metadata, accessControl, prefix); } catch (RuntimeException exception) { - throw handleListingException(exception, "views", prefix.getCatalogName()); + throw handleListingException(exception, "tables", prefix.getCatalogName()); } } - private static Set doListViews(Session session, Metadata metadata, AccessControl accessControl, QualifiedTablePrefix prefix) + private static Map doGetRelationTypes(Session session, Metadata metadata, AccessControl accessControl, QualifiedTablePrefix prefix) { - Set tableNames = metadata.listViews(session, prefix).stream() - .map(QualifiedObjectName::asSchemaTableName) - .collect(toImmutableSet()); - return accessControl.filterTables(session.toSecurityContext(), prefix.getCatalogName(), tableNames); + Map relationTypes = metadata.getRelationTypes(session, prefix); + + // Table listing operation only involves getting table names, but not any metadata. So redirected tables are not + // handled any differently. The target table or catalog are not involved. Thus the following filter is only called + // for the source catalog on source table names. + Set accessibleNames = accessControl.filterTables(session.toSecurityContext(), prefix.getCatalogName(), relationTypes.keySet()); + if (accessibleNames.equals(relationTypes.keySet())) { + return relationTypes; + } + return accessibleNames.stream() + .collect(toImmutableMap(identity(), relationTypes::get)); } public static Map getViews(Session session, Metadata metadata, AccessControl accessControl, QualifiedTablePrefix prefix) 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 80ca50b6a120..1adeb8d71a4a 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 @@ -69,6 +69,7 @@ import io.trino.spi.connector.ProjectionApplicationResult; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.RowChangeParadigm; import io.trino.spi.connector.SampleApplicationResult; import io.trino.spi.connector.SampleType; @@ -511,10 +512,11 @@ public List listTables(Session session, QualifiedTablePrefi Optional objectName = prefix.asQualifiedObjectName(); if (objectName.isPresent()) { - Optional exists = isExistingRelationForListing(session, objectName.get()); - if (exists.isPresent()) { - return exists.get() ? ImmutableList.of(objectName.get()) : ImmutableList.of(); + Optional relationType = getRelationTypeIfExists(session, objectName.get()); + if (relationType.isPresent()) { + return ImmutableList.of(objectName.get()); } + // TODO we can probably return empty lit here } Optional catalog = getOptionalCatalogMetadata(session, prefix.getCatalogName()); @@ -537,25 +539,63 @@ public List listTables(Session session, QualifiedTablePrefi return ImmutableList.copyOf(tables); } - private Optional isExistingRelationForListing(Session session, QualifiedObjectName name) + @Override + public Map getRelationTypes(Session session, QualifiedTablePrefix prefix) + { + requireNonNull(prefix, "prefix is null"); + if (cannotExist(prefix)) { + return ImmutableMap.of(); + } + + Optional objectName = prefix.asQualifiedObjectName(); + if (objectName.isPresent()) { + Optional relationType = getRelationTypeIfExists(session, objectName.get()); + if (relationType.isPresent()) { + return ImmutableMap.of(objectName.get().asSchemaTableName(), relationType.get()); + } + return ImmutableMap.of(); + } + + Optional catalog = getOptionalCatalogMetadata(session, prefix.getCatalogName()); + Map relationTypes = new LinkedHashMap<>(); + if (catalog.isPresent()) { + CatalogMetadata catalogMetadata = catalog.get(); + + for (CatalogHandle catalogHandle : catalogMetadata.listCatalogHandles()) { + ConnectorMetadata metadata = catalogMetadata.getMetadataFor(session, catalogHandle); + ConnectorSession connectorSession = session.toConnectorSession(catalogHandle); + if (isExternalInformationSchema(catalogHandle, prefix.getSchemaName())) { + continue; + } + metadata.getRelationTypes(connectorSession, prefix.getSchemaName()).entrySet().stream() + .filter(entry -> !isExternalInformationSchema(catalogHandle, entry.getKey().getSchemaName())) + .forEach(entry -> relationTypes.put(entry.getKey(), entry.getValue())); + } + } + return ImmutableMap.copyOf(relationTypes); + } + + private Optional getRelationTypeIfExists(Session session, QualifiedObjectName name) { if (isMaterializedView(session, name)) { - return Optional.of(true); + return Optional.of(RelationType.MATERIALIZED_VIEW); } if (isView(session, name)) { - return Optional.of(true); + return Optional.of(RelationType.VIEW); } // TODO: consider a better way to resolve relation names: https://github.com/trinodb/trino/issues/9400 try { - return Optional.of(getRedirectionAwareTableHandle(session, name).tableHandle().isPresent()); + if (getRedirectionAwareTableHandle(session, name).tableHandle().isPresent()) { + return Optional.of(RelationType.TABLE); + } + return Optional.empty(); } catch (TrinoException e) { // ignore redirection errors for consistency with listing if (e.getErrorCode().equals(TABLE_REDIRECTION_ERROR.toErrorCode())) { - return Optional.of(true); + return Optional.of(RelationType.TABLE); } - // we don't know if it exists or not return Optional.empty(); } } diff --git a/core/trino-main/src/main/java/io/trino/tracing/TracingConnectorMetadata.java b/core/trino-main/src/main/java/io/trino/tracing/TracingConnectorMetadata.java index df84f0eec8bd..26cfe77b0373 100644 --- a/core/trino-main/src/main/java/io/trino/tracing/TracingConnectorMetadata.java +++ b/core/trino-main/src/main/java/io/trino/tracing/TracingConnectorMetadata.java @@ -51,6 +51,7 @@ import io.trino.spi.connector.ProjectionApplicationResult; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.RetryMode; import io.trino.spi.connector.RowChangeParadigm; import io.trino.spi.connector.SampleApplicationResult; @@ -267,6 +268,15 @@ public List listTables(ConnectorSession session, Optional getRelationTypes(ConnectorSession session, Optional schemaName) + { + Span span = startSpan("getRelationTypes", schemaName); + try (var ignored = scopedSpan(span)) { + return delegate.getRelationTypes(session, schemaName); + } + } + @Override public Map getColumnHandles(ConnectorSession session, ConnectorTableHandle tableHandle) { diff --git a/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java b/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java index e629d9524267..6d669bd5e7a9 100644 --- a/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java +++ b/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java @@ -65,6 +65,7 @@ import io.trino.spi.connector.MaterializedViewFreshness; import io.trino.spi.connector.ProjectionApplicationResult; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.RowChangeParadigm; import io.trino.spi.connector.SampleApplicationResult; import io.trino.spi.connector.SampleType; @@ -317,6 +318,15 @@ public List listTables(Session session, QualifiedTablePrefi } } + @Override + public Map getRelationTypes(Session session, QualifiedTablePrefix prefix) + { + Span span = startSpan("getRelationTypes", prefix); + try (var ignored = scopedSpan(span)) { + return delegate.getRelationTypes(session, prefix); + } + } + @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 5d9d9f27d32e..2611b045a74e 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 @@ -43,6 +43,7 @@ import io.trino.spi.connector.MaterializedViewFreshness; import io.trino.spi.connector.ProjectionApplicationResult; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.RowChangeParadigm; import io.trino.spi.connector.SampleApplicationResult; import io.trino.spi.connector.SampleType; @@ -232,6 +233,12 @@ public List listTables(Session session, QualifiedTablePrefi throw new UnsupportedOperationException(); } + @Override + public Map getRelationTypes(Session session, QualifiedTablePrefix prefix) + { + throw new UnsupportedOperationException(); + } + @Override public Map getColumnHandles(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 09842afe22c6..3a006f8a0a84 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 @@ -283,6 +283,28 @@ default List listTables(ConnectorSession session, Optional getRelationTypes(ConnectorSession session, Optional schemaName) + { + Set materializedViews = Set.copyOf(listMaterializedViews(session, schemaName)); + Set views = Set.copyOf(listViews(session, schemaName)); + + return listTables(session, schemaName).stream() + .collect(toMap( + identity(), + relation -> { + if (materializedViews.contains(relation)) { + return RelationType.MATERIALIZED_VIEW; + } + if (views.contains(relation)) { + return RelationType.VIEW; + } + return RelationType.TABLE; + })); + } + /** * Gets all of the columns on the specified table, or an empty map if the columns cannot be enumerated. * diff --git a/core/trino-spi/src/main/java/io/trino/spi/connector/RelationType.java b/core/trino-spi/src/main/java/io/trino/spi/connector/RelationType.java new file mode 100644 index 000000000000..d038a1de8bc3 --- /dev/null +++ b/core/trino-spi/src/main/java/io/trino/spi/connector/RelationType.java @@ -0,0 +1,21 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.spi.connector; + +public enum RelationType +{ + TABLE, + VIEW, + MATERIALIZED_VIEW, +} 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 adc7a7be7b7e..dfbed636f83b 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 @@ -51,6 +51,7 @@ import io.trino.spi.connector.ProjectionApplicationResult; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.RetryMode; import io.trino.spi.connector.RowChangeParadigm; import io.trino.spi.connector.SampleApplicationResult; @@ -294,6 +295,14 @@ public List listTables(ConnectorSession session, Optional getRelationTypes(ConnectorSession session, Optional schemaName) + { + try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(classLoader)) { + return delegate.getRelationTypes(session, schemaName); + } + } + @Override public Map getColumnHandles(ConnectorSession session, ConnectorTableHandle tableHandle) { diff --git a/plugin/trino-hive/pom.xml b/plugin/trino-hive/pom.xml index f844ae68cb26..577bbbd24557 100644 --- a/plugin/trino-hive/pom.xml +++ b/plugin/trino-hive/pom.xml @@ -536,7 +536,7 @@ maven-surefire-plugin - **/TestHiveGlueMetastore.java + **/TestGlueHiveMetastore.java **/TestHiveS3AndGlueMetastoreTest.java **/TestHiveConcurrentModificationGlueMetastore.java **/TestFullParquetReader.java @@ -593,7 +593,7 @@ maven-surefire-plugin - **/TestHiveGlueMetastore.java + **/TestGlueHiveMetastore.java **/TestHiveS3AndGlueMetastoreTest.java **/TestHiveConcurrentModificationGlueMetastore.java 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 71bc4e010046..596550932425 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 @@ -88,6 +88,7 @@ import io.trino.spi.connector.MaterializedViewFreshness; import io.trino.spi.connector.MetadataProvider; import io.trino.spi.connector.ProjectionApplicationResult; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.RetryMode; import io.trino.spi.connector.RowChangeParadigm; import io.trino.spi.connector.SchemaNotFoundException; @@ -137,6 +138,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Optional; import java.util.OptionalInt; @@ -814,6 +816,34 @@ public List listTables(ConnectorSession session, Optional getRelationTypes(ConnectorSession session, Optional optionalSchemaName) + { + ImmutableMap.Builder result = ImmutableMap.builder(); + + boolean fetched = false; + if (optionalSchemaName.isEmpty()) { + Optional> relationTypes = metastore.getRelationTypes(); + if (relationTypes.isPresent()) { + relationTypes.get().entrySet().stream() + .filter(entry -> !isHiveSystemSchema(entry.getKey().getSchemaName())) + .forEach(result::put); + fetched = true; + } + } + if (!fetched) { + for (String schemaName : listSchemas(session, optionalSchemaName)) { + for (Entry entry : metastore.getRelationTypes(schemaName).entrySet()) { + result.put(new SchemaTableName(schemaName, entry.getKey()), entry.getValue()); + } + } + } + + listMaterializedViews(session, optionalSchemaName) + .forEach(name -> result.put(name, RelationType.MATERIALIZED_VIEW)); + return result.buildKeepingLast(); + } + private List listSchemas(ConnectorSession session, Optional schemaName) { if (schemaName.isPresent()) { @@ -892,7 +922,7 @@ public TableStatistics getTableStatistics(ConnectorSession session, ConnectorTab .collect(toImmutableMap(HiveColumnHandle::getName, Function.identity())); Map columnTypes = columns.entrySet().stream() - .collect(toImmutableMap(Map.Entry::getKey, entry -> getColumnMetadata(session, tableHandle, entry.getValue()).getType())); + .collect(toImmutableMap(Entry::getKey, entry -> getColumnMetadata(session, tableHandle, entry.getValue()).getType())); HivePartitionResult partitionResult = partitionManager.getPartitions(metastore, tableHandle, new Constraint(hiveTableHandle.getEnforcedConstraint())); // If partitions are not loaded, then don't generate table statistics. // Note that the computation is not persisted in the table handle, so can be redone many times @@ -3075,7 +3105,7 @@ public Optional> applyProjecti ImmutableMap.Builder newVariablesBuilder = ImmutableMap.builder(); ImmutableSet.Builder projectedColumnsBuilder = ImmutableSet.builder(); - for (Map.Entry entry : columnProjections.entrySet()) { + for (Entry entry : columnProjections.entrySet()) { ConnectorExpression expression = entry.getKey(); ProjectedColumnRepresentation projectedColumn = entry.getValue(); diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveMetastoreClosure.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveMetastoreClosure.java index 190e81bd28fe..cdbeee24b11a 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveMetastoreClosure.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveMetastoreClosure.java @@ -30,6 +30,7 @@ import io.trino.plugin.hive.metastore.Table; import io.trino.plugin.hive.projection.PartitionProjection; import io.trino.spi.TrinoException; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; import io.trino.spi.function.LanguageFunction; @@ -164,6 +165,16 @@ public Optional> getAllTables() return delegate.getAllTables(); } + public Map getRelationTypes(String databaseName) + { + return delegate.getRelationTypes(databaseName); + } + + public Optional> getRelationTypes() + { + return delegate.getRelationTypes(); + } + public List getAllViews(String databaseName) { return delegate.getAllViews(databaseName); diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/ForwardingHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/ForwardingHiveMetastore.java index f8b3fcd5926c..2a4c7a2701d6 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/ForwardingHiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/ForwardingHiveMetastore.java @@ -21,6 +21,7 @@ import io.trino.plugin.hive.acid.AcidOperation; import io.trino.plugin.hive.acid.AcidTransaction; import io.trino.plugin.hive.metastore.HivePrivilegeInfo.HivePrivilege; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.function.LanguageFunction; import io.trino.spi.predicate.TupleDomain; @@ -122,6 +123,18 @@ public Optional> getAllTables() return delegate.getAllTables(); } + @Override + public Map getRelationTypes(String databaseName) + { + return delegate.getRelationTypes(databaseName); + } + + @Override + public Optional> getRelationTypes() + { + return delegate.getRelationTypes(); + } + @Override public List getTablesWithParameter(String databaseName, String parameterKey, String parameterValue) { diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/HiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/HiveMetastore.java index 30b91704acea..2a821d23f29e 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/HiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/HiveMetastore.java @@ -23,6 +23,7 @@ import io.trino.plugin.hive.acid.AcidTransaction; import io.trino.plugin.hive.metastore.HivePrivilegeInfo.HivePrivilege; import io.trino.spi.TrinoException; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.function.LanguageFunction; import io.trino.spi.predicate.TupleDomain; @@ -69,6 +70,13 @@ default void updatePartitionStatistics(Table table, String partitionName, Functi */ Optional> getAllTables(); + Map getRelationTypes(String databaseName); + + /** + * @return empty if operation is not supported + */ + Optional> getRelationTypes(); + List getTablesWithParameter(String databaseName, String parameterKey, String parameterValue); /** diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/SemiTransactionalHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/SemiTransactionalHiveMetastore.java index 8a377fa75504..81eb6abafce7 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/SemiTransactionalHiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/SemiTransactionalHiveMetastore.java @@ -52,6 +52,7 @@ import io.trino.plugin.hive.util.ValidTxnWriteIdList; import io.trino.spi.TrinoException; import io.trino.spi.connector.ConnectorSession; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaNotFoundException; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; @@ -252,6 +253,24 @@ public synchronized Optional> getAllTables() return delegate.getAllTables(); } + public synchronized Map getRelationTypes(String databaseName) + { + checkReadable(); + if (!tableActions.isEmpty()) { + throw new UnsupportedOperationException("Listing all relations after adding/dropping/altering tables/views in a transaction is not supported"); + } + return delegate.getRelationTypes(databaseName); + } + + public synchronized Optional> getRelationTypes() + { + checkReadable(); + if (!tableActions.isEmpty()) { + throw new UnsupportedOperationException("Listing all relations after adding/dropping/altering tables/views in a transaction is not supported"); + } + return delegate.getRelationTypes(); + } + public synchronized Optional getTable(String databaseName, String tableName) { checkReadable(); diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/cache/CachingHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/cache/CachingHiveMetastore.java index b7e817737454..478c865c3700 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/cache/CachingHiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/cache/CachingHiveMetastore.java @@ -17,6 +17,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader.InvalidCacheLoadException; import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Sets.SetView; @@ -49,6 +50,7 @@ import io.trino.plugin.hive.metastore.PrincipalPrivileges; import io.trino.plugin.hive.metastore.Table; import io.trino.spi.TrinoException; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.function.LanguageFunction; import io.trino.spi.predicate.TupleDomain; @@ -116,6 +118,8 @@ public enum StatsRecording private final LoadingCache> tableCache; private final LoadingCache> tableNamesCache; private final LoadingCache>> allTableNamesCache; + private final LoadingCache> relationTypesCache; + private final LoadingCache>> allRelationTypesCache; private final LoadingCache> tablesWithParameterCache; private final Cache> tableStatisticsCache; private final Cache> partitionStatisticsCache; @@ -202,6 +206,8 @@ private CachingHiveMetastore( databaseCache = cacheFactory.buildCache(this::loadDatabase); tableNamesCache = cacheFactory.buildCache(this::loadAllTables); allTableNamesCache = cacheFactory.buildCache(ignore -> loadAllTables()); + relationTypesCache = cacheFactory.buildCache(this::loadRelationTypes); + allRelationTypesCache = cacheFactory.buildCache(ignore -> loadRelationTypes()); tablesWithParameterCache = cacheFactory.buildCache(this::loadTablesMatchingParameter); tableStatisticsCache = statsCacheFactory.buildCache(this::refreshTableStatistics); tableCache = cacheFactory.buildCache(this::loadTable); @@ -223,6 +229,8 @@ public void flushCache() databaseNamesCache.invalidateAll(); tableNamesCache.invalidateAll(); allTableNamesCache.invalidateAll(); + relationTypesCache.invalidateAll(); + allRelationTypesCache.invalidateAll(); viewNamesCache.invalidateAll(); allViewNamesCache.invalidateAll(); databaseCache.invalidateAll(); @@ -572,6 +580,10 @@ public void updatePartitionStatistics(Table table, Map getAllTables(String databaseName) { + Map relationTypes = relationTypesCache.getIfPresent(databaseName); + if (relationTypes != null) { + return ImmutableList.copyOf(relationTypes.keySet()); + } return get(tableNamesCache, databaseName); } @@ -583,6 +595,10 @@ private List loadAllTables(String databaseName) @Override public Optional> getAllTables() { + Optional> relationTypes = allRelationTypesCache.getIfPresent(SingletonCacheKey.INSTANCE); + if (relationTypes != null && relationTypes.isPresent()) { + return Optional.of(ImmutableList.copyOf(relationTypes.get().keySet())); + } return getOptional(allTableNamesCache, SingletonCacheKey.INSTANCE); } @@ -591,6 +607,28 @@ private Optional> loadAllTables() return delegate.getAllTables(); } + @Override + public Map getRelationTypes(String databaseName) + { + return get(relationTypesCache, databaseName); + } + + private Map loadRelationTypes(String databaseName) + { + return delegate.getRelationTypes(databaseName); + } + + @Override + public Optional> getRelationTypes() + { + return getOptional(allRelationTypesCache, SingletonCacheKey.INSTANCE); + } + + private Optional> loadRelationTypes() + { + return delegate.getRelationTypes(); + } + @Override public List getTablesWithParameter(String databaseName, String parameterKey, String parameterValue) { @@ -794,6 +832,8 @@ public void invalidateTable(String databaseName, String tableName) tableCache.invalidate(hiveTableName); tableNamesCache.invalidate(databaseName); allTableNamesCache.invalidateAll(); + relationTypesCache.invalidate(databaseName); + allRelationTypesCache.invalidateAll(); viewNamesCache.invalidate(databaseName); allViewNamesCache.invalidateAll(); invalidateAllIf(tablePrivilegesCache, userTableKey -> userTableKey.matches(databaseName, tableName)); @@ -1290,6 +1330,20 @@ public CacheStatsMBean getAllTableNamesStats() return new CacheStatsMBean(allTableNamesCache); } + @Managed + @Nested + public CacheStatsMBean getRelationTypesStats() + { + return new CacheStatsMBean(relationTypesCache); + } + + @Managed + @Nested + public CacheStatsMBean getAllRelationTypesStats() + { + return new CacheStatsMBean(allRelationTypesCache); + } + @Managed @Nested public CacheStatsMBean getTableWithParameterStats() @@ -1395,6 +1449,16 @@ LoadingCache>> getAllTableName return allTableNamesCache; } + LoadingCache> getRelationTypesCache() + { + return relationTypesCache; + } + + LoadingCache>> getAllRelationTypesCache() + { + return allRelationTypesCache; + } + LoadingCache> getTablesWithParameterCache() { return tablesWithParameterCache; @@ -1450,7 +1514,8 @@ LoadingCache> getConfigValuesCache() return configValuesCache; } - private record CacheFactory(OptionalLong expiresAfterWriteMillis, OptionalLong refreshMillis, Optional refreshExecutor, long maximumSize, StatsRecording statsRecording) + private record CacheFactory(OptionalLong expiresAfterWriteMillis, OptionalLong refreshMillis, Optional refreshExecutor, long maximumSize, + StatsRecording statsRecording) { private static final CacheFactory NEVER_CACHE = new CacheFactory(OptionalLong.empty(), OptionalLong.empty(), Optional.empty(), 0, StatsRecording.DISABLED); diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/cache/SharedHiveMetastoreCache.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/cache/SharedHiveMetastoreCache.java index aeeefbbf6033..4c42d4e5c935 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/cache/SharedHiveMetastoreCache.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/cache/SharedHiveMetastoreCache.java @@ -261,6 +261,20 @@ public AggregateCacheStatsMBean getAllTableNamesStats() return new AggregateCacheStatsMBean(CachingHiveMetastore::getAllTableNamesCache); } + @Managed + @Nested + public AggregateCacheStatsMBean getRelationTypesStats() + { + return new AggregateCacheStatsMBean(CachingHiveMetastore::getRelationTypesCache); + } + + @Managed + @Nested + public AggregateCacheStatsMBean getAllRelationTypesStats() + { + return new AggregateCacheStatsMBean(CachingHiveMetastore::getAllRelationTypesCache); + } + @Managed @Nested public AggregateCacheStatsMBean getTableWithParameterStats() diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/file/FileHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/file/FileHiveMetastore.java index d529b1e22d5b..994b7174b268 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/file/FileHiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/file/FileHiveMetastore.java @@ -56,6 +56,7 @@ import io.trino.plugin.hive.metastore.thrift.ThriftMetastoreUtil; import io.trino.spi.TrinoException; import io.trino.spi.connector.ColumnNotFoundException; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaNotFoundException; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; @@ -523,6 +524,21 @@ public Optional> getAllTables() return Optional.empty(); } + @Override + public synchronized Map getRelationTypes(String databaseName) + { + ImmutableMap.Builder relationTypes = ImmutableMap.builder(); + getAllTables(databaseName).forEach(name -> relationTypes.put(name, RelationType.TABLE)); + getAllViews(databaseName).forEach(name -> relationTypes.put(name, RelationType.VIEW)); + return relationTypes.buildKeepingLast(); + } + + @Override + public Optional> getRelationTypes() + { + return Optional.empty(); + } + @Override public synchronized List getTablesWithParameter(String databaseName, String parameterKey, String parameterValue) { diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueHiveMetastore.java index fc6c078e9a65..c4941e9cd0c7 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueHiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueHiveMetastore.java @@ -102,6 +102,7 @@ import io.trino.plugin.hive.util.HiveUtil; import io.trino.spi.TrinoException; import io.trino.spi.connector.ColumnNotFoundException; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaNotFoundException; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; @@ -434,6 +435,37 @@ public Optional> getAllTables() return Optional.empty(); } + @Override + public Map getRelationTypes(String databaseName) + { + try { + return getGlueTables(databaseName) + .filter(tableFilter.or(SOME_KIND_OF_VIEW_FILTER)) + .collect(toImmutableMap( + com.amazonaws.services.glue.model.Table::getName, + table -> { + // GlueHiveMetastore currently does not distinguish views and materialized views, see getAllViews(). + if (SOME_KIND_OF_VIEW_FILTER.test(table)) { + return RelationType.VIEW; + } + return RelationType.TABLE; + })); + } + catch (EntityNotFoundException | AccessDeniedException e) { + // database does not exist or permission denied + return ImmutableMap.of(); + } + catch (AmazonServiceException e) { + throw new TrinoException(HIVE_METASTORE_ERROR, e); + } + } + + @Override + public Optional> getRelationTypes() + { + return Optional.empty(); + } + @Override public List getTablesWithParameter(String databaseName, String parameterKey, String parameterValue) { diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/thrift/BridgingHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/thrift/BridgingHiveMetastore.java index d5926bb35155..bf015ef3af10 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/thrift/BridgingHiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/thrift/BridgingHiveMetastore.java @@ -34,6 +34,7 @@ import io.trino.plugin.hive.metastore.Table; import io.trino.plugin.hive.util.HiveUtil; import io.trino.spi.TrinoException; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaNotFoundException; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; @@ -146,6 +147,15 @@ public List getAllTables(String databaseName) return delegate.getAllTables(databaseName); } + @Override + public Map getRelationTypes(String databaseName) + { + ImmutableMap.Builder relationTypes = ImmutableMap.builder(); + getAllTables(databaseName).forEach(name -> relationTypes.put(name, RelationType.TABLE)); + getAllViews(databaseName).forEach(name -> relationTypes.put(name, RelationType.VIEW)); + return relationTypes.buildKeepingLast(); + } + @Override public List getTablesWithParameter(String databaseName, String parameterKey, String parameterValue) { @@ -164,6 +174,17 @@ public Optional> getAllTables() return delegate.getAllTables(); } + @Override + public Optional> getRelationTypes() + { + return getAllTables().flatMap(relations -> getAllViews().map(views -> { + ImmutableMap.Builder relationTypes = ImmutableMap.builder(); + relations.forEach(name -> relationTypes.put(name, RelationType.TABLE)); + views.forEach(name -> relationTypes.put(name, RelationType.VIEW)); + return relationTypes.buildKeepingLast(); + })); + } + @Override public Optional> getAllViews() { diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/tracing/TracingHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/tracing/TracingHiveMetastore.java index dea02fb2ffd1..c5d9fb8b95b8 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/tracing/TracingHiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/tracing/TracingHiveMetastore.java @@ -31,6 +31,7 @@ import io.trino.plugin.hive.metastore.PartitionWithStatistics; import io.trino.plugin.hive.metastore.PrincipalPrivileges; import io.trino.plugin.hive.metastore.Table; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.function.LanguageFunction; import io.trino.spi.predicate.TupleDomain; @@ -193,6 +194,31 @@ public Optional> getAllTables() }); } + @Override + public Map getRelationTypes(String databaseName) + { + Span span = tracer.spanBuilder("HiveMetastore.getRelationTypes") + .setAttribute(SCHEMA, databaseName) + .startSpan(); + return withTracing(span, () -> { + Map relationTypes = delegate.getRelationTypes(databaseName); + span.setAttribute(TABLE_RESPONSE_COUNT, relationTypes.size()); + return relationTypes; + }); + } + + @Override + public Optional> getRelationTypes() + { + Span span = tracer.spanBuilder("HiveMetastore.getRelations") + .startSpan(); + return withTracing(span, () -> { + Optional> relationTypes = delegate.getRelationTypes(); + relationTypes.ifPresent(map -> span.setAttribute(TABLE_RESPONSE_COUNT, map.size())); + return relationTypes; + }); + } + @Override public List getTablesWithParameter(String databaseName, String parameterKey, String parameterValue) { diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/CountingAccessHiveMetastore.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/CountingAccessHiveMetastore.java index 1630456391e6..a1737c3ad01f 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/CountingAccessHiveMetastore.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/CountingAccessHiveMetastore.java @@ -22,6 +22,7 @@ import io.trino.plugin.hive.PartitionStatistics; import io.trino.plugin.hive.acid.AcidTransaction; import io.trino.plugin.hive.metastore.HivePrivilegeInfo.HivePrivilege; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.function.LanguageFunction; import io.trino.spi.predicate.TupleDomain; @@ -35,8 +36,10 @@ import java.util.Set; import java.util.function.Function; +import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_ALL_RELATION_TYPES; import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_ALL_TABLES; import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_ALL_VIEWS; +import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_RELATION_TYPES_FROM_DATABASE; @ThreadSafe public class CountingAccessHiveMetastore @@ -52,6 +55,8 @@ public enum Method GET_TABLE, GET_ALL_TABLES, GET_ALL_TABLES_FROM_DATABASE, + GET_RELATION_TYPES_FROM_DATABASE, + GET_ALL_RELATION_TYPES, GET_TABLES_WITH_PARAMETER, GET_TABLE_STATISTICS, GET_ALL_VIEWS, @@ -371,6 +376,23 @@ public Optional> getAllTables() return allTables; } + @Override + public Map getRelationTypes(String databaseName) + { + methodInvocations.add(GET_RELATION_TYPES_FROM_DATABASE); + return delegate.getRelationTypes(databaseName); + } + + @Override + public Optional> getRelationTypes() + { + Optional> relationTypes = delegate.getRelationTypes(); + if (relationTypes.isPresent()) { + methodInvocations.add(GET_ALL_RELATION_TYPES); + } + return relationTypes; + } + @Override public boolean functionExists(String databaseName, String functionName, String signatureToken) { diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/UnimplementedHiveMetastore.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/UnimplementedHiveMetastore.java index cb7023359ce7..ca2fd5dba8c8 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/UnimplementedHiveMetastore.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/UnimplementedHiveMetastore.java @@ -18,6 +18,7 @@ import io.trino.plugin.hive.PartitionStatistics; import io.trino.plugin.hive.acid.AcidTransaction; import io.trino.plugin.hive.metastore.HivePrivilegeInfo.HivePrivilege; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.function.LanguageFunction; import io.trino.spi.predicate.TupleDomain; @@ -97,6 +98,18 @@ public Optional> getAllTables() throw new UnsupportedOperationException(); } + @Override + public Map getRelationTypes(String databaseName) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional> getRelationTypes() + { + throw new UnsupportedOperationException(); + } + @Override public List getTablesWithParameter(String databaseName, String parameterKey, String parameterValue) { diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestHiveGlueMetastore.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestGlueHiveMetastore.java similarity index 99% rename from plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestHiveGlueMetastore.java rename to plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestGlueHiveMetastore.java index 5ef50056585c..a81c4374cd45 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestHiveGlueMetastore.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestGlueHiveMetastore.java @@ -132,10 +132,10 @@ * See https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default * on ways to set your AWS credentials which will be needed to run this test. */ -public class TestHiveGlueMetastore +public class TestGlueHiveMetastore extends AbstractTestHiveLocal { - private static final Logger log = Logger.get(TestHiveGlueMetastore.class); + private static final Logger log = Logger.get(TestGlueHiveMetastore.class); private static final String PARTITION_KEY = "part_key_1"; private static final String PARTITION_KEY2 = "part_key_2"; @@ -191,7 +191,7 @@ public class TestHiveGlueMetastore private HiveMetastoreClosure metastore; private AWSGlueAsync glueClient; - public TestHiveGlueMetastore() + public TestGlueHiveMetastore() { super(TEST_DATABASE_NAME_PREFIX + randomUUID().toString().toLowerCase(ENGLISH).replace("-", "")); } diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/thrift/TestHiveMetastoreMetadataQueriesAccessOperations.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/thrift/TestHiveMetastoreMetadataQueriesAccessOperations.java index 9fa42c8e0c25..348f971f3229 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/thrift/TestHiveMetastoreMetadataQueriesAccessOperations.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/thrift/TestHiveMetastoreMetadataQueriesAccessOperations.java @@ -25,6 +25,7 @@ import io.trino.plugin.hive.metastore.CountingAccessHiveMetastoreUtil; import io.trino.plugin.hive.metastore.Table; import io.trino.plugin.hive.metastore.UnimplementedHiveMetastore; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.testing.AbstractTestQueryFramework; import io.trino.testing.DistributedQueryRunner; @@ -36,16 +37,20 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import java.util.stream.IntStream; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableMap.toImmutableMap; import static io.trino.plugin.hive.HiveStorageFormat.ORC; import static io.trino.plugin.hive.TableType.MANAGED_TABLE; import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_ALL_DATABASES; +import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_ALL_RELATION_TYPES; import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_ALL_TABLES; import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_ALL_TABLES_FROM_DATABASE; import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_ALL_VIEWS; import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_ALL_VIEWS_FROM_DATABASE; +import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_RELATION_TYPES_FROM_DATABASE; import static io.trino.plugin.hive.metastore.CountingAccessHiveMetastore.Method.GET_TABLE; import static io.trino.plugin.hive.metastore.StorageFormat.fromHiveStorageFormat; import static io.trino.testing.TestingSession.testSessionBuilder; @@ -123,8 +128,7 @@ public void testSelectTablesWithoutPredicate() mockMetastore.setAllTablesViewsImplemented(true); Multiset tables = ImmutableMultiset.builder() - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build(); assertMetastoreInvocations("SELECT * FROM information_schema.tables", tables); assertMetastoreInvocations("SELECT * FROM system.jdbc.tables", tables); @@ -132,8 +136,7 @@ public void testSelectTablesWithoutPredicate() mockMetastore.setAllTablesViewsImplemented(false); tables = ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .addCopies(GET_ALL_TABLES_FROM_DATABASE, TEST_SCHEMAS_COUNT) - .addCopies(GET_ALL_VIEWS_FROM_DATABASE, TEST_SCHEMAS_COUNT) + .addCopies(GET_RELATION_TYPES_FROM_DATABASE, TEST_SCHEMAS_COUNT) .build(); assertMetastoreInvocations("SELECT * FROM information_schema.tables", tables); assertMetastoreInvocations("SELECT * FROM system.jdbc.tables", tables); @@ -156,14 +159,12 @@ public void testSelectTablesWithFilterBySchema() assertMetastoreInvocations( "SELECT * FROM information_schema.tables WHERE table_schema = 'test_schema_0'", ImmutableMultiset.builder() - .add(GET_ALL_TABLES_FROM_DATABASE) - .add(GET_ALL_VIEWS_FROM_DATABASE) + .add(GET_RELATION_TYPES_FROM_DATABASE) .build()); assertMetastoreInvocations( "SELECT * FROM system.jdbc.tables WHERE table_schem = 'test_schema_0'", ImmutableMultiset.builder() - .add(GET_ALL_TABLES_FROM_DATABASE) - .add(GET_ALL_VIEWS_FROM_DATABASE) + .add(GET_RELATION_TYPES_FROM_DATABASE) .build()); } @@ -177,21 +178,18 @@ public void testSelectTablesWithLikeOverSchema() "SELECT * FROM information_schema.tables WHERE table_schema LIKE 'test%'", ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build()); assertMetastoreInvocations( "SELECT * FROM system.jdbc.tables WHERE table_schem LIKE 'test%'", ImmutableMultiset.builder() - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build()); mockMetastore.setAllTablesViewsImplemented(false); Multiset tables = ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .addCopies(GET_ALL_TABLES_FROM_DATABASE, TEST_SCHEMAS_COUNT) - .addCopies(GET_ALL_VIEWS_FROM_DATABASE, TEST_SCHEMAS_COUNT) + .addCopies(GET_RELATION_TYPES_FROM_DATABASE, TEST_SCHEMAS_COUNT) .build(); assertMetastoreInvocations("SELECT * FROM information_schema.tables WHERE table_schema LIKE 'test%'", tables); assertMetastoreInvocations("SELECT * FROM system.jdbc.tables WHERE table_schem LIKE 'test%'", tables); @@ -207,13 +205,11 @@ public void testSelectTablesWithFilterByTableName() "SELECT * FROM information_schema.tables WHERE table_name = 'test_table_0'", ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build()); Multiset tables = ImmutableMultiset.builder() - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build(); assertMetastoreInvocations("SELECT * FROM system.jdbc.tables WHERE table_name = 'test_table_0'", tables); assertMetastoreInvocations("SELECT * FROM system.jdbc.tables WHERE table_name LIKE 'test\\_table\\_0' ESCAPE '\\'", tables); @@ -222,8 +218,7 @@ public void testSelectTablesWithFilterByTableName() mockMetastore.setAllTablesViewsImplemented(false); tables = ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .addCopies(GET_ALL_TABLES_FROM_DATABASE, TEST_SCHEMAS_COUNT) - .addCopies(GET_ALL_VIEWS_FROM_DATABASE, TEST_SCHEMAS_COUNT) + .addCopies(GET_RELATION_TYPES_FROM_DATABASE, TEST_SCHEMAS_COUNT) .build(); assertMetastoreInvocations("SELECT * FROM information_schema.tables WHERE table_name = 'test_table_0'", tables); assertMetastoreInvocations("SELECT * FROM system.jdbc.tables WHERE table_name = 'test_table_0'", tables); @@ -241,21 +236,18 @@ public void testSelectTablesWithLikeOverTableName() "SELECT * FROM information_schema.tables WHERE table_name LIKE 'test%'", ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build()); assertMetastoreInvocations( "SELECT * FROM system.jdbc.tables WHERE table_name LIKE 'test%'", ImmutableMultiset.builder() - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build()); mockMetastore.setAllTablesViewsImplemented(false); Multiset tables = ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .addCopies(GET_ALL_TABLES_FROM_DATABASE, TEST_SCHEMAS_COUNT) - .addCopies(GET_ALL_VIEWS_FROM_DATABASE, TEST_SCHEMAS_COUNT) + .addCopies(GET_RELATION_TYPES_FROM_DATABASE, TEST_SCHEMAS_COUNT) .build(); assertMetastoreInvocations("SELECT * FROM information_schema.tables WHERE table_name LIKE 'test%'", tables); assertMetastoreInvocations("SELECT * FROM system.jdbc.tables WHERE table_name LIKE 'test%'", tables); @@ -271,8 +263,7 @@ public void testSelectViewsWithoutPredicate() assertMetastoreInvocations( "SELECT * FROM system.jdbc.tables WHERE table_type = 'VIEW'", ImmutableMultiset.builder() - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build()); mockMetastore.setAllTablesViewsImplemented(false); @@ -286,8 +277,7 @@ public void testSelectViewsWithoutPredicate() "SELECT * FROM system.jdbc.tables WHERE table_type = 'VIEW'", ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .addCopies(GET_ALL_TABLES_FROM_DATABASE, TEST_SCHEMAS_COUNT) - .addCopies(GET_ALL_VIEWS_FROM_DATABASE, TEST_SCHEMAS_COUNT) + .addCopies(GET_RELATION_TYPES_FROM_DATABASE, TEST_SCHEMAS_COUNT) .build()); } @@ -308,8 +298,7 @@ public void testSelectViewsWithFilterBySchema() assertMetastoreInvocations("SELECT * FROM information_schema.views WHERE table_schema = 'test_schema_0'", ImmutableMultiset.of(GET_ALL_VIEWS_FROM_DATABASE)); assertMetastoreInvocations("SELECT * FROM system.jdbc.tables WHERE table_type = 'VIEW' AND table_schem = 'test_schema_0'", ImmutableMultiset.builder() - .add(GET_ALL_TABLES_FROM_DATABASE) - .add(GET_ALL_VIEWS_FROM_DATABASE) + .add(GET_RELATION_TYPES_FROM_DATABASE) .build()); } @@ -328,8 +317,7 @@ public void testSelectViewsWithLikeOverSchema() assertMetastoreInvocations( "SELECT * FROM system.jdbc.tables WHERE table_type = 'VIEW' AND table_schem LIKE 'test%'", ImmutableMultiset.builder() - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build()); mockMetastore.setAllTablesViewsImplemented(false); @@ -343,8 +331,7 @@ public void testSelectViewsWithLikeOverSchema() "SELECT * FROM system.jdbc.tables WHERE table_type = 'VIEW' AND table_schem LIKE 'test%'", ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .addCopies(GET_ALL_TABLES_FROM_DATABASE, TEST_SCHEMAS_COUNT) - .addCopies(GET_ALL_VIEWS_FROM_DATABASE, TEST_SCHEMAS_COUNT) + .addCopies(GET_RELATION_TYPES_FROM_DATABASE, TEST_SCHEMAS_COUNT) .build()); } @@ -363,8 +350,7 @@ public void testSelectViewsWithFilterByTableName() assertMetastoreInvocations( "SELECT * FROM system.jdbc.tables WHERE table_type = 'VIEW' AND table_name = 'test_table_0'", ImmutableMultiset.builder() - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build()); mockMetastore.setAllTablesViewsImplemented(false); @@ -378,8 +364,7 @@ public void testSelectViewsWithFilterByTableName() "SELECT * FROM system.jdbc.tables WHERE table_type = 'VIEW' AND table_name = 'test_table_0'", ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .addCopies(GET_ALL_TABLES_FROM_DATABASE, TEST_SCHEMAS_COUNT) - .addCopies(GET_ALL_VIEWS_FROM_DATABASE, TEST_SCHEMAS_COUNT) + .addCopies(GET_RELATION_TYPES_FROM_DATABASE, TEST_SCHEMAS_COUNT) .build()); } @@ -398,8 +383,7 @@ public void testSelectViewsWithLikeOverTableName() assertMetastoreInvocations( "SELECT * FROM system.jdbc.tables WHERE table_type = 'VIEW' AND table_name LIKE 'test%'", ImmutableMultiset.builder() - .add(GET_ALL_TABLES) - .add(GET_ALL_VIEWS) + .add(GET_ALL_RELATION_TYPES) .build()); mockMetastore.setAllTablesViewsImplemented(false); @@ -413,8 +397,7 @@ public void testSelectViewsWithLikeOverTableName() "SELECT * FROM system.jdbc.tables WHERE table_type = 'VIEW' AND table_name LIKE 'test%'", ImmutableMultiset.builder() .add(GET_ALL_DATABASES) - .addCopies(GET_ALL_TABLES_FROM_DATABASE, TEST_SCHEMAS_COUNT) - .addCopies(GET_ALL_VIEWS_FROM_DATABASE, TEST_SCHEMAS_COUNT) + .addCopies(GET_RELATION_TYPES_FROM_DATABASE, TEST_SCHEMAS_COUNT) .build()); } @@ -769,6 +752,23 @@ public Optional> getAllTables() return Optional.empty(); } + @Override + public Map getRelationTypes(String databaseName) + { + return TABLES_PER_SCHEMA.stream() + .collect(toImmutableMap(Function.identity(), ignore -> RelationType.TABLE)); + } + + @Override + public Optional> getRelationTypes() + { + if (allTablesViewsImplemented) { + return Optional.of(ALL_TABLES.stream() + .collect(toImmutableMap(Function.identity(), ignore -> RelationType.TABLE))); + } + return Optional.empty(); + } + @Override public List getAllViews(String databaseName) { 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 41cd8c7bdd93..4f69e72796b5 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 @@ -80,6 +80,7 @@ import io.trino.spi.connector.ProjectionApplicationResult; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.RetryMode; import io.trino.spi.connector.RowChangeParadigm; import io.trino.spi.connector.SaveMode; @@ -685,6 +686,12 @@ public List listTables(ConnectorSession session, Optional getRelationTypes(ConnectorSession session, Optional schemaName) + { + return catalog.getRelationTypes(session, schemaName); + } + @Override public Map getColumnHandles(ConnectorSession session, ConnectorTableHandle tableHandle) { 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 05ca9a5a6739..8d44190ee307 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 @@ -22,6 +22,7 @@ import io.trino.spi.connector.ConnectorViewDefinition; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.security.TrinoPrincipal; import org.apache.iceberg.BaseTable; @@ -75,6 +76,8 @@ public interface TrinoCatalog List listTables(ConnectorSession session, Optional namespace); + Map getRelationTypes(ConnectorSession session, Optional namespace); + Optional> streamRelationColumns( ConnectorSession session, Optional namespace, 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 6761c555c00c..b07c2cb90d0a 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 @@ -34,6 +34,7 @@ import com.amazonaws.services.glue.model.TableInput; import com.amazonaws.services.glue.model.UpdateTableRequest; import com.google.common.cache.Cache; +import com.google.common.collect.AbstractIterator; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.UncheckedExecutionException; @@ -66,6 +67,7 @@ import io.trino.spi.connector.MaterializedViewNotFoundException; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaNotFoundException; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; @@ -92,6 +94,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -107,7 +110,9 @@ import static com.google.common.base.Throwables.throwIfUnchecked; import static com.google.common.base.Verify.verify; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableMap.toImmutableMap; import static com.google.common.collect.ImmutableSet.toImmutableSet; +import static com.google.common.collect.Streams.stream; import static io.trino.cache.CacheUtils.uncheckedCacheGet; import static io.trino.filesystem.Locations.appendPath; import static io.trino.plugin.hive.HiveErrorCode.HIVE_DATABASE_LOCATION_ERROR; @@ -156,6 +161,7 @@ import static java.lang.Boolean.parseBoolean; import static java.lang.String.format; import static java.util.Locale.ENGLISH; +import static java.util.Map.entry; import static java.util.Objects.requireNonNull; import static org.apache.iceberg.BaseMetastoreTableOperations.METADATA_LOCATION_PROP; import static org.apache.iceberg.CatalogUtil.dropTableData; @@ -358,25 +364,16 @@ public void renameNamespace(ConnectorSession session, String source, String targ @Override public List listTables(ConnectorSession session, Optional namespace) { - ImmutableList.Builder tables = ImmutableList.builder(); - try { - List namespaces = listNamespaces(session, namespace); - for (String glueNamespace : namespaces) { - try { - // Add all tables from a namespace together, in case it is removed while fetching paginated results - tables.addAll(getGlueTables(glueNamespace) - .map(table -> new SchemaTableName(glueNamespace, table.getName())) - .collect(toImmutableList())); - } - catch (EntityNotFoundException | AccessDeniedException e) { - // Namespace may have been deleted or permission denied - } - } - } - catch (AmazonServiceException e) { - throw new TrinoException(ICEBERG_CATALOG_ERROR, e); - } - return tables.build(); + return listRelations(session, namespace) + .map(Entry::getKey) + .collect(toImmutableList()); + } + + @Override + public Map getRelationTypes(ConnectorSession session, Optional namespace) + { + return listRelations(session, namespace) + .collect(toImmutableMap(Entry::getKey, Entry::getValue)); } @Override @@ -392,7 +389,7 @@ public Optional> streamRelationColumns( listNamespaces(session, namespace).stream() .flatMap(glueNamespace -> getGlueTables(glueNamespace) - .map(table -> Map.entry(new SchemaTableName(glueNamespace, table.getName()), table))) + .map(table -> entry(new SchemaTableName(glueNamespace, table.getName()), table))) .forEach(entry -> { SchemaTableName name = entry.getKey(); com.amazonaws.services.glue.model.Table table = entry.getValue(); @@ -484,7 +481,7 @@ public Optional> streamRelationComments( listNamespaces(session, namespace).stream() .flatMap(glueNamespace -> getGlueTables(glueNamespace) - .map(table -> Map.entry(new SchemaTableName(glueNamespace, table.getName()), table))) + .map(table -> entry(new SchemaTableName(glueNamespace, table.getName()), table))) .forEach(entry -> { SchemaTableName name = entry.getKey(); com.amazonaws.services.glue.model.Table table = entry.getValue(); @@ -1029,25 +1026,10 @@ public void dropView(ConnectorSession session, SchemaTableName schemaViewName) @Override public List listViews(ConnectorSession session, Optional namespace) { - ImmutableList.Builder views = ImmutableList.builder(); - try { - List namespaces = listNamespaces(session, namespace); - for (String glueNamespace : namespaces) { - try { - views.addAll(getGlueTables(glueNamespace) - .filter(table -> isTrinoView(getTableType(table), getTableParameters(table))) - .map(table -> new SchemaTableName(glueNamespace, table.getName())) - .collect(toImmutableList())); - } - catch (EntityNotFoundException | AccessDeniedException e) { - // Namespace may have been deleted or permission denied - } - } - } - catch (AmazonServiceException e) { - throw new TrinoException(ICEBERG_CATALOG_ERROR, e); - } - return views.build(); + return listRelations(session, namespace) + .filter(entry -> entry.getValue() == RelationType.VIEW) + .map(Entry::getKey) + .collect(toImmutableList()); } @Override @@ -1132,25 +1114,10 @@ private void updateView(ConnectorSession session, SchemaTableName viewName, Conn @Override public List listMaterializedViews(ConnectorSession session, Optional namespace) { - ImmutableList.Builder materializedViews = ImmutableList.builder(); - try { - List namespaces = listNamespaces(session, namespace); - for (String glueNamespace : namespaces) { - try { - materializedViews.addAll(getGlueTables(glueNamespace) - .filter(table -> isTrinoMaterializedView(getTableType(table), getTableParameters(table))) - .map(table -> new SchemaTableName(glueNamespace, table.getName())) - .collect(toImmutableList())); - } - catch (EntityNotFoundException | AccessDeniedException e) { - // Namespace may have been deleted or permission denied - } - } - } - catch (AmazonServiceException e) { - throw new TrinoException(ICEBERG_CATALOG_ERROR, e); - } - return materializedViews.build(); + return listRelations(session, namespace) + .filter(entry -> entry.getValue() == RelationType.MATERIALIZED_VIEW) + .map(Entry::getKey) + .collect(toImmutableList()); } @Override @@ -1543,6 +1510,68 @@ com.amazonaws.services.glue.model.Table getTable(SchemaTableName tableName, bool } } + private Stream> listRelations(ConnectorSession session, Optional namespace) + { + List namespaces = listNamespaces(session, namespace); + return namespaces.stream() + .flatMap(glueNamespace -> getGlueTablesWithExceptionHandling(glueNamespace) + .map(table -> { + String tableType = getTableType(table); + Map tableParameters = getTableParameters(table); + RelationType relationType; + if (isTrinoView(tableType, tableParameters)) { + relationType = RelationType.VIEW; + } + else if (isTrinoMaterializedView(tableType, tableParameters)) { + relationType = RelationType.MATERIALIZED_VIEW; + } + else { + relationType = RelationType.TABLE; + } + + return entry(new SchemaTableName(glueNamespace, table.getName()), relationType); + })); + } + + private Stream getGlueTablesWithExceptionHandling(String glueNamespace) + { + return stream(new AbstractIterator<>() + { + private Iterator delegate; + + @Override + protected com.amazonaws.services.glue.model.Table computeNext() + { + boolean firstCall = (delegate == null); + try { + if (delegate == null) { + delegate = getGlueTables(glueNamespace) + .iterator(); + } + + if (!delegate.hasNext()) { + return endOfData(); + } + return delegate.next(); + } + catch (EntityNotFoundException e) { + // database does not exist or deleted during iteration + return endOfData(); + } + catch (AccessDeniedException e) { + // permission denied may actually mean "does not exist" + if (!firstCall) { + LOG.warn(e, "Permission denied when getting next batch of tables from namespace %s", glueNamespace); + } + return endOfData(); + } + catch (AmazonServiceException e) { + throw new TrinoException(ICEBERG_CATALOG_ERROR, e); + } + } + }); + } + private Stream getGlueTables(String glueNamespace) { return getPaginatedResults( 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 a0a02eb6b1ee..5e29362ed6f9 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 @@ -49,6 +49,7 @@ import io.trino.spi.connector.MaterializedViewNotFoundException; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaNotFoundException; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; @@ -119,6 +120,8 @@ import static java.lang.String.format; import static java.util.Locale.ENGLISH; import static java.util.Objects.requireNonNull; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; import static org.apache.iceberg.BaseMetastoreTableOperations.ICEBERG_TABLE_TYPE_VALUE; import static org.apache.iceberg.BaseMetastoreTableOperations.METADATA_LOCATION_PROP; import static org.apache.iceberg.BaseMetastoreTableOperations.TABLE_TYPE_PROP; @@ -385,6 +388,26 @@ public List listTables(ConnectorSession session, Optional getRelationTypes(ConnectorSession session, Optional namespace) + { + Set materializedViews = ImmutableSet.copyOf(listMaterializedViews(session, namespace)); + Set views = ImmutableSet.copyOf(listViews(session, namespace)); + + return listTables(session, namespace).stream() + .collect(toMap( + identity(), + relation -> { + if (materializedViews.contains(relation)) { + return RelationType.MATERIALIZED_VIEW; + } + if (views.contains(relation)) { + return RelationType.VIEW; + } + return RelationType.TABLE; + })); + } + @Override public Optional> streamRelationColumns( ConnectorSession session, 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 fae4f5507cb1..86a8d3191e9a 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 @@ -32,6 +32,7 @@ import io.trino.spi.connector.ConnectorViewDefinition; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; import io.trino.spi.security.TrinoPrincipal; @@ -57,6 +58,7 @@ import java.util.function.UnaryOperator; import static com.google.common.base.Throwables.throwIfUnchecked; +import static com.google.common.base.Verify.verify; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; import static com.google.common.collect.Maps.transformValues; @@ -72,6 +74,7 @@ import static java.lang.String.format; import static java.util.Locale.ENGLISH; import static java.util.Objects.requireNonNull; +import static java.util.function.Function.identity; import static org.apache.iceberg.CatalogUtil.dropTableData; public class TrinoJdbcCatalog @@ -180,6 +183,16 @@ public List listTables(ConnectorSession session, Optional getRelationTypes(ConnectorSession session, Optional namespace) + { + // views and materialized views are currently not supported + verify(listViews(session, namespace).isEmpty(), "Unexpected views support"); + verify(listMaterializedViews(session, namespace).isEmpty(), "Unexpected views support"); + return listTables(session, namespace).stream() + .collect(toImmutableMap(identity(), ignore -> RelationType.TABLE)); + } + @Override public Optional> streamRelationColumns( ConnectorSession session, 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 ab0a40a3ef9a..361c2cfd6986 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 @@ -31,6 +31,7 @@ import io.trino.spi.connector.ConnectorViewDefinition; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaNotFoundException; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.security.TrinoPrincipal; @@ -56,7 +57,9 @@ import java.util.function.UnaryOperator; import static com.google.common.base.Throwables.throwIfUnchecked; +import static com.google.common.base.Verify.verify; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableMap.toImmutableMap; import static io.trino.cache.CacheUtils.uncheckedCacheGet; import static io.trino.filesystem.Locations.appendPath; import static io.trino.plugin.iceberg.IcebergSchemaProperties.LOCATION_PROPERTY; @@ -67,6 +70,7 @@ import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED; import static io.trino.spi.connector.SchemaTableName.schemaTableName; import static java.util.Objects.requireNonNull; +import static java.util.function.Function.identity; public class TrinoNessieCatalog extends AbstractTrinoCatalog @@ -170,6 +174,16 @@ public List listTables(ConnectorSession session, Optional getRelationTypes(ConnectorSession session, Optional namespace) + { + // views and materialized views are currently not supported + verify(listViews(session, namespace).isEmpty(), "Unexpected views support"); + verify(listMaterializedViews(session, namespace).isEmpty(), "Unexpected views support"); + return listTables(session, namespace).stream() + .collect(toImmutableMap(identity(), ignore -> RelationType.TABLE)); + } + @Override public Optional> streamRelationColumns( ConnectorSession session, 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 9357a08c158a..74d296d574ed 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 @@ -34,6 +34,7 @@ import io.trino.spi.connector.ConnectorViewDefinition; import io.trino.spi.connector.RelationColumnsMetadata; import io.trino.spi.connector.RelationCommentMetadata; +import io.trino.spi.connector.RelationType; import io.trino.spi.connector.SchemaNotFoundException; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; @@ -65,7 +66,9 @@ import java.util.function.UnaryOperator; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Verify.verify; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableMap.toImmutableMap; import static io.trino.cache.CacheUtils.uncheckedCacheGet; import static io.trino.filesystem.Locations.appendPath; import static io.trino.plugin.hive.HiveMetadata.TABLE_COMMENT; @@ -75,6 +78,7 @@ import static java.lang.String.format; import static java.util.Objects.requireNonNull; import static java.util.UUID.randomUUID; +import static java.util.function.Function.identity; public class TrinoRestCatalog implements TrinoCatalog @@ -205,6 +209,16 @@ public List listTables(ConnectorSession session, Optional getRelationTypes(ConnectorSession session, Optional namespace) + { + // views and materialized views are currently not supported + verify(listViews(session, namespace).isEmpty(), "Unexpected views support"); + verify(listMaterializedViews(session, namespace).isEmpty(), "Unexpected views support"); + return listTables(session, namespace).stream() + .collect(toImmutableMap(identity(), ignore -> RelationType.TABLE)); + } + @Override public Optional> streamRelationColumns( ConnectorSession session, diff --git a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/glue/TestIcebergGlueCatalogAccessOperations.java b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/glue/TestIcebergGlueCatalogAccessOperations.java index 42ff3e2a441f..4b1ec1908c47 100644 --- a/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/glue/TestIcebergGlueCatalogAccessOperations.java +++ b/plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/catalog/glue/TestIcebergGlueCatalogAccessOperations.java @@ -458,7 +458,7 @@ public void testSelectSystemTable() } @Test - public void testInformationSchemaColumns() + public void testInformationSchemaTableAndColumns() { String schemaName = "test_i_s_columns_schema" + randomNameSuffix(); assertUpdate("CREATE SCHEMA " + schemaName); @@ -483,7 +483,7 @@ public void testInformationSchemaColumns() assertUpdate(session, "CREATE TABLE test_other_select_i_s_columns" + i + "(id varchar, age integer)"); // won't match the filter } - // Bulk retrieval + // Bulk columns retrieval assertInvocations( session, "SELECT * FROM information_schema.columns WHERE table_schema = CURRENT_SCHEMA AND table_name LIKE 'test_select_i_s_columns%'", @@ -493,7 +493,16 @@ public void testInformationSchemaColumns() ImmutableMultiset.of()); } - // Pointed lookup + // Tables listing + assertInvocations( + session, + "SELECT * FROM information_schema.tables WHERE table_schema = CURRENT_SCHEMA", + ImmutableMultiset.builder() + .add(GET_TABLES) + .build(), + ImmutableMultiset.of()); + + // Pointed columns lookup assertInvocations( session, "SELECT * FROM information_schema.columns WHERE table_schema = CURRENT_SCHEMA AND table_name = 'test_select_i_s_columns0'", @@ -504,7 +513,7 @@ public void testInformationSchemaColumns() .add(new FileOperation(METADATA_JSON, INPUT_FILE_NEW_STREAM)) .build()); - // Pointed lookup via DESCRIBE (which does some additional things before delegating to information_schema.columns) + // Pointed columns lookup via DESCRIBE (which does some additional things before delegating to information_schema.columns) assertInvocations( session, "DESCRIBE test_select_i_s_columns0", diff --git a/testing/trino-tests/src/test/java/io/trino/connector/informationschema/TestInformationSchemaConnector.java b/testing/trino-tests/src/test/java/io/trino/connector/informationschema/TestInformationSchemaConnector.java index 167dbe40d7b5..18e23395d0c0 100644 --- a/testing/trino-tests/src/test/java/io/trino/connector/informationschema/TestInformationSchemaConnector.java +++ b/testing/trino-tests/src/test/java/io/trino/connector/informationschema/TestInformationSchemaConnector.java @@ -175,32 +175,27 @@ public void testMetadataCalls() "SELECT count(table_name), count(table_type) from test_catalog.information_schema.tables", "VALUES (3008, 3008)", ImmutableMultiset.builder() - .add("ConnectorMetadata.listTables") - .add("ConnectorMetadata.listViews") + .add("ConnectorMetadata.getRelationTypes") .build()); assertMetadataCalls( "SELECT count(table_name), count(table_type) from test_catalog.information_schema.tables WHERE table_schema = 'test_schema1'", "VALUES (1000, 1000)", ImmutableMultiset.builder() - .add("ConnectorMetadata.listTables(schema=test_schema1)") - .add("ConnectorMetadata.listViews(schema=test_schema1)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema1)") .build()); assertMetadataCalls( "SELECT count(table_name), count(table_type) from test_catalog.information_schema.tables WHERE table_schema LIKE 'test_sch_ma1'", "VALUES (1000, 1000)", ImmutableMultiset.builder() .add("ConnectorMetadata.listSchemaNames") - .add("ConnectorMetadata.listTables(schema=test_schema1)") - .add("ConnectorMetadata.listViews(schema=test_schema1)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema1)") .build()); assertMetadataCalls( "SELECT count(table_name), count(table_type) from test_catalog.information_schema.tables WHERE table_schema LIKE 'test_sch_ma1' AND table_schema IN ('test_schema1', 'test_schema2')", "VALUES (1000, 1000)", ImmutableMultiset.builder() - .add("ConnectorMetadata.listTables(schema=test_schema1)") - .add("ConnectorMetadata.listViews(schema=test_schema1)") - .add("ConnectorMetadata.listTables(schema=test_schema2)") - .add("ConnectorMetadata.listViews(schema=test_schema2)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema1)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema2)") .build()); assertMetadataCalls( "SELECT count(table_name), count(table_type) from test_catalog.information_schema.tables WHERE table_schema IN " + @@ -212,26 +207,25 @@ public void testMetadataCalls() .collect(joining(",", "(", ")")), "VALUES (3000, 3000)", ImmutableMultiset.builder() - .add("ConnectorMetadata.listTables") - .add("ConnectorMetadata.listViews") + .add("ConnectorMetadata.getRelationTypes") .build()); assertMetadataCalls( "SELECT count(table_name), count(table_type) from test_catalog.information_schema.tables WHERE table_name = 'test_table1'", "VALUES (2, 2)", ImmutableMultiset.builder() .add("ConnectorMetadata.listSchemaNames") - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table1)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema2, table=test_table1)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema3_empty, table=test_table1)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema4_empty, table=test_table1)", 5) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table1)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema2, table=test_table1)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema3_empty, table=test_table1)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema4_empty, table=test_table1)", 4) .add("ConnectorMetadata.getMaterializedView(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.getMaterializedView(schema=test_schema2, table=test_table1)") .add("ConnectorMetadata.getMaterializedView(schema=test_schema3_empty, table=test_table1)") .add("ConnectorMetadata.getMaterializedView(schema=test_schema4_empty, table=test_table1)") - .addCopies("ConnectorMetadata.getView(schema=test_schema1, table=test_table1)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema2, table=test_table1)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema3_empty, table=test_table1)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema4_empty, table=test_table1)", 2) + .add("ConnectorMetadata.getView(schema=test_schema1, table=test_table1)") + .add("ConnectorMetadata.getView(schema=test_schema2, table=test_table1)") + .add("ConnectorMetadata.getView(schema=test_schema3_empty, table=test_table1)") + .add("ConnectorMetadata.getView(schema=test_schema4_empty, table=test_table1)") .add("ConnectorMetadata.redirectTable(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.redirectTable(schema=test_schema2, table=test_table1)") .add("ConnectorMetadata.redirectTable(schema=test_schema3_empty, table=test_table1)") @@ -246,28 +240,24 @@ public void testMetadataCalls() "VALUES (2, 2)", ImmutableMultiset.builder() .add("ConnectorMetadata.listSchemaNames") - .add("ConnectorMetadata.listTables(schema=test_schema1)") - .add("ConnectorMetadata.listTables(schema=test_schema2)") - .add("ConnectorMetadata.listTables(schema=test_schema3_empty)") - .add("ConnectorMetadata.listTables(schema=test_schema4_empty)") - .add("ConnectorMetadata.listViews(schema=test_schema1)") - .add("ConnectorMetadata.listViews(schema=test_schema2)") - .add("ConnectorMetadata.listViews(schema=test_schema3_empty)") - .add("ConnectorMetadata.listViews(schema=test_schema4_empty)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema1)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema2)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema3_empty)") + .add("ConnectorMetadata.getRelationTypes(schema=test_schema4_empty)") .build()); assertMetadataCalls( "SELECT count(table_name), count(table_type) from test_catalog.information_schema.tables WHERE table_name LIKE 'test_t_ble1' AND table_name IN ('test_table1', 'test_table2')", "VALUES (2, 2)", ImmutableMultiset.builder() .add("ConnectorMetadata.listSchemaNames") - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table1)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table2)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema2, table=test_table1)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema2, table=test_table2)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema3_empty, table=test_table1)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema3_empty, table=test_table2)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema4_empty, table=test_table1)", 5) - .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema4_empty, table=test_table2)", 5) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table1)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema1, table=test_table2)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema2, table=test_table1)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema2, table=test_table2)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema3_empty, table=test_table1)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema3_empty, table=test_table2)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema4_empty, table=test_table1)", 4) + .addCopies("ConnectorMetadata.getSystemTable(schema=test_schema4_empty, table=test_table2)", 4) .add("ConnectorMetadata.getMaterializedView(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.getMaterializedView(schema=test_schema1, table=test_table2)") .add("ConnectorMetadata.getMaterializedView(schema=test_schema2, table=test_table2)") @@ -276,14 +266,14 @@ public void testMetadataCalls() .add("ConnectorMetadata.getMaterializedView(schema=test_schema3_empty, table=test_table1)") .add("ConnectorMetadata.getMaterializedView(schema=test_schema4_empty, table=test_table2)") .add("ConnectorMetadata.getMaterializedView(schema=test_schema4_empty, table=test_table1)") - .addCopies("ConnectorMetadata.getView(schema=test_schema1, table=test_table1)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema1, table=test_table2)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema2, table=test_table1)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema2, table=test_table2)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema3_empty, table=test_table1)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema3_empty, table=test_table2)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema4_empty, table=test_table1)", 2) - .addCopies("ConnectorMetadata.getView(schema=test_schema4_empty, table=test_table2)", 2) + .add("ConnectorMetadata.getView(schema=test_schema1, table=test_table1)") + .add("ConnectorMetadata.getView(schema=test_schema1, table=test_table2)") + .add("ConnectorMetadata.getView(schema=test_schema2, table=test_table1)") + .add("ConnectorMetadata.getView(schema=test_schema2, table=test_table2)") + .add("ConnectorMetadata.getView(schema=test_schema3_empty, table=test_table1)") + .add("ConnectorMetadata.getView(schema=test_schema3_empty, table=test_table2)") + .add("ConnectorMetadata.getView(schema=test_schema4_empty, table=test_table1)") + .add("ConnectorMetadata.getView(schema=test_schema4_empty, table=test_table2)") .add("ConnectorMetadata.redirectTable(schema=test_schema1, table=test_table1)") .add("ConnectorMetadata.redirectTable(schema=test_schema1, table=test_table2)") .add("ConnectorMetadata.redirectTable(schema=test_schema2, table=test_table1)")