Search in sources :

Example 26 with PlanMatchPattern

use of io.trino.sql.planner.assertions.PlanMatchPattern in project trino by trinodb.

the class BaseJdbcConnectorTest method testJoinPushdown.

@Test
public void testJoinPushdown() {
    PlanMatchPattern joinOverTableScans = node(JoinNode.class, anyTree(node(TableScanNode.class)), anyTree(node(TableScanNode.class)));
    PlanMatchPattern broadcastJoinOverTableScans = node(JoinNode.class, node(TableScanNode.class), exchange(ExchangeNode.Scope.LOCAL, exchange(ExchangeNode.Scope.REMOTE, ExchangeNode.Type.REPLICATE, node(TableScanNode.class))));
    Session session = joinPushdownEnabled(getSession());
    if (!hasBehavior(SUPPORTS_JOIN_PUSHDOWN)) {
        assertThat(query(session, "SELECT r.name, n.name FROM nation n JOIN region r ON n.regionkey = r.regionkey")).isNotFullyPushedDown(joinOverTableScans);
        return;
    }
    // Disable DF here for the sake of negative test cases' expected plan. With DF enabled, some operators return in DF's FilterNode and some do not.
    Session withoutDynamicFiltering = Session.builder(session).setSystemProperty("enable_dynamic_filtering", "false").build();
    String notDistinctOperator = "IS NOT DISTINCT FROM";
    List<String> nonEqualities = Stream.concat(Stream.of(JoinCondition.Operator.values()).filter(operator -> operator != JoinCondition.Operator.EQUAL).map(JoinCondition.Operator::getValue), Stream.of(notDistinctOperator)).collect(toImmutableList());
    try (TestTable nationLowercaseTable = new TestTable(// If a connector supports Join pushdown, but does not allow CTAS, we need to make the table creation here overridable.
    getQueryRunner()::execute, "nation_lowercase", "AS SELECT nationkey, lower(name) name, regionkey FROM nation")) {
        // basic case
        assertThat(query(session, "SELECT r.name, n.name FROM nation n JOIN region r ON n.regionkey = r.regionkey")).isFullyPushedDown();
        // join over different columns
        assertThat(query(session, "SELECT r.name, n.name FROM nation n JOIN region r ON n.nationkey = r.regionkey")).isFullyPushedDown();
        // pushdown when using USING
        assertThat(query(session, "SELECT r.name, n.name FROM nation n JOIN region r USING(regionkey)")).isFullyPushedDown();
        // varchar equality predicate
        assertConditionallyPushedDown(session, "SELECT n.name, n2.regionkey FROM nation n JOIN nation n2 ON n.name = n2.name", hasBehavior(SUPPORTS_JOIN_PUSHDOWN_WITH_VARCHAR_EQUALITY), joinOverTableScans);
        assertConditionallyPushedDown(session, format("SELECT n.name, nl.regionkey FROM nation n JOIN %s nl ON n.name = nl.name", nationLowercaseTable.getName()), hasBehavior(SUPPORTS_JOIN_PUSHDOWN_WITH_VARCHAR_EQUALITY), joinOverTableScans);
        // multiple bigint predicates
        assertThat(query(session, "SELECT n.name, c.name FROM nation n JOIN customer c ON n.nationkey = c.nationkey and n.regionkey = c.custkey")).isFullyPushedDown();
        // inequality
        for (String operator : nonEqualities) {
            // bigint inequality predicate
            assertThat(query(withoutDynamicFiltering, format("SELECT r.name, n.name FROM nation n JOIN region r ON n.regionkey %s r.regionkey", operator))).isNotFullyPushedDown(broadcastJoinOverTableScans);
            // varchar inequality predicate
            assertThat(query(withoutDynamicFiltering, format("SELECT n.name, nl.name FROM nation n JOIN %s nl ON n.name %s nl.name", nationLowercaseTable.getName(), operator))).isNotFullyPushedDown(broadcastJoinOverTableScans);
        }
        // inequality along with an equality, which constitutes an equi-condition and allows filter to remain as part of the Join
        for (String operator : nonEqualities) {
            assertConditionallyPushedDown(session, format("SELECT n.name, c.name FROM nation n JOIN customer c ON n.nationkey = c.nationkey AND n.regionkey %s c.custkey", operator), expectJoinPushdown(operator), joinOverTableScans);
        }
        // varchar inequality along with an equality, which constitutes an equi-condition and allows filter to remain as part of the Join
        for (String operator : nonEqualities) {
            assertConditionallyPushedDown(session, format("SELECT n.name, nl.name FROM nation n JOIN %s nl ON n.regionkey = nl.regionkey AND n.name %s nl.name", nationLowercaseTable.getName(), operator), expectVarcharJoinPushdown(operator), joinOverTableScans);
        }
        // LEFT JOIN
        assertThat(query(session, "SELECT r.name, n.name FROM nation n LEFT JOIN region r ON n.nationkey = r.regionkey")).isFullyPushedDown();
        assertThat(query(session, "SELECT r.name, n.name FROM region r LEFT JOIN nation n ON n.nationkey = r.regionkey")).isFullyPushedDown();
        // RIGHT JOIN
        assertThat(query(session, "SELECT r.name, n.name FROM nation n RIGHT JOIN region r ON n.nationkey = r.regionkey")).isFullyPushedDown();
        assertThat(query(session, "SELECT r.name, n.name FROM region r RIGHT JOIN nation n ON n.nationkey = r.regionkey")).isFullyPushedDown();
        // FULL JOIN
        assertConditionallyPushedDown(session, "SELECT r.name, n.name FROM nation n FULL JOIN region r ON n.nationkey = r.regionkey", hasBehavior(SUPPORTS_JOIN_PUSHDOWN_WITH_FULL_JOIN), joinOverTableScans);
        // Join over a (double) predicate
        assertThat(query(session, "" + "SELECT c.name, n.name " + "FROM (SELECT * FROM customer WHERE acctbal > 8000) c " + "JOIN nation n ON c.custkey = n.nationkey")).isFullyPushedDown();
        // Join over a varchar equality predicate
        assertConditionallyPushedDown(session, "SELECT c.name, n.name FROM (SELECT * FROM customer WHERE address = 'TcGe5gaZNgVePxU5kRrvXBfkasDTea') c " + "JOIN nation n ON c.custkey = n.nationkey", hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_EQUALITY), joinOverTableScans);
        // Join over a varchar inequality predicate
        assertConditionallyPushedDown(session, "SELECT c.name, n.name FROM (SELECT * FROM customer WHERE address < 'TcGe5gaZNgVePxU5kRrvXBfkasDTea') c " + "JOIN nation n ON c.custkey = n.nationkey", hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY), joinOverTableScans);
        // join over aggregation
        assertConditionallyPushedDown(session, "SELECT * FROM (SELECT regionkey rk, count(nationkey) c FROM nation GROUP BY regionkey) n " + "JOIN region r ON n.rk = r.regionkey", hasBehavior(SUPPORTS_AGGREGATION_PUSHDOWN), joinOverTableScans);
        // join over LIMIT
        assertConditionallyPushedDown(session, "SELECT * FROM (SELECT nationkey FROM nation LIMIT 30) n " + "JOIN region r ON n.nationkey = r.regionkey", hasBehavior(SUPPORTS_LIMIT_PUSHDOWN), joinOverTableScans);
        // join over TopN
        assertConditionallyPushedDown(session, "SELECT * FROM (SELECT nationkey FROM nation ORDER BY regionkey LIMIT 5) n " + "JOIN region r ON n.nationkey = r.regionkey", hasBehavior(SUPPORTS_TOPN_PUSHDOWN), joinOverTableScans);
        // join over join
        assertThat(query(session, "SELECT * FROM nation n, region r, customer c WHERE n.regionkey = r.regionkey AND r.regionkey = c.custkey")).isFullyPushedDown();
    }
}
Also used : SkipException(org.testng.SkipException) QueryId(io.trino.spi.QueryId) SUPPORTS_JOIN_PUSHDOWN_WITH_VARCHAR_INEQUALITY(io.trino.testing.TestingConnectorBehavior.SUPPORTS_JOIN_PUSHDOWN_WITH_VARCHAR_INEQUALITY) SUPPORTS_ROW_LEVEL_DELETE(io.trino.testing.TestingConnectorBehavior.SUPPORTS_ROW_LEVEL_DELETE) SUPPORTS_AGGREGATION_PUSHDOWN_VARIANCE(io.trino.testing.TestingConnectorBehavior.SUPPORTS_AGGREGATION_PUSHDOWN_VARIANCE) MaterializedResult(io.trino.testing.MaterializedResult) SUPPORTS_AGGREGATION_PUSHDOWN_COVARIANCE(io.trino.testing.TestingConnectorBehavior.SUPPORTS_AGGREGATION_PUSHDOWN_COVARIANCE) Assertions.assertThat(org.assertj.core.api.Assertions.assertThat) PlanMatchPattern(io.trino.sql.planner.assertions.PlanMatchPattern) Test(org.testng.annotations.Test) TestTable(io.trino.testing.sql.TestTable) FilterNode(io.trino.sql.planner.plan.FilterNode) Duration(io.airlift.units.Duration) Future(java.util.concurrent.Future) PlanMatchPattern.exchange(io.trino.sql.planner.assertions.PlanMatchPattern.exchange) SUPPORTS_JOIN_PUSHDOWN_WITH_FULL_JOIN(io.trino.testing.TestingConnectorBehavior.SUPPORTS_JOIN_PUSHDOWN_WITH_FULL_JOIN) TestingConnectorBehavior(io.trino.testing.TestingConnectorBehavior) SUPPORTS_AGGREGATION_PUSHDOWN_COUNT_DISTINCT(io.trino.testing.TestingConnectorBehavior.SUPPORTS_AGGREGATION_PUSHDOWN_COUNT_DISTINCT) SqlExecutor(io.trino.testing.sql.SqlExecutor) JoinNode(io.trino.sql.planner.plan.JoinNode) ENGLISH(java.util.Locale.ENGLISH) TableScanNode(io.trino.sql.planner.plan.TableScanNode) SUPPORTS_CANCELLATION(io.trino.testing.TestingConnectorBehavior.SUPPORTS_CANCELLATION) SUPPORTS_JOIN_PUSHDOWN_WITH_DISTINCT_FROM(io.trino.testing.TestingConnectorBehavior.SUPPORTS_JOIN_PUSHDOWN_WITH_DISTINCT_FROM) SUPPORTS_CREATE_TABLE(io.trino.testing.TestingConnectorBehavior.SUPPORTS_CREATE_TABLE) MarkDistinctNode(io.trino.sql.planner.plan.MarkDistinctNode) TestView(io.trino.testing.sql.TestView) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) UUID(java.util.UUID) String.format(java.lang.String.format) Preconditions.checkState(com.google.common.base.Preconditions.checkState) List(java.util.List) Stream(java.util.stream.Stream) PlanMatchPattern.anyTree(io.trino.sql.planner.assertions.PlanMatchPattern.anyTree) SUPPORTS_AGGREGATION_PUSHDOWN(io.trino.testing.TestingConnectorBehavior.SUPPORTS_AGGREGATION_PUSHDOWN) SUPPORTS_INSERT(io.trino.testing.TestingConnectorBehavior.SUPPORTS_INSERT) USE_MARK_DISTINCT(io.trino.SystemSessionProperties.USE_MARK_DISTINCT) SUPPORTS_PREDICATE_EXPRESSION_PUSHDOWN_WITH_LIKE(io.trino.testing.TestingConnectorBehavior.SUPPORTS_PREDICATE_EXPRESSION_PUSHDOWN_WITH_LIKE) ExchangeNode(io.trino.sql.planner.plan.ExchangeNode) Session(io.trino.Session) JoinCondition(io.trino.spi.connector.JoinCondition) DataProvider(org.testng.annotations.DataProvider) SUPPORTS_AGGREGATION_PUSHDOWN_STDDEV(io.trino.testing.TestingConnectorBehavior.SUPPORTS_AGGREGATION_PUSHDOWN_STDDEV) LimitNode(io.trino.sql.planner.plan.LimitNode) SUPPORTS_JOIN_PUSHDOWN_WITH_VARCHAR_EQUALITY(io.trino.testing.TestingConnectorBehavior.SUPPORTS_JOIN_PUSHDOWN_WITH_VARCHAR_EQUALITY) SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY(io.trino.testing.TestingConnectorBehavior.SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY) MINUTES(java.util.concurrent.TimeUnit.MINUTES) SUPPORTS_TOPN_PUSHDOWN(io.trino.testing.TestingConnectorBehavior.SUPPORTS_TOPN_PUSHDOWN) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) Assertions.assertThatThrownBy(org.assertj.core.api.Assertions.assertThatThrownBy) Verify.verify(com.google.common.base.Verify.verify) SUPPORTS_LIMIT_PUSHDOWN(io.trino.testing.TestingConnectorBehavior.SUPPORTS_LIMIT_PUSHDOWN) Threads.daemonThreadsNamed(io.airlift.concurrent.Threads.daemonThreadsNamed) ThreadLocalRandom(java.util.concurrent.ThreadLocalRandom) AggregationNode(io.trino.sql.planner.plan.AggregationNode) ProjectNode(io.trino.sql.planner.plan.ProjectNode) ExecutorService(java.util.concurrent.ExecutorService) SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_EQUALITY(io.trino.testing.TestingConnectorBehavior.SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_EQUALITY) AfterClass(org.testng.annotations.AfterClass) MoreCollectors.toOptional(com.google.common.collect.MoreCollectors.toOptional) SUPPORTS_TOPN_PUSHDOWN_WITH_VARCHAR(io.trino.testing.TestingConnectorBehavior.SUPPORTS_TOPN_PUSHDOWN_WITH_VARCHAR) CANCELLED(io.trino.plugin.jdbc.RemoteDatabaseEvent.Status.CANCELLED) Language(org.intellij.lang.annotations.Language) RUNNING(io.trino.plugin.jdbc.RemoteDatabaseEvent.Status.RUNNING) TopNNode(io.trino.sql.planner.plan.TopNNode) SortOrder(io.trino.spi.connector.SortOrder) BaseConnectorTest(io.trino.testing.BaseConnectorTest) PlanMatchPattern.node(io.trino.sql.planner.assertions.PlanMatchPattern.node) SUPPORTS_AGGREGATION_PUSHDOWN_CORRELATION(io.trino.testing.TestingConnectorBehavior.SUPPORTS_AGGREGATION_PUSHDOWN_CORRELATION) Assert.assertEventually(io.trino.testing.assertions.Assert.assertEventually) Executors.newCachedThreadPool(java.util.concurrent.Executors.newCachedThreadPool) QueryAssert(io.trino.sql.query.QueryAssertions.QueryAssert) SUPPORTS_AGGREGATION_PUSHDOWN_REGRESSION(io.trino.testing.TestingConnectorBehavior.SUPPORTS_AGGREGATION_PUSHDOWN_REGRESSION) SUPPORTS_JOIN_PUSHDOWN(io.trino.testing.TestingConnectorBehavior.SUPPORTS_JOIN_PUSHDOWN) JOIN_PUSHDOWN_ENABLED(io.trino.plugin.jdbc.JdbcMetadataSessionProperties.JOIN_PUSHDOWN_ENABLED) TableScanNode(io.trino.sql.planner.plan.TableScanNode) PlanMatchPattern(io.trino.sql.planner.assertions.PlanMatchPattern) TestTable(io.trino.testing.sql.TestTable) Session(io.trino.Session) Test(org.testng.annotations.Test) BaseConnectorTest(io.trino.testing.BaseConnectorTest)

