@VisibleForTesting JoinEnumerator(CostComparator costComparator, Expression filter, Context context) { this.context = requireNonNull(context); this.session = requireNonNull(context.getSession(), "session is null"); this.costProvider = requireNonNull(context.getCostProvider(), "costProvider is null"); this.resultComparator = costComparator.forSession(session).onResultOf(result -> result.cost); this.idAllocator = requireNonNull(context.getIdAllocator(), "idAllocator is null"); this.allFilter = requireNonNull(filter, "filter is null"); this.allFilterInference = createEqualityInference(filter); this.lookup = requireNonNull(context.getLookup(), "lookup is null"); }
@Override public Result apply(AggregationNode parent, Captures captures, Context context) { if (!parent.hasDefaultOutput() || parent.getOutputSymbols().size() != 1) { return Result.empty(); } Map<Symbol, AggregationNode.Aggregation> assignments = parent.getAggregations(); for (Map.Entry<Symbol, AggregationNode.Aggregation> entry : assignments.entrySet()) { AggregationNode.Aggregation aggregation = entry.getValue(); requireNonNull(aggregation, "aggregation is null"); Signature signature = aggregation.getSignature(); FunctionCall functionCall = aggregation.getCall(); if (!"count".equals(signature.getName()) || !functionCall.getArguments().isEmpty()) { return Result.empty(); } } if (!assignments.isEmpty() && isScalar(parent.getSource(), context.getLookup())) { return Result.ofPlanNode(new ValuesNode(parent.getId(), parent.getOutputSymbols(), ImmutableList.of(ImmutableList.of(new LongLiteral("1"))))); } return Result.empty(); } }
@Override public Result apply(LateralJoinNode lateralJoinNode, Captures captures, Context context) { PlanNode subquery = lateralJoinNode.getSubquery(); PlanNodeDecorrelator planNodeDecorrelator = new PlanNodeDecorrelator(context.getIdAllocator(), context.getLookup()); Optional<DecorrelatedNode> decorrelatedNodeOptional = planNodeDecorrelator.decorrelateFilters(subquery, lateralJoinNode.getCorrelation()); return decorrelatedNodeOptional.map(decorrelatedNode -> Result.ofPlanNode(new JoinNode( context.getIdAllocator().getNextId(), lateralJoinNode.getType().toJoinNodeType(), lateralJoinNode.getInput(), decorrelatedNode.getNode(), ImmutableList.of(), lateralJoinNode.getOutputSymbols(), decorrelatedNode.getCorrelatedPredicates(), Optional.empty(), Optional.empty(), Optional.empty()))).orElseGet(Result::empty); } }
|| !(join.getType() == JoinNode.Type.LEFT || join.getType() == JoinNode.Type.RIGHT) || !groupsOnAllColumns(aggregation, getOuterTable(join).getOutputSymbols()) || !isDistinct(context.getLookup().resolve(getOuterTable(join)), context.getLookup()::resolve)) { return Result.empty(); Optional<PlanNode> resultNode = coalesceWithNullAggregation(rewrittenAggregation, rewrittenJoin, context.getSymbolAllocator(), context.getIdAllocator(), context.getLookup()); if (!resultNode.isPresent()) { return Result.empty();
@Override public Result apply(LateralJoinNode lateralJoinNode, Captures captures, Context context) PlanNode subquery = context.getLookup().resolve(lateralJoinNode.getSubquery()); if (!searchFrom(subquery, context.getLookup()) .where(EnforceSingleRowNode.class::isInstance) .recurseOnlyWhen(ProjectNode.class::isInstance) PlanNode rewrittenSubquery = searchFrom(subquery, context.getLookup()) .where(EnforceSingleRowNode.class::isInstance) .recurseOnlyWhen(ProjectNode.class::isInstance) .removeFirst(); if (isAtMostScalar(rewrittenSubquery, context.getLookup())) { return Result.ofPlanNode(new LateralJoinNode( context.getIdAllocator().getNextId(),
private Optional<PlanNode> rewriteToNonDefaultAggregation(ApplyNode applyNode, Context context) { checkState(applyNode.getSubquery().getOutputSymbols().isEmpty(), "Expected subquery output symbols to be pruned"); Symbol exists = getOnlyElement(applyNode.getSubqueryAssignments().getSymbols()); Symbol subqueryTrue = context.getSymbolAllocator().newSymbol("subqueryTrue", BOOLEAN); Assignments.Builder assignments = Assignments.builder(); assignments.putIdentities(applyNode.getInput().getOutputSymbols()); assignments.put(exists, new CoalesceExpression(ImmutableList.of(subqueryTrue.toSymbolReference(), BooleanLiteral.FALSE_LITERAL))); PlanNode subquery = new ProjectNode( context.getIdAllocator().getNextId(), new LimitNode( context.getIdAllocator().getNextId(), applyNode.getSubquery(), 1L, false), Assignments.of(subqueryTrue, TRUE_LITERAL)); PlanNodeDecorrelator decorrelator = new PlanNodeDecorrelator(context.getIdAllocator(), context.getLookup()); if (!decorrelator.decorrelateFilters(subquery, applyNode.getCorrelation()).isPresent()) { return Optional.empty(); } return Optional.of(new ProjectNode(context.getIdAllocator().getNextId(), new LateralJoinNode( applyNode.getId(), applyNode.getInput(), subquery, applyNode.getCorrelation(), LEFT, applyNode.getOriginSubquery()), assignments.build())); }
@Override public Result apply(AggregationNode aggregation, Captures captures, Context context) { Lookup lookup = context.getLookup(); PlanNodeIdAllocator idAllocator = context.getIdAllocator(); Session session = context.getSession(); Optional<PlanNode> rewrittenSource = recurseToPartial(lookup.resolve(aggregation.getSource()), lookup, idAllocator); if (!rewrittenSource.isPresent()) { return Result.empty(); } PlanNode source = rewrittenSource.get(); if (getTaskConcurrency(session) > 1) { source = ExchangeNode.partitionedExchange( idAllocator.getNextId(), ExchangeNode.Scope.LOCAL, source, new PartitioningScheme(Partitioning.create(FIXED_ARBITRARY_DISTRIBUTION, ImmutableList.of()), source.getOutputSymbols())); source = new AggregationNode( idAllocator.getNextId(), source, inputsAsOutputs(aggregation.getAggregations()), aggregation.getGroupingSets(), aggregation.getPreGroupedSymbols(), AggregationNode.Step.INTERMEDIATE, aggregation.getHashSymbol(), aggregation.getGroupIdSymbol()); source = ExchangeNode.gatheringExchange(idAllocator.getNextId(), ExchangeNode.Scope.LOCAL, source); } return Result.ofPlanNode(aggregation.replaceChildren(ImmutableList.of(source))); }
@Override public Result apply(LateralJoinNode parent, Captures captures, Context context) { List<ValuesNode> values = searchFrom(parent.getSubquery(), context.getLookup()) .recurseOnlyWhen(ProjectNode.class::isInstance) .where(ValuesNode.class::isInstance) .findAll(); if (values.size() != 1 || !isSingleRowValuesWithNoColumns(values.get(0))) { return Result.empty(); } List<ProjectNode> subqueryProjections = searchFrom(parent.getSubquery(), context.getLookup()) .where(node -> node instanceof ProjectNode && !node.getOutputSymbols().equals(parent.getCorrelation())) .findAll(); if (subqueryProjections.size() == 0) { return Result.ofPlanNode(parent.getInput()); } else if (subqueryProjections.size() == 1) { Assignments assignments = Assignments.builder() .putIdentities(parent.getInput().getOutputSymbols()) .putAll(subqueryProjections.get(0).getAssignments()) .build(); return Result.ofPlanNode(projectNode(parent.getInput(), assignments, context)); } return Result.empty(); }
@Override public Result apply(LateralJoinNode lateralJoinNode, Captures captures, Context context) { PlanNode subquery = lateralJoinNode.getSubquery(); if (!isScalar(subquery, context.getLookup())) { return Result.empty(); } Optional<AggregationNode> aggregation = findAggregation(subquery, context.getLookup()); if (!(aggregation.isPresent() && aggregation.get().getGroupingKeys().isEmpty())) { return Result.empty(); } ScalarAggregationToJoinRewriter rewriter = new ScalarAggregationToJoinRewriter(functionRegistry, context.getSymbolAllocator(), context.getIdAllocator(), context.getLookup()); PlanNode rewrittenNode = rewriter.rewriteScalarAggregation(lateralJoinNode, aggregation.get()); if (rewrittenNode instanceof LateralJoinNode) { return Result.empty(); } return Result.ofPlanNode(rewrittenNode); }
@Override public Result apply(ApplyNode apply, Captures captures, Context context) { Assignments subqueryAssignments = apply.getSubqueryAssignments(); if (subqueryAssignments.size() != 1) { return Result.empty(); } Expression assignmentExpression = getOnlyElement(subqueryAssignments.getExpressions()); if (!(assignmentExpression instanceof InPredicate)) { return Result.empty(); } InPredicate inPredicate = (InPredicate) assignmentExpression; Symbol inPredicateOutputSymbol = getOnlyElement(subqueryAssignments.getSymbols()); return apply(apply, inPredicate, inPredicateOutputSymbol, context.getLookup(), context.getIdAllocator(), context.getSymbolAllocator()); }
@Override public Result apply(JoinNode node, Captures captures, Context context) { JoinGraph joinGraph = JoinGraph.buildShallowFrom(node, context.getLookup()); if (joinGraph.size() < 3) { return Result.empty(); } List<Integer> joinOrder = getJoinOrder(joinGraph); if (isOriginalOrder(joinOrder)) { return Result.empty(); } PlanNode replacement = buildJoinTree(node.getOutputSymbols(), joinGraph, joinOrder, context.getIdAllocator()); return Result.ofPlanNode(replacement); }
@Override public Result apply(JoinNode joinNode, Captures captures, Context context) { MultiJoinNode multiJoinNode = toMultiJoinNode(joinNode, context.getLookup(), getMaxReorderedJoins(context.getSession())); JoinEnumerator joinEnumerator = new JoinEnumerator( costComparator, multiJoinNode.getFilter(), context); JoinEnumerationResult result = joinEnumerator.chooseJoinOrder(multiJoinNode.getSources(), multiJoinNode.getOutputSymbols()); if (!result.getPlanNode().isPresent()) { return Result.empty(); } return Result.ofPlanNode(result.getPlanNode().get()); }
@Override public Result apply(LateralJoinNode lateralJoinNode, Captures captures, Context context) { PlanNode input = lateralJoinNode.getInput(); PlanNode subquery = lateralJoinNode.getSubquery(); if (isUnreferencedScalar(input, context.getLookup())) { return Result.ofPlanNode(subquery); } if (isUnreferencedScalar(subquery, context.getLookup())) { return Result.ofPlanNode(input); } return Result.empty(); }
private static <T> RuleApplication applyRule(Rule<T> rule, PlanNode planNode, Rule.Context context) { PlanNodeMatcher matcher = new PlanNodeMatcher(context.getLookup()); Match<T> match = matcher.match(rule.getPattern(), planNode); Rule.Result result; if (!rule.isEnabled(context.getSession()) || match.isEmpty()) { result = Rule.Result.empty(); } else { result = rule.apply(match.value(), match.captures(), context); } return new RuleApplication(context.getLookup(), context.getStatsProvider(), context.getSymbolAllocator().getTypes(), result); }
private static boolean mustReplicate(JoinNode joinNode, Context context) { JoinNode.Type type = joinNode.getType(); if (joinNode.getCriteria().isEmpty() && (type == INNER || type == LEFT)) { // There is nothing to partition on return true; } return isAtMostScalar(joinNode.getRight(), context.getLookup()); }