use of io.trino.testing.TestingConnectorBehavior.SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY in project trino by trinodb.
the class BaseJdbcConnectorTest method testCountDistinctWithStringTypes.
@Test
public void testCountDistinctWithStringTypes() {
if (!(hasBehavior(SUPPORTS_CREATE_TABLE) && hasBehavior(SUPPORTS_INSERT))) {
throw new SkipException("Unable to CREATE TABLE to test count distinct");
}
List<String> rows = Stream.of("a", "b", "A", "B", " a ", "a", "b", " b ", "ą").map(value -> format("'%1$s', '%1$s'", value)).collect(toImmutableList());
try (TestTable testTable = new TestTable(getQueryRunner()::execute, "distinct_strings", "(t_char CHAR(5), t_varchar VARCHAR(5))", rows)) {
if (!(hasBehavior(SUPPORTS_AGGREGATION_PUSHDOWN) && hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY))) {
// disabling hash generation to prevent extra projections in the plan which make it hard to write matchers for isNotFullyPushedDown
Session optimizeHashGenerationDisabled = Session.builder(getSession()).setSystemProperty("optimize_hash_generation", "false").build();
// It is not captured in the `isNotFullyPushedDown` calls (can't do that) but depending on the connector in use some aggregations
// still can be pushed down to connector.
// If `SUPPORTS_AGGREGATION_PUSHDOWN == false` but `SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY == true` the DISTINCT part of aggregation
// will still be pushed down to connector as `GROUP BY`. Only the `count` part will remain on the Trino side.
// If `SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY == false` both parts of aggregation will be executed on Trino side.
assertThat(query(optimizeHashGenerationDisabled, "SELECT count(DISTINCT t_varchar) FROM " + testTable.getName())).matches("VALUES BIGINT '7'").isNotFullyPushedDown(AggregationNode.class);
assertThat(query(optimizeHashGenerationDisabled, "SELECT count(DISTINCT t_char) FROM " + testTable.getName())).matches("VALUES BIGINT '7'").isNotFullyPushedDown(AggregationNode.class);
assertThat(query("SELECT count(DISTINCT t_char), count(DISTINCT t_varchar) FROM " + testTable.getName())).matches("VALUES (BIGINT '7', BIGINT '7')").isNotFullyPushedDown(MarkDistinctNode.class, ExchangeNode.class, ExchangeNode.class, ProjectNode.class);
} else {
// Single count(DISTINCT ...) can be pushed even down even if SUPPORTS_AGGREGATION_PUSHDOWN_COUNT_DISTINCT == false as GROUP BY
assertThat(query("SELECT count(DISTINCT t_varchar) FROM " + testTable.getName())).matches("VALUES BIGINT '7'").isFullyPushedDown();
// Single count(DISTINCT ...) can be pushed down even if SUPPORTS_AGGREGATION_PUSHDOWN_COUNT_DISTINCT == false as GROUP BY
assertThat(query("SELECT count(DISTINCT t_char) FROM " + testTable.getName())).matches("VALUES BIGINT '7'").isFullyPushedDown();
assertConditionallyPushedDown(getSession(), "SELECT count(DISTINCT t_char), count(DISTINCT t_varchar) FROM " + testTable.getName(), hasBehavior(SUPPORTS_AGGREGATION_PUSHDOWN_COUNT_DISTINCT), node(MarkDistinctNode.class, node(ExchangeNode.class, node(ExchangeNode.class, node(ProjectNode.class, node(TableScanNode.class))))));
}
}
}
use of io.trino.testing.TestingConnectorBehavior.SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY 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();
}
}
Aggregations