Search in sources :

Example 21 with FilterNode

use of com.facebook.presto.spi.plan.FilterNode in project presto by prestodb.

the class TestEffectivePredicateExtractor method testInnerJoinPropagatesPredicatesViaEquiConditions.

@Test
public void testInnerJoinPropagatesPredicatesViaEquiConditions() {
    Map<VariableReferenceExpression, ColumnHandle> leftAssignments = Maps.filterKeys(scanAssignments, Predicates.in(ImmutableList.of(AV, BV, CV)));
    TableScanNode leftScan = tableScanNode(leftAssignments);
    Map<VariableReferenceExpression, ColumnHandle> rightAssignments = Maps.filterKeys(scanAssignments, Predicates.in(ImmutableList.of(DV, EV, FV)));
    TableScanNode rightScan = tableScanNode(rightAssignments);
    FilterNode left = filter(leftScan, equals(AV, bigintLiteral(10)));
    // predicates on "a" column should be propagated to output symbols via join equi conditions
    PlanNode node = new JoinNode(Optional.empty(), newId(), JoinNode.Type.INNER, left, rightScan, ImmutableList.of(new JoinNode.EquiJoinClause(AV, DV)), ImmutableList.<VariableReferenceExpression>builder().addAll(rightScan.getOutputVariables()).build(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of());
    RowExpression effectivePredicate = effectivePredicateExtractor.extract(node);
    assertEquals(normalizeConjuncts(effectivePredicate), normalizeConjuncts(equals(DV, bigintLiteral(10))));
}
Also used : ColumnHandle(com.facebook.presto.spi.ColumnHandle) PlanNode(com.facebook.presto.spi.plan.PlanNode) TableScanNode(com.facebook.presto.spi.plan.TableScanNode) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) SemiJoinNode(com.facebook.presto.sql.planner.plan.SemiJoinNode) FilterNode(com.facebook.presto.spi.plan.FilterNode) RowExpression(com.facebook.presto.spi.relation.RowExpression) Test(org.testng.annotations.Test)

Example 22 with FilterNode

use of com.facebook.presto.spi.plan.FilterNode in project presto by prestodb.

the class TestEffectivePredicateExtractor method testRightJoin.

@Test
public void testRightJoin() {
    ImmutableList.Builder<JoinNode.EquiJoinClause> criteriaBuilder = ImmutableList.builder();
    criteriaBuilder.add(new JoinNode.EquiJoinClause(AV, DV));
    criteriaBuilder.add(new JoinNode.EquiJoinClause(BV, EV));
    List<JoinNode.EquiJoinClause> criteria = criteriaBuilder.build();
    Map<VariableReferenceExpression, ColumnHandle> leftAssignments = Maps.filterKeys(scanAssignments, Predicates.in(ImmutableList.of(AV, BV, CV)));
    TableScanNode leftScan = tableScanNode(leftAssignments);
    Map<VariableReferenceExpression, ColumnHandle> rightAssignments = Maps.filterKeys(scanAssignments, Predicates.in(ImmutableList.of(DV, EV, FV)));
    TableScanNode rightScan = tableScanNode(rightAssignments);
    FilterNode left = filter(leftScan, and(lessThan(BV, AV), lessThan(CV, bigintLiteral(10)), equals(GV, bigintLiteral(10))));
    FilterNode right = filter(rightScan, and(equals(DV, EV), lessThan(FV, bigintLiteral(100))));
    PlanNode node = new JoinNode(Optional.empty(), newId(), JoinNode.Type.RIGHT, left, right, criteria, ImmutableList.<VariableReferenceExpression>builder().addAll(left.getOutputVariables()).addAll(right.getOutputVariables()).build(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of());
    RowExpression effectivePredicate = effectivePredicateExtractor.extract(node);
    // All left side symbols should be checked against NULL
    assertEquals(normalizeConjuncts(effectivePredicate), normalizeConjuncts(or(lessThan(BV, AV), and(isNull(BV), isNull(AV))), or(lessThan(CV, bigintLiteral(10)), isNull(CV)), equals(DV, EV), lessThan(FV, bigintLiteral(100)), or(equals(AV, DV), isNull(AV)), or(equals(BV, EV), isNull(BV))));
}
Also used : ColumnHandle(com.facebook.presto.spi.ColumnHandle) ImmutableList(com.google.common.collect.ImmutableList) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) SemiJoinNode(com.facebook.presto.sql.planner.plan.SemiJoinNode) FilterNode(com.facebook.presto.spi.plan.FilterNode) RowExpression(com.facebook.presto.spi.relation.RowExpression) PlanNode(com.facebook.presto.spi.plan.PlanNode) TableScanNode(com.facebook.presto.spi.plan.TableScanNode) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) Test(org.testng.annotations.Test)