Example 27 with PlanMatchPattern

use of io.trino.sql.planner.assertions.PlanMatchPattern in project trino by trinodb.

the class BaseJdbcConnectorTest method testCaseSensitiveTopNPushdown.

@Test
public void testCaseSensitiveTopNPushdown() {
    if (!hasBehavior(SUPPORTS_TOPN_PUSHDOWN)) {
        // Covered by testTopNPushdown
        return;
    }
    // topN over varchar/char columns should only be pushed down if the remote systems's sort order matches Trino
    boolean expectTopNPushdown = hasBehavior(SUPPORTS_TOPN_PUSHDOWN_WITH_VARCHAR);
    PlanMatchPattern topNOverTableScan = node(TopNNode.class, anyTree(node(TableScanNode.class)));
    try (TestTable testTable = new TestTable(getQueryRunner()::execute, "test_case_sensitive_topn_pushdown", "(a_string varchar(10), a_char char(10), a_bigint bigint)", List.of("'A', 'A', 1", "'B', 'B', 2", "'a', 'a', 3", "'b', 'b', 4"))) {
        assertConditionallyOrderedPushedDown(getSession(), "SELECT a_bigint FROM " + testTable.getName() + " ORDER BY a_string ASC LIMIT 2", expectTopNPushdown, topNOverTableScan);
        assertConditionallyOrderedPushedDown(getSession(), "SELECT a_bigint FROM " + testTable.getName() + " ORDER BY a_string DESC LIMIT 2", expectTopNPushdown, topNOverTableScan);
        assertConditionallyOrderedPushedDown(getSession(), "SELECT a_bigint FROM " + testTable.getName() + " ORDER BY a_char ASC LIMIT 2", expectTopNPushdown, topNOverTableScan);
        assertConditionallyOrderedPushedDown(getSession(), "SELECT a_bigint FROM " + testTable.getName() + " ORDER BY a_char DESC LIMIT 2", expectTopNPushdown, topNOverTableScan);
        // multiple sort columns with at-least one case-sensitive column
        assertConditionallyOrderedPushedDown(getSession(), "SELECT a_bigint FROM " + testTable.getName() + " ORDER BY a_bigint, a_char LIMIT 2", expectTopNPushdown, topNOverTableScan);
        assertConditionallyOrderedPushedDown(getSession(), "SELECT a_bigint FROM " + testTable.getName() + " ORDER BY a_bigint, a_string DESC LIMIT 2", expectTopNPushdown, topNOverTableScan);
    }
}
Also used : PlanMatchPattern(io.trino.sql.planner.assertions.PlanMatchPattern) TestTable(io.trino.testing.sql.TestTable) Test(org.testng.annotations.Test) BaseConnectorTest(io.trino.testing.BaseConnectorTest)

