@Override public Void visitApply(ApplyNode node, Void context) { String parameters = Joiner.on(",").join(node.getCorrelation()); printNode(node, "Apply", parameters, NODE_COLORS.get(NodeType.JOIN)); node.getInput().accept(this, context); node.getSubquery().accept(this, context); return null; }
@Override public Void visitApply(ApplyNode node, Void context) { String parameters = Joiner.on(",").join(node.getCorrelation()); printNode(node, "Apply", parameters, NODE_COLORS.get(NodeType.JOIN)); node.getInput().accept(this, context); node.getSubquery().accept(this, context); return null; }
private List<Symbol> getCorrelation(PlanNode node) { if (node instanceof ApplyNode) { return ((ApplyNode) node).getCorrelation(); } else if (node instanceof LateralJoinNode) { return ((LateralJoinNode) node).getCorrelation(); } else { throw new IllegalStateException("Unexpected plan node: " + node); } }
private List<Symbol> getCorrelation(PlanNode node) { if (node instanceof ApplyNode) { return ((ApplyNode) node).getCorrelation(); } else if (node instanceof LateralJoinNode) { return ((LateralJoinNode) node).getCorrelation(); } else { throw new IllegalStateException("Unexpected plan node: " + node); } }
@Override public Void visitApply(ApplyNode node, Set<Symbol> boundSymbols) { Set<Symbol> subqueryCorrelation = ImmutableSet.<Symbol>builder() .addAll(boundSymbols) .addAll(node.getCorrelation()) .build(); node.getInput().accept(this, boundSymbols); // visit child node.getSubquery().accept(this, subqueryCorrelation); // visit child checkDependencies(node.getInput().getOutputSymbols(), node.getCorrelation(), "APPLY input must provide all the necessary correlation symbols for subquery"); checkDependencies(SymbolsExtractor.extractUnique(node.getSubquery()), node.getCorrelation(), "not all APPLY correlation symbols are used in subquery"); ImmutableSet<Symbol> inputs = ImmutableSet.<Symbol>builder() .addAll(createInputs(node.getSubquery(), boundSymbols)) .addAll(createInputs(node.getInput(), boundSymbols)) .build(); for (Expression expression : node.getSubqueryAssignments().getExpressions()) { Set<Symbol> dependencies = SymbolsExtractor.extractUnique(expression); checkDependencies(inputs, dependencies, "Invalid node. Expression dependencies (%s) not in source plan output (%s)", dependencies, inputs); } return null; }
@Override public Void visitApply(ApplyNode node, Set<Symbol> boundSymbols) { Set<Symbol> subqueryCorrelation = ImmutableSet.<Symbol>builder() .addAll(boundSymbols) .addAll(node.getCorrelation()) .build(); node.getInput().accept(this, boundSymbols); // visit child node.getSubquery().accept(this, subqueryCorrelation); // visit child checkDependencies(node.getInput().getOutputSymbols(), node.getCorrelation(), "APPLY input must provide all the necessary correlation symbols for subquery"); checkDependencies(SymbolsExtractor.extractUnique(node.getSubquery()), node.getCorrelation(), "not all APPLY correlation symbols are used in subquery"); ImmutableSet<Symbol> inputs = ImmutableSet.<Symbol>builder() .addAll(createInputs(node.getSubquery(), boundSymbols)) .addAll(createInputs(node.getInput(), boundSymbols)) .build(); for (Expression expression : node.getSubqueryAssignments().getExpressions()) { Set<Symbol> dependencies = SymbolsExtractor.extractUnique(expression); checkDependencies(inputs, dependencies, "Invalid node. Expression dependencies (%s) not in source plan output (%s)", dependencies, inputs); } return null; }
private Result apply( ApplyNode apply, InPredicate inPredicate, Symbol inPredicateOutputSymbol, Lookup lookup, PlanNodeIdAllocator idAllocator, SymbolAllocator symbolAllocator) { Optional<Decorrelated> decorrelated = new DecorrelatingVisitor(lookup, apply.getCorrelation()) .decorrelate(apply.getSubquery()); if (!decorrelated.isPresent()) { return Result.empty(); } PlanNode projection = buildInPredicateEquivalent( apply, inPredicate, inPredicateOutputSymbol, decorrelated.get(), idAllocator, symbolAllocator); return Result.ofPlanNode(projection); }
private Result apply( ApplyNode apply, InPredicate inPredicate, Symbol inPredicateOutputSymbol, Lookup lookup, PlanNodeIdAllocator idAllocator, SymbolAllocator symbolAllocator) { Optional<Decorrelated> decorrelated = new DecorrelatingVisitor(lookup, apply.getCorrelation()) .decorrelate(apply.getSubquery()); if (!decorrelated.isPresent()) { return Result.empty(); } PlanNode projection = buildInPredicateEquivalent( apply, inPredicate, inPredicateOutputSymbol, decorrelated.get(), idAllocator, symbolAllocator); return Result.ofPlanNode(projection); }
@Override public PlanNode visitApply(ApplyNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getInput()); PlanNode subquery = context.rewrite(node.getSubquery()); List<Symbol> canonicalCorrelation = Lists.transform(node.getCorrelation(), this::canonicalize); return new ApplyNode(node.getId(), source, subquery, canonicalize(node.getSubqueryAssignments()), canonicalCorrelation, node.getOriginSubquery()); }
@Override public PlanNode visitApply(ApplyNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getInput()); PlanNode subquery = context.rewrite(node.getSubquery()); List<Symbol> canonicalCorrelation = Lists.transform(node.getCorrelation(), this::canonicalize); return new ApplyNode(node.getId(), source, subquery, canonicalize(node.getSubqueryAssignments()), canonicalCorrelation, node.getOriginSubquery()); }
@Override public Void visitApply(ApplyNode node, Integer indent) { print(indent, "- Apply[%s] => [%s]", node.getCorrelation(), formatOutputs(node.getOutputSymbols())); printPlanNodesStatsAndCost(indent + 2, node); printStats(indent + 2, node.getId()); printAssignments(node.getSubqueryAssignments(), indent + 4); return processChildren(node, indent + 1); }
@Override public Void visitApply(ApplyNode node, Integer indent) { print(indent, "- Apply[%s] => [%s]", node.getCorrelation(), formatOutputs(node.getOutputSymbols())); printPlanNodesStatsAndCost(indent + 2, node); printStats(indent + 2, node.getId()); printAssignments(node.getSubqueryAssignments(), indent + 4); return processChildren(node, indent + 1); }
@Override public PlanNode optimize(PlanNode plan, Session session, TypeProvider types, SymbolAllocator symbolAllocator, PlanNodeIdAllocator idAllocator, WarningCollector warningCollector) { searchFrom(plan).where(ApplyNode.class::isInstance) .findFirst() .ifPresent(node -> { ApplyNode applyNode = (ApplyNode) node; throw error(applyNode.getCorrelation(), applyNode.getOriginSubquery()); }); searchFrom(plan).where(LateralJoinNode.class::isInstance) .findFirst() .ifPresent(node -> { LateralJoinNode lateralJoinNode = (LateralJoinNode) node; throw error(lateralJoinNode.getCorrelation(), lateralJoinNode.getOriginSubquery()); }); return plan; }
@Override public PlanNode optimize(PlanNode plan, Session session, TypeProvider types, SymbolAllocator symbolAllocator, PlanNodeIdAllocator idAllocator, WarningCollector warningCollector) { searchFrom(plan).where(ApplyNode.class::isInstance) .findFirst() .ifPresent(node -> { ApplyNode applyNode = (ApplyNode) node; throw error(applyNode.getCorrelation(), applyNode.getOriginSubquery()); }); searchFrom(plan).where(LateralJoinNode.class::isInstance) .findFirst() .ifPresent(node -> { LateralJoinNode lateralJoinNode = (LateralJoinNode) node; throw error(lateralJoinNode.getCorrelation(), lateralJoinNode.getOriginSubquery()); }); return plan; }
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())); }
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())); }
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 Result apply(ApplyNode applyNode, Captures captures, Context context) { Assignments subqueryAssignments = applyNode.getSubqueryAssignments().rewrite(x -> rewriter.rewrite(x, context)); if (applyNode.getSubqueryAssignments().equals(subqueryAssignments)) { return Result.empty(); } return Result.ofPlanNode(new ApplyNode( applyNode.getId(), applyNode.getInput(), applyNode.getSubquery(), subqueryAssignments, applyNode.getCorrelation(), applyNode.getOriginSubquery())); } }
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 Result apply(ApplyNode applyNode, Captures captures, Context context) { Assignments subqueryAssignments = applyNode.getSubqueryAssignments().rewrite(x -> rewriter.rewrite(x, context)); if (applyNode.getSubqueryAssignments().equals(subqueryAssignments)) { return Result.empty(); } return Result.ofPlanNode(new ApplyNode( applyNode.getId(), applyNode.getInput(), applyNode.getSubquery(), subqueryAssignments, applyNode.getCorrelation(), applyNode.getOriginSubquery())); } }