Example 23 with FilterNode

use of com.facebook.presto.spi.plan.FilterNode in project presto by prestodb.

the class TestEffectivePredicateExtractor method testLeftJoinWithFalseInner.

@Test
public void testLeftJoinWithFalseInner() {
    List<JoinNode.EquiJoinClause> criteria = ImmutableList.of(new JoinNode.EquiJoinClause(AV, DV));
    Map<VariableReferenceExpression, ColumnHandle> leftAssignments = Maps.filterKeys(scanAssignments, Predicates.in(ImmutableList.of(AV, BV, CV)));
    TableScanNode leftScan = tableScanNode(leftAssignments);
    Map<VariableReferenceExpression, ColumnHandle> rightAssignments = Maps.filterKeys(scanAssignments, Predicates.in(ImmutableList.of(DV, EV, FV)));
    TableScanNode rightScan = tableScanNode(rightAssignments);
    FilterNode left = filter(leftScan, and(lessThan(BV, AV), lessThan(CV, bigintLiteral(10)), equals(GV, bigintLiteral(10))));
    FilterNode right = filter(rightScan, FALSE_CONSTANT);
    PlanNode node = new JoinNode(Optional.empty(), newId(), JoinNode.Type.LEFT, left, right, criteria, ImmutableList.<VariableReferenceExpression>builder().addAll(left.getOutputVariables()).addAll(right.getOutputVariables()).build(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of());
    RowExpression effectivePredicate = effectivePredicateExtractor.extract(node);
    // False literal on the right side should be ignored
    assertEquals(normalizeConjuncts(effectivePredicate), normalizeConjuncts(lessThan(BV, AV), lessThan(CV, bigintLiteral(10)), or(equals(AV, DV), isNull(DV))));
}
Also used : ColumnHandle(com.facebook.presto.spi.ColumnHandle) PlanNode(com.facebook.presto.spi.plan.PlanNode) TableScanNode(com.facebook.presto.spi.plan.TableScanNode) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) SemiJoinNode(com.facebook.presto.sql.planner.plan.SemiJoinNode) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) FilterNode(com.facebook.presto.spi.plan.FilterNode) RowExpression(com.facebook.presto.spi.relation.RowExpression) Test(org.testng.annotations.Test)

Example 24 with FilterNode

use of com.facebook.presto.spi.plan.FilterNode in project presto by prestodb.

the class TestEffectivePredicateExtractor method testRightJoinWithFalseInner.

@Test
public void testRightJoinWithFalseInner() {
    List<JoinNode.EquiJoinClause> criteria = ImmutableList.of(new JoinNode.EquiJoinClause(AV, DV));
    Map<VariableReferenceExpression, ColumnHandle> leftAssignments = Maps.filterKeys(scanAssignments, Predicates.in(ImmutableList.of(AV, BV, CV)));
    TableScanNode leftScan = tableScanNode(leftAssignments);
    Map<VariableReferenceExpression, ColumnHandle> rightAssignments = Maps.filterKeys(scanAssignments, Predicates.in(ImmutableList.of(DV, EV, FV)));
    TableScanNode rightScan = tableScanNode(rightAssignments);
    FilterNode left = filter(leftScan, FALSE_CONSTANT);
    FilterNode right = filter(rightScan, and(equals(DV, EV), lessThan(FV, bigintLiteral(100))));
    PlanNode node = new JoinNode(Optional.empty(), newId(), JoinNode.Type.RIGHT, left, right, criteria, ImmutableList.<VariableReferenceExpression>builder().addAll(left.getOutputVariables()).addAll(right.getOutputVariables()).build(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of());
    RowExpression effectivePredicate = effectivePredicateExtractor.extract(node);
    // False literal on the left side should be ignored
    assertEquals(normalizeConjuncts(effectivePredicate), normalizeConjuncts(equals(DV, EV), lessThan(FV, bigintLiteral(100)), or(equals(AV, DV), isNull(AV))));
}
Also used : ColumnHandle(com.facebook.presto.spi.ColumnHandle) PlanNode(com.facebook.presto.spi.plan.PlanNode) TableScanNode(com.facebook.presto.spi.plan.TableScanNode) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) SemiJoinNode(com.facebook.presto.sql.planner.plan.SemiJoinNode) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) FilterNode(com.facebook.presto.spi.plan.FilterNode) RowExpression(com.facebook.presto.spi.relation.RowExpression) Test(org.testng.annotations.Test)