Aggregations

PlanMatchPattern (io.trino.sql.planner.assertions.PlanMatchPattern)27 Test (org.testng.annotations.Test)27 ImmutableList (com.google.common.collect.ImmutableList)18 ImmutableMap (com.google.common.collect.ImmutableMap)16 BasePlanTest (io.trino.sql.planner.assertions.BasePlanTest)16 PlanMatchPattern.anyTree (io.trino.sql.planner.assertions.PlanMatchPattern.anyTree)16 Optional (java.util.Optional)15 Language (org.intellij.lang.annotations.Language)15 SortOrder (io.trino.spi.connector.SortOrder)14 PlanMatchPattern.functionCall (io.trino.sql.planner.assertions.PlanMatchPattern.functionCall)14 PlanMatchPattern.expression (io.trino.sql.planner.assertions.PlanMatchPattern.expression)13 PlanMatchPattern.specification (io.trino.sql.planner.assertions.PlanMatchPattern.specification)13 PlanMatchPattern.window (io.trino.sql.planner.assertions.PlanMatchPattern.window)13 PlanMatchPattern.project (io.trino.sql.planner.assertions.PlanMatchPattern.project)12 PlanMatchPattern.values (io.trino.sql.planner.assertions.PlanMatchPattern.values)10 CREATED (io.trino.sql.planner.LogicalPlanner.Stage.CREATED)9 QualifiedName (io.trino.sql.tree.QualifiedName)9 List (java.util.List)9 TEST_SESSION (io.trino.SessionTestUtils.TEST_SESSION)8 INTEGER (io.trino.spi.type.IntegerType.INTEGER)8