diff --git a/presto-main/src/main/java/io/prestosql/connector/informationschema/InformationSchemaMetadata.java b/presto-main/src/main/java/io/prestosql/connector/informationschema/InformationSchemaMetadata.java index a4551251228fd..ad0cd2ea156c3 100644 --- a/presto-main/src/main/java/io/prestosql/connector/informationschema/InformationSchemaMetadata.java +++ b/presto-main/src/main/java/io/prestosql/connector/informationschema/InformationSchemaMetadata.java @@ -290,9 +290,10 @@ private Set getPrefixes(ConnectorSession session, Informat return ImmutableSet.of(); } + SchemaTableName schemaTableName = handle.getSchemaTableName(); Set prefixes = calculatePrefixesWithSchemaName(session, constraint.getSummary(), constraint.predicate()); if (isTablesEnumeratingTable(handle.getSchemaTableName())) { - Set tablePrefixes = calculatePrefixesWithTableName(session, prefixes, constraint.getSummary(), constraint.predicate()); + Set tablePrefixes = calculatePrefixesWithTableName(schemaTableName, session, prefixes, constraint.getSummary(), constraint.predicate()); // in case of high number of prefixes it is better to populate all data and then filter if (tablePrefixes.size() <= MAX_PREFIXES_COUNT) { prefixes = tablePrefixes; @@ -332,6 +333,7 @@ private Set calculatePrefixesWithSchemaName( } public Set calculatePrefixesWithTableName( + SchemaTableName schemaTableName, ConnectorSession connectorSession, Set prefixes, TupleDomain constraint, @@ -346,23 +348,28 @@ public Set calculatePrefixesWithTableName( .filter(this::isLowerCase) .map(table -> table.toLowerCase(ENGLISH)) .map(table -> new QualifiedObjectName(catalogName, prefix.getSchemaName().get(), table))) - .filter(objectName -> metadata.getTableHandle(session, objectName).isPresent() || metadata.getView(session, objectName).isPresent()) + .filter(objectName -> !isColumnsEnumeratingTable(schemaTableName) || metadata.getTableHandle(session, objectName).isPresent() || metadata.getView(session, objectName).isPresent()) .filter(objectName -> !predicate.isPresent() || predicate.get().test(asFixedValues(objectName))) .map(QualifiedObjectName::asQualifiedTablePrefix) .collect(toImmutableSet()); } - if (predicate.isPresent()) { - return prefixes.stream() - .flatMap(prefix -> Stream.concat( - metadata.listTables(session, prefix).stream(), - metadata.listViews(session, prefix).stream())) - .filter(objectName -> predicate.get().test(asFixedValues(objectName))) - .map(QualifiedObjectName::asQualifiedTablePrefix) - .collect(toImmutableSet()); + if (!predicate.isPresent() || !isColumnsEnumeratingTable(schemaTableName)) { + return prefixes; } - return prefixes; + return prefixes.stream() + .flatMap(prefix -> Stream.concat( + metadata.listTables(session, prefix).stream(), + metadata.listViews(session, prefix).stream())) + .filter(objectName -> predicate.get().test(asFixedValues(objectName))) + .map(QualifiedObjectName::asQualifiedTablePrefix) + .collect(toImmutableSet()); + } + + private boolean isColumnsEnumeratingTable(SchemaTableName schemaTableName) + { + return TABLE_COLUMNS.equals(schemaTableName); } private Stream listSchemaNames(Session session) diff --git a/presto-main/src/test/java/io/prestosql/metadata/TestInformationSchemaMetadata.java b/presto-main/src/test/java/io/prestosql/metadata/TestInformationSchemaMetadata.java index 4867af75ce1e4..cdd67013f9bcf 100644 --- a/presto-main/src/test/java/io/prestosql/metadata/TestInformationSchemaMetadata.java +++ b/presto-main/src/test/java/io/prestosql/metadata/TestInformationSchemaMetadata.java @@ -42,6 +42,7 @@ import io.prestosql.transaction.TransactionManager; import org.testng.annotations.Test; +import java.util.Map; import java.util.Optional; import static com.google.common.collect.ImmutableSet.toImmutableSet; @@ -123,30 +124,12 @@ public void testInformationSchemaPredicatePushdown() public void testInformationSchemaPredicatePushdownWithConstraintPredicate() { TransactionId transactionId = transactionManager.beginTransaction(false); - Constraint constraint = new Constraint( - TupleDomain.all(), - // test_schema has a table named "another_table" and we filter that out in this predicate - bindings -> { - NullableValue catalog = bindings.get(new InformationSchemaColumnHandle("table_catalog")); - NullableValue schema = bindings.get(new InformationSchemaColumnHandle("table_schema")); - NullableValue table = bindings.get(new InformationSchemaColumnHandle("table_name")); - boolean isValid = true; - if (catalog != null) { - isValid = ((Slice) catalog.getValue()).toStringUtf8().equals("test_catalog"); - } - if (schema != null) { - isValid &= ((Slice) schema.getValue()).toStringUtf8().equals("test_schema"); - } - if (table != null) { - isValid &= ((Slice) table.getValue()).toStringUtf8().equals("test_view"); - } - return isValid; - }); + Constraint constraint = new Constraint(TupleDomain.all(), TestInformationSchemaMetadata::testConstraint); ConnectorSession session = createNewSession(transactionId); ConnectorMetadata metadata = new InformationSchemaMetadata("test_catalog", this.metadata); InformationSchemaTableHandle tableHandle = (InformationSchemaTableHandle) - metadata.getTableHandle(session, new SchemaTableName("information_schema", "views")); + metadata.getTableHandle(session, new SchemaTableName("information_schema", "columns")); tableHandle = metadata.applyFilter(session, tableHandle, constraint) .map(ConstraintApplicationResult::getHandle) .map(InformationSchemaTableHandle.class::cast) @@ -176,6 +159,44 @@ public void testInformationSchemaPredicatePushdownWithoutTablePredicate() assertEquals(tableHandle.getPrefixes(), ImmutableSet.of(new QualifiedTablePrefix("test_catalog", "test_schema"))); } + @Test + public void testInformationSchemaPredicatePushdownWithConstraintPredicateOnViewsTable() + { + TransactionId transactionId = transactionManager.beginTransaction(false); + + // predicate on non columns enumerating table should not cause tables to be enumerated + Constraint constraint = new Constraint(TupleDomain.all(), TestInformationSchemaMetadata::testConstraint); + ConnectorSession session = createNewSession(transactionId); + ConnectorMetadata metadata = new InformationSchemaMetadata("test_catalog", this.metadata); + InformationSchemaTableHandle tableHandle = (InformationSchemaTableHandle) + metadata.getTableHandle(session, new SchemaTableName("information_schema", "views")); + tableHandle = metadata.applyFilter(session, tableHandle, constraint) + .map(ConstraintApplicationResult::getHandle) + .map(InformationSchemaTableHandle.class::cast) + .orElseThrow(AssertionError::new); + + assertEquals(tableHandle.getPrefixes(), ImmutableSet.of(new QualifiedTablePrefix("test_catalog", "test_schema"))); + } + + private static boolean testConstraint(Map bindings) + { + // test_schema has a table named "another_table" and we filter that out in this predicate + NullableValue catalog = bindings.get(new InformationSchemaColumnHandle("table_catalog")); + NullableValue schema = bindings.get(new InformationSchemaColumnHandle("table_schema")); + NullableValue table = bindings.get(new InformationSchemaColumnHandle("table_name")); + boolean isValid = true; + if (catalog != null) { + isValid = ((Slice) catalog.getValue()).toStringUtf8().equals("test_catalog"); + } + if (schema != null) { + isValid &= ((Slice) schema.getValue()).toStringUtf8().equals("test_schema"); + } + if (table != null) { + isValid &= ((Slice) table.getValue()).toStringUtf8().equals("test_view"); + } + return isValid; + } + private static ConnectorSession createNewSession(TransactionId transactionId) { return testSessionBuilder() diff --git a/presto-tests/src/test/java/io/prestosql/tests/TestInformationSchemaConnector.java b/presto-tests/src/test/java/io/prestosql/tests/TestInformationSchemaConnector.java index c993f1f48c22a..e04edbac02683 100644 --- a/presto-tests/src/test/java/io/prestosql/tests/TestInformationSchemaConnector.java +++ b/presto-tests/src/test/java/io/prestosql/tests/TestInformationSchemaConnector.java @@ -113,7 +113,7 @@ public void testLargeData() assertQuery("SELECT count(*) from test_catalog.information_schema.tables WHERE table_name LIKE 'test_t_ble1'", "VALUES 2"); assertQuery("SELECT count(*) from test_catalog.information_schema.tables WHERE table_name LIKE 'test_t_ble1' AND table_name IN ('test_table1', 'test_table2')", "VALUES 2"); assertQuery("SELECT count(*) from test_catalog.information_schema.columns WHERE table_schema = 'test_schema1' AND table_name = 'test_table1'", "VALUES 100"); - assertEquals(METADATA_CALLS_COUNTER.get() - metadataCallsCountBeforeTests, 30); + assertEquals(METADATA_CALLS_COUNTER.get() - metadataCallsCountBeforeTests, 29); } private static DistributedQueryRunner createQueryRunner()