Example 25 with FilterNode

use of com.facebook.presto.spi.plan.FilterNode in project presto by prestodb.

the class RelationPlanner method visitJoin.

@Override
protected RelationPlan visitJoin(Join node, Void context) {
    // TODO: translate the RIGHT join into a mirrored LEFT join when we refactor (@martint)
    RelationPlan leftPlan = process(node.getLeft(), context);
    Optional<Unnest> unnest = getUnnest(node.getRight());
    if (unnest.isPresent()) {
        if (node.getType() != Join.Type.CROSS && node.getType() != Join.Type.IMPLICIT) {
            throw notSupportedException(unnest.get(), "UNNEST on other than the right side of CROSS JOIN");
        }
        return planCrossJoinUnnest(leftPlan, node, unnest.get());
    }
    Optional<Lateral> lateral = getLateral(node.getRight());
    if (lateral.isPresent()) {
        if (node.getType() != Join.Type.CROSS && node.getType() != Join.Type.IMPLICIT) {
            throw notSupportedException(lateral.get(), "LATERAL on other than the right side of CROSS JOIN");
        }
        return planLateralJoin(node, leftPlan, lateral.get());
    }
    RelationPlan rightPlan = process(node.getRight(), context);
    if (node.getCriteria().isPresent() && node.getCriteria().get() instanceof JoinUsing) {
        return planJoinUsing(node, leftPlan, rightPlan);
    }
    PlanBuilder leftPlanBuilder = initializePlanBuilder(leftPlan);
    PlanBuilder rightPlanBuilder = initializePlanBuilder(rightPlan);
    // NOTE: variables must be in the same order as the outputDescriptor
    List<VariableReferenceExpression> outputs = ImmutableList.<VariableReferenceExpression>builder().addAll(leftPlan.getFieldMappings()).addAll(rightPlan.getFieldMappings()).build();
    ImmutableList.Builder<JoinNode.EquiJoinClause> equiClauses = ImmutableList.builder();
    List<Expression> complexJoinExpressions = new ArrayList<>();
    List<Expression> postInnerJoinConditions = new ArrayList<>();
    if (node.getType() != Join.Type.CROSS && node.getType() != Join.Type.IMPLICIT) {
        Expression criteria = analysis.getJoinCriteria(node);
        RelationType left = analysis.getOutputDescriptor(node.getLeft());
        RelationType right = analysis.getOutputDescriptor(node.getRight());
        List<Expression> leftComparisonExpressions = new ArrayList<>();
        List<Expression> rightComparisonExpressions = new ArrayList<>();
        List<ComparisonExpression.Operator> joinConditionComparisonOperators = new ArrayList<>();
        for (Expression conjunct : ExpressionUtils.extractConjuncts(criteria)) {
            conjunct = ExpressionUtils.normalize(conjunct);
            if (!isEqualComparisonExpression(conjunct) && node.getType() != INNER) {
                complexJoinExpressions.add(conjunct);
                continue;
            }
            Set<QualifiedName> dependencies = VariablesExtractor.extractNames(conjunct, analysis.getColumnReferences());
            if (dependencies.stream().allMatch(left::canResolve) || dependencies.stream().allMatch(right::canResolve)) {
                // If the conjunct can be evaluated entirely with the inputs on either side of the join, add
                // it to the list complex expressions and let the optimizers figure out how to push it down later.
                complexJoinExpressions.add(conjunct);
            } else if (conjunct instanceof ComparisonExpression) {
                Expression firstExpression = ((ComparisonExpression) conjunct).getLeft();
                Expression secondExpression = ((ComparisonExpression) conjunct).getRight();
                ComparisonExpression.Operator comparisonOperator = ((ComparisonExpression) conjunct).getOperator();
                Set<QualifiedName> firstDependencies = VariablesExtractor.extractNames(firstExpression, analysis.getColumnReferences());
                Set<QualifiedName> secondDependencies = VariablesExtractor.extractNames(secondExpression, analysis.getColumnReferences());
                if (firstDependencies.stream().allMatch(left::canResolve) && secondDependencies.stream().allMatch(right::canResolve)) {
                    leftComparisonExpressions.add(firstExpression);
                    rightComparisonExpressions.add(secondExpression);
                    addNullFilters(complexJoinExpressions, node.getType(), firstExpression, secondExpression);
                    joinConditionComparisonOperators.add(comparisonOperator);
                } else if (firstDependencies.stream().allMatch(right::canResolve) && secondDependencies.stream().allMatch(left::canResolve)) {
                    leftComparisonExpressions.add(secondExpression);
                    rightComparisonExpressions.add(firstExpression);
                    addNullFilters(complexJoinExpressions, node.getType(), secondExpression, firstExpression);
                    joinConditionComparisonOperators.add(comparisonOperator.flip());
                } else {
                    // the case when we mix variables from both left and right join side on either side of condition.
                    complexJoinExpressions.add(conjunct);
                }
            } else {
                complexJoinExpressions.add(conjunct);
            }
        }
        leftPlanBuilder = subqueryPlanner.handleSubqueries(leftPlanBuilder, leftComparisonExpressions, node);
        rightPlanBuilder = subqueryPlanner.handleSubqueries(rightPlanBuilder, rightComparisonExpressions, node);
        // Add projections for join criteria
        leftPlanBuilder = leftPlanBuilder.appendProjections(leftComparisonExpressions, variableAllocator, idAllocator);
        rightPlanBuilder = rightPlanBuilder.appendProjections(rightComparisonExpressions, variableAllocator, idAllocator);
        for (int i = 0; i < leftComparisonExpressions.size(); i++) {
            if (joinConditionComparisonOperators.get(i) == ComparisonExpression.Operator.EQUAL) {
                VariableReferenceExpression leftVariable = leftPlanBuilder.translateToVariable(leftComparisonExpressions.get(i));
                VariableReferenceExpression righVariable = rightPlanBuilder.translateToVariable(rightComparisonExpressions.get(i));
                equiClauses.add(new JoinNode.EquiJoinClause(leftVariable, righVariable));
            } else {
                Expression leftExpression = leftPlanBuilder.rewrite(leftComparisonExpressions.get(i));
                Expression rightExpression = rightPlanBuilder.rewrite(rightComparisonExpressions.get(i));
                postInnerJoinConditions.add(new ComparisonExpression(joinConditionComparisonOperators.get(i), leftExpression, rightExpression));
            }
        }
    }
    PlanNode root = new JoinNode(getSourceLocation(node), idAllocator.getNextId(), JoinNodeUtils.typeConvert(node.getType()), leftPlanBuilder.getRoot(), rightPlanBuilder.getRoot(), equiClauses.build(), ImmutableList.<VariableReferenceExpression>builder().addAll(leftPlanBuilder.getRoot().getOutputVariables()).addAll(rightPlanBuilder.getRoot().getOutputVariables()).build(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of());
    if (node.getType() != INNER) {
        for (Expression complexExpression : complexJoinExpressions) {
            Set<InPredicate> inPredicates = subqueryPlanner.collectInPredicateSubqueries(complexExpression, node);
            if (!inPredicates.isEmpty()) {
                InPredicate inPredicate = Iterables.getLast(inPredicates);
                throw notSupportedException(inPredicate, "IN with subquery predicate in join condition");
            }
        }
        // subqueries can be applied only to one side of join - left side is selected in arbitrary way
        leftPlanBuilder = subqueryPlanner.handleUncorrelatedSubqueries(leftPlanBuilder, complexJoinExpressions, node);
    }
    RelationPlan intermediateRootRelationPlan = new RelationPlan(root, analysis.getScope(node), outputs);
    TranslationMap translationMap = new TranslationMap(intermediateRootRelationPlan, analysis, lambdaDeclarationToVariableMap);
    translationMap.setFieldMappings(outputs);
    translationMap.putExpressionMappingsFrom(leftPlanBuilder.getTranslations());
    translationMap.putExpressionMappingsFrom(rightPlanBuilder.getTranslations());
    if (node.getType() != INNER && !complexJoinExpressions.isEmpty()) {
        Expression joinedFilterCondition = ExpressionUtils.and(complexJoinExpressions);
        Expression rewrittenFilterCondition = translationMap.rewrite(joinedFilterCondition);
        root = new JoinNode(getSourceLocation(node), idAllocator.getNextId(), JoinNodeUtils.typeConvert(node.getType()), leftPlanBuilder.getRoot(), rightPlanBuilder.getRoot(), equiClauses.build(), ImmutableList.<VariableReferenceExpression>builder().addAll(leftPlanBuilder.getRoot().getOutputVariables()).addAll(rightPlanBuilder.getRoot().getOutputVariables()).build(), Optional.of(castToRowExpression(rewrittenFilterCondition)), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of());
    }
    if (node.getType() == INNER) {
        // rewrite all the other conditions using output variables from left + right plan node.
        PlanBuilder rootPlanBuilder = new PlanBuilder(translationMap, root);
        rootPlanBuilder = subqueryPlanner.handleSubqueries(rootPlanBuilder, complexJoinExpressions, node);
        for (Expression expression : complexJoinExpressions) {
            postInnerJoinConditions.add(rootPlanBuilder.rewrite(expression));
        }
        root = rootPlanBuilder.getRoot();
        Expression postInnerJoinCriteria;
        if (!postInnerJoinConditions.isEmpty()) {
            postInnerJoinCriteria = ExpressionUtils.and(postInnerJoinConditions);
            root = new FilterNode(getSourceLocation(postInnerJoinCriteria), idAllocator.getNextId(), root, castToRowExpression(postInnerJoinCriteria));
        }
    }
    return new RelationPlan(root, analysis.getScope(node), outputs);
}
Also used : AggregationNode.singleGroupingSet(com.facebook.presto.spi.plan.AggregationNode.singleGroupingSet) Set(java.util.Set) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) ImmutableList(com.google.common.collect.ImmutableList) FilterNode(com.facebook.presto.spi.plan.FilterNode) ArrayList(java.util.ArrayList) PlanNode(com.facebook.presto.spi.plan.PlanNode) RelationType(com.facebook.presto.sql.analyzer.RelationType) Unnest(com.facebook.presto.sql.tree.Unnest) Lateral(com.facebook.presto.sql.tree.Lateral) LateralJoinNode(com.facebook.presto.sql.planner.plan.LateralJoinNode) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) QualifiedName(com.facebook.presto.sql.tree.QualifiedName) JoinUsing(com.facebook.presto.sql.tree.JoinUsing) InPredicate(com.facebook.presto.sql.tree.InPredicate) ComparisonExpression(com.facebook.presto.sql.tree.ComparisonExpression) ExpressionTreeUtils.isEqualComparisonExpression(com.facebook.presto.sql.analyzer.ExpressionTreeUtils.isEqualComparisonExpression) CoalesceExpression(com.facebook.presto.sql.tree.CoalesceExpression) OriginalExpressionUtils.castToRowExpression(com.facebook.presto.sql.relational.OriginalExpressionUtils.castToRowExpression) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) RowExpression(com.facebook.presto.spi.relation.RowExpression) DereferenceExpression(com.facebook.presto.sql.tree.DereferenceExpression) ComparisonExpression(com.facebook.presto.sql.tree.ComparisonExpression) ExpressionTreeUtils.isEqualComparisonExpression(com.facebook.presto.sql.analyzer.ExpressionTreeUtils.isEqualComparisonExpression) Expression(com.facebook.presto.sql.tree.Expression) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression)

