public static Assignments of() { return builder().build(); }
private static Map<Symbol, Symbol> computeIdentityTranslations(Assignments assignments) { Map<Symbol, Symbol> outputToInput = new HashMap<>(); for (Map.Entry<Symbol, Expression> assignment : assignments.getMap().entrySet()) { if (assignment.getValue() instanceof SymbolReference) { outputToInput.put(assignment.getKey(), Symbol.from(assignment.getValue())); } } return outputToInput; }
@Override public List<Symbol> getOutputSymbols() { return assignments.getOutputs(); }
@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()); }
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())); }
if (intersection(node.getSubqueryAssignments().getSymbols(), context.get()).isEmpty()) { return context.rewrite(node.getInput(), context.get()); Assignments.Builder subqueryAssignments = Assignments.builder(); for (Map.Entry<Symbol, Expression> entry : node.getSubqueryAssignments().getMap().entrySet()) { Symbol output = entry.getKey(); Expression expression = entry.getValue();
private PlanNode projectNode(PlanNode source, String symbol, Expression expression) { return new ProjectNode( idAllocator.getNextId(), source, Assignments.of(new Symbol(symbol), expression)); }
Assignments assignments = child.getAssignments().filter(targets::contains); Map<Symbol, Expression> parentAssignments = parent.getAssignments() .entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, .entrySet().stream() .filter(entry -> targets.contains(entry.getKey())) .map(Map.Entry::getValue) .collect(toSet()); Assignments.Builder childAssignments = Assignments.builder(); for (Map.Entry<Symbol, Expression> assignment : child.getAssignments().entrySet()) { if (!targets.contains(assignment.getKey())) { childAssignments.put(assignment); child.getSource(), childAssignments.build()), Assignments.copyOf(parentAssignments)));
private ProjectNode project(PlanNode node, List<Symbol> columns) { return new ProjectNode( idAllocator.getNextId(), node, Assignments.identity(columns)); } }
private PlanNode rewriteToDefaultAggregation(ApplyNode parent, Context context) { Symbol count = context.getSymbolAllocator().newSymbol(COUNT.toString(), BIGINT); Symbol exists = getOnlyElement(parent.getSubqueryAssignments().getSymbols()); return new LateralJoinNode( parent.getId(), parent.getInput(), new ProjectNode( context.getIdAllocator().getNextId(), new AggregationNode( context.getIdAllocator().getNextId(), parent.getSubquery(), ImmutableMap.of(count, new Aggregation(COUNT_CALL, countSignature, Optional.empty())), globalAggregation(), ImmutableList.of(), AggregationNode.Step.SINGLE, Optional.empty(), Optional.empty()), Assignments.of(exists, new ComparisonExpression(GREATER_THAN, count.toSymbolReference(), new Cast(new LongLiteral("0"), BIGINT.toString())))), parent.getCorrelation(), INNER, parent.getOriginSubquery()); } }
@Override public PlanNode visitProject(ProjectNode node, RewriteContext<Expression> context) { Set<Symbol> deterministicSymbols = node.getAssignments().entrySet().stream() .filter(entry -> DeterminismEvaluator.isDeterministic(entry.getValue())) .map(Map.Entry::getKey) .collect(Collectors.toSet()); Predicate<Expression> deterministic = conjunct -> SymbolsExtractor.extractUnique(conjunct).stream() .allMatch(deterministicSymbols::contains); Map<Boolean, List<Expression>> conjuncts = extractConjuncts(context.get()).stream().collect(Collectors.partitioningBy(deterministic)); // Push down conjuncts from the inherited predicate that only depend on deterministic assignments with // certain limitations. List<Expression> deterministicConjuncts = conjuncts.get(true); // We partition the expressions in the deterministicConjuncts into two lists, and only inline the // expressions that are in the inlining targets list. Map<Boolean, List<Expression>> inlineConjuncts = deterministicConjuncts.stream() .collect(Collectors.partitioningBy(expression -> isInliningCandidate(expression, node))); List<Expression> inlinedDeterministicConjuncts = inlineConjuncts.get(true).stream() .map(entry -> inlineSymbols(node.getAssignments().getMap(), entry)) .collect(Collectors.toList()); PlanNode rewrittenNode = context.defaultRewrite(node, combineConjuncts(inlinedDeterministicConjuncts)); // All deterministic conjuncts that contains non-inlining targets, and non-deterministic conjuncts, // if any, will be in the filter node. List<Expression> nonInliningConjuncts = inlineConjuncts.get(false); nonInliningConjuncts.addAll(conjuncts.get(false)); if (!nonInliningConjuncts.isEmpty()) { rewrittenNode = new FilterNode(idAllocator.getNextId(), rewrittenNode, combineConjuncts(nonInliningConjuncts)); } return rewrittenNode; }
Assignments.Builder assignments = Assignments.builder(); // assignments for the new ProjectNode for (Map.Entry<Symbol, Expression> entry : parent.getAssignments().entrySet()) { Expression translatedExpression = inlineSymbols(outputToInput, entry.getValue()); Type type = context.getSymbolAllocator().getTypes().get(entry.getKey());
@Override public Result apply(ProjectNode projectNode, Captures captures, Context context) { Assignments assignments = projectNode.getAssignments().rewrite(x -> rewriter.rewrite(x, context)); if (projectNode.getAssignments().equals(assignments)) { return Result.empty(); } return Result.ofPlanNode(new ProjectNode(projectNode.getId(), projectNode.getSource(), assignments)); } }
public static Function<PlanNode, Set<Symbol>> actualAssignments() { return node -> ((ProjectNode) node).getAssignments().getSymbols(); }
public boolean isIdentity() { for (Map.Entry<Symbol, Expression> entry : assignments.entrySet()) { Expression expression = entry.getValue(); Symbol symbol = entry.getKey(); if (!(expression instanceof SymbolReference && ((SymbolReference) expression).getName().equals(symbol.getName()))) { return false; } } return true; }
public Assignments build() { return new Assignments(assignments); } }
idAllocator.getNextId(), result, Assignments.copyOf(graph.getAssignments().get()));
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())); }
if (intersection(node.getSubqueryAssignments().getSymbols(), context.get()).isEmpty()) { return context.rewrite(node.getInput(), context.get()); Assignments.Builder subqueryAssignments = Assignments.builder(); for (Map.Entry<Symbol, Expression> entry : node.getSubqueryAssignments().getMap().entrySet()) { Symbol output = entry.getKey(); Expression expression = entry.getValue();