public JoinNode join(JoinNode.Type joinType, PlanNode left, PlanNode right, JoinNode.EquiJoinClause... criteria) { return join(joinType, left, right, Optional.empty(), criteria); }
public JoinNode join(JoinNode.Type joinType, PlanNode left, PlanNode right, Expression filter, JoinNode.EquiJoinClause... criteria) { return join(joinType, left, right, Optional.of(filter), criteria); }
public JoinNode join( JoinNode.Type type, PlanNode left, PlanNode right, List<JoinNode.EquiJoinClause> criteria, List<Symbol> outputSymbols, Optional<Expression> filter, Optional<Symbol> leftHashSymbol, Optional<Symbol> rightHashSymbol) { return join(type, left, right, criteria, outputSymbols, filter, leftHashSymbol, rightHashSymbol, Optional.empty()); }
private JoinNode join(JoinNode.Type joinType, PlanNode left, PlanNode right, Optional<Expression> filter, JoinNode.EquiJoinClause... criteria) { return join( joinType, left, right, ImmutableList.copyOf(criteria), ImmutableList.<Symbol>builder() .addAll(left.getOutputSymbols()) .addAll(right.getOutputSymbols()) .build(), filter, Optional.empty(), Optional.empty()); }
@Test public void testJoinOrder() { PlanBuilder planBuilder = new PlanBuilder(new PlanNodeIdAllocator(), dummyMetadata()); TableScanNode a = planBuilder.tableScan(emptyList(), emptyMap()); TableScanNode b = planBuilder.tableScan(emptyList(), emptyMap()); List<PlanNodeId> order = scheduleOrder(planBuilder.join(JoinNode.Type.INNER, a, b)); assertEquals(order, ImmutableList.of(b.getId(), a.getId())); }
@Test(expectedExceptions = IllegalStateException.class) public void testDoesNotAllowOuterJoin() { PlanBuilder p = planBuilder(); Symbol a1 = p.symbol("A1"); Symbol b1 = p.symbol("B1"); JoinNode outerJoin = p.join( FULL, p.values(a1), p.values(b1), ImmutableList.of(equiJoinClause(a1, b1)), ImmutableList.of(a1, b1), Optional.empty()); toMultiJoinNode(outerJoin, noLookup(), DEFAULT_JOIN_LIMIT); }
@Test public void testRetainDistributionType() { assertDetermineJoinDistributionType() .on(p -> p.join( INNER, p.values(ImmutableList.of(p.symbol("A1")), ImmutableList.of(expressions("10"), expressions("11"))), p.values(ImmutableList.of(p.symbol("B1")), ImmutableList.of(expressions("50"), expressions("11"))), ImmutableList.of(new JoinNode.EquiJoinClause(p.symbol("A1", BIGINT), p.symbol("B1", BIGINT))), ImmutableList.of(p.symbol("A1", BIGINT), p.symbol("B1", BIGINT)), Optional.empty(), Optional.empty(), Optional.empty(), Optional.of(DistributionType.REPLICATED))) .doesNotFire(); }
@Test public void testDoesNotFireForUnfilteredJoin() { tester().assertThat(canonicalizeExpressions.joinExpressionRewrite()) .on(p -> p.join(INNER, p.values(), p.values())) .doesNotFire(); }
@Test public void testDoesNotFireForCanonicalExpressions() { tester().assertThat(canonicalizeExpressions.joinExpressionRewrite()) .on(p -> p.join(INNER, p.values(), p.values(), FALSE_LITERAL)) .doesNotFire(); } }
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Final aggregation with default value not separated from partial aggregation by local hash exchange") public void testWithPartialAggregationBelowJoinWithoutSeparatingExchange() { Symbol symbol = new Symbol("symbol"); PlanNode root = builder.aggregation( af -> af.step(FINAL) .groupingSets(groupingSets(ImmutableList.of(symbol), 2, ImmutableSet.of(0))) .source(builder.join( INNER, builder.aggregation(ap -> ap .step(PARTIAL) .groupingSets(groupingSets(ImmutableList.of(symbol), 2, ImmutableSet.of(0))) .source(tableScanNode)), builder.values()))); validatePlan(root, true); }
@Test public void testDoesNotFireWithNoStats() { assertReorderJoins() .on(p -> p.join( INNER, p.values(new PlanNodeId("valuesA"), ImmutableList.of(p.symbol("A1")), TWO_ROWS), p.values(new PlanNodeId("valuesB"), p.symbol("B1")), ImmutableList.of(new EquiJoinClause(p.symbol("A1"), p.symbol("B1"))), ImmutableList.of(p.symbol("A1")), Optional.empty())) .overrideStats("valuesA", PlanNodeStatsEstimate.unknown()) .doesNotFire(); }
@Test public void testPushDownBothArguments() { assertRuleApplication() .on(p -> p.join(LEFT, p.values(p.symbol("wkt", VARCHAR)), p.values(p.symbol("lat"), p.symbol("lng")), expression("ST_Contains(ST_GeometryFromText(wkt), ST_Point(lng, lat))"))) .matches( spatialLeftJoin("ST_Contains(st_geometryfromtext, st_point)", project(ImmutableMap.of("st_geometryfromtext", PlanMatchPattern.expression("ST_GeometryFromText(wkt)")), values(ImmutableMap.of("wkt", 0))), project(ImmutableMap.of("st_point", PlanMatchPattern.expression("ST_Point(lng, lat)")), values(ImmutableMap.of("lat", 0, "lng", 1))))); }
@Test public void testPushDownOppositeOrder() { assertRuleApplication() .on(p -> p.join(LEFT, p.values(p.symbol("lat"), p.symbol("lng")), p.values(p.symbol("wkt", VARCHAR)), expression("ST_Contains(ST_GeometryFromText(wkt), ST_Point(lng, lat))"))) .matches( spatialLeftJoin("ST_Contains(st_geometryfromtext, st_point)", project(ImmutableMap.of("st_point", PlanMatchPattern.expression("ST_Point(lng, lat)")), values(ImmutableMap.of("lat", 0, "lng", 1))), project(ImmutableMap.of("st_geometryfromtext", PlanMatchPattern.expression("ST_GeometryFromText(wkt)")), values(ImmutableMap.of("wkt", 0))))); }
@Test public void testPushDownBothArguments() { assertRuleApplication() .on(p -> p.filter(PlanBuilder.expression("ST_Contains(ST_GeometryFromText(wkt), ST_Point(lng, lat))"), p.join(INNER, p.values(p.symbol("wkt", VARCHAR)), p.values(p.symbol("lat"), p.symbol("lng"))))) .matches( spatialJoin("ST_Contains(st_geometryfromtext, st_point)", project(ImmutableMap.of("st_geometryfromtext", expression("ST_GeometryFromText(wkt)")), values(ImmutableMap.of("wkt", 0))), project(ImmutableMap.of("st_point", expression("ST_Point(lng, lat)")), values(ImmutableMap.of("lat", 0, "lng", 1))))); }
@Test public void testPushDownOppositeOrder() { assertRuleApplication() .on(p -> p.filter(PlanBuilder.expression("ST_Contains(ST_GeometryFromText(wkt), ST_Point(lng, lat))"), p.join(INNER, p.values(p.symbol("lat"), p.symbol("lng")), p.values(p.symbol("wkt", VARCHAR))))) .matches( spatialJoin("ST_Contains(st_geometryfromtext, st_point)", project(ImmutableMap.of("st_point", expression("ST_Point(lng, lat)")), values(ImmutableMap.of("lat", 0, "lng", 1))), project(ImmutableMap.of("st_geometryfromtext", expression("ST_GeometryFromText(wkt)")), values(ImmutableMap.of("wkt", 0))))); }
@Test public void testDoesNotFireForNonDeterministicFilter() { assertReorderJoins() .on(p -> p.join( INNER, p.values(new PlanNodeId("valuesA"), p.symbol("A1")), p.values(new PlanNodeId("valuesB"), p.symbol("B1")), ImmutableList.of(new EquiJoinClause(p.symbol("A1"), p.symbol("B1"))), ImmutableList.of(p.symbol("A1"), p.symbol("B1")), Optional.of(new ComparisonExpression(LESS_THAN, p.symbol("A1").toSymbolReference(), new FunctionCall(QualifiedName.of("random"), ImmutableList.of()))))) .doesNotFire(); }
private void testRadiusExpressionInDistanceQuery(String filter, String newFilter, String radiusExpression) { assertRuleApplication() .on(p -> p.filter(PlanBuilder.expression(filter), p.join(INNER, p.values(p.symbol("a", GEOMETRY), p.symbol("name_a")), p.values(p.symbol("b", GEOMETRY), p.symbol("name_b"), p.symbol("r"))))) .matches( spatialJoin(newFilter, values(ImmutableMap.of("a", 0, "name_a", 1)), project(ImmutableMap.of("radius", expression(radiusExpression)), values(ImmutableMap.of("b", 0, "name_b", 1, "r", 2))))); }
private void testPointExpressionsInDistanceQuery(String filter, String newFilter, String radiusExpression) { assertRuleApplication() .on(p -> p.filter(PlanBuilder.expression(filter), p.join(INNER, p.values(p.symbol("lat_a"), p.symbol("lng_a"), p.symbol("name_a")), p.values(p.symbol("lat_b"), p.symbol("lng_b"), p.symbol("name_b"))))) .matches( spatialJoin(newFilter, project(ImmutableMap.of("point_a", expression("ST_Point(lng_a, lat_a)")), values(ImmutableMap.of("lat_a", 0, "lng_a", 1, "name_a", 2))), project(ImmutableMap.of("point_b", expression("ST_Point(lng_b, lat_b)")), project(ImmutableMap.of("radius", expression(radiusExpression)), values(ImmutableMap.of("lat_b", 0, "lng_b", 1, "name_b", 2)))))); }
private void testSimpleDistanceQuery(String filter, String newFilter) { assertRuleApplication() .on(p -> p.filter(PlanBuilder.expression(filter), p.join(INNER, p.values(p.symbol("a", GEOMETRY), p.symbol("name_a")), p.values(p.symbol("b", GEOMETRY), p.symbol("name_b"), p.symbol("r"))))) .matches( spatialJoin(newFilter, values(ImmutableMap.of("a", 0, "name_a", 1)), values(ImmutableMap.of("b", 0, "name_b", 1, "r", 2)))); }
private void assertJoinStats(JoinNode.Type joinType, String leftJoinColumn, String leftOtherColumn, String rightJoinColumn, String rightOtherColumn, PlanNodeStatsEstimate leftStats, PlanNodeStatsEstimate rightStats, PlanNodeStatsEstimate resultStats) { tester().assertStatsFor(pb -> { Symbol leftJoinColumnSymbol = pb.symbol(leftJoinColumn, BIGINT); Symbol rightJoinColumnSymbol = pb.symbol(rightJoinColumn, DOUBLE); Symbol leftOtherColumnSymbol = pb.symbol(leftOtherColumn, BIGINT); Symbol rightOtherColumnSymbol = pb.symbol(rightOtherColumn, DOUBLE); return pb .join(joinType, pb.values(leftJoinColumnSymbol, leftOtherColumnSymbol), pb.values(rightJoinColumnSymbol, rightOtherColumnSymbol), new EquiJoinClause(leftJoinColumnSymbol, rightJoinColumnSymbol)); }).withSourceStats(0, leftStats) .withSourceStats(1, rightStats) .check(JOIN_STATS_RULE, stats -> stats.equalTo(resultStats)); }