Aggregations

FilterNode (com.facebook.presto.spi.plan.FilterNode)31 PlanNode (com.facebook.presto.spi.plan.PlanNode)22 VariableReferenceExpression (com.facebook.presto.spi.relation.VariableReferenceExpression)19 Test (org.testng.annotations.Test)16 RowExpression (com.facebook.presto.spi.relation.RowExpression)15 TableScanNode (com.facebook.presto.spi.plan.TableScanNode)11 ProjectNode (com.facebook.presto.spi.plan.ProjectNode)10 JoinNode (com.facebook.presto.sql.planner.plan.JoinNode)10 ImmutableList (com.google.common.collect.ImmutableList)8 ColumnHandle (com.facebook.presto.spi.ColumnHandle)7 PlanBuilder (com.facebook.presto.sql.planner.iterative.rule.test.PlanBuilder)7 SemiJoinNode (com.facebook.presto.sql.planner.plan.SemiJoinNode)7 Expression (com.facebook.presto.sql.tree.Expression)7 Session (com.facebook.presto.Session)6 OriginalExpressionUtils.castToRowExpression (com.facebook.presto.sql.relational.OriginalExpressionUtils.castToRowExpression)5 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)5 Map (java.util.Map)5 Objects.requireNonNull (java.util.Objects.requireNonNull)5 Optional (java.util.Optional)5 LogicalRowExpressions (com.facebook.presto.expressions.LogicalRowExpressions)4