@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, 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, ImmutableList.Builder<Expression> context) { context.addAll(node.getSubqueryAssignments().getExpressions()); return super.visitApply(node, context); } }
@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 Result apply(ApplyNode applyNode, Captures captures, Context context) { if (applyNode.getSubqueryAssignments().size() != 1) { return Result.empty(); } Expression expression = getOnlyElement(applyNode.getSubqueryAssignments().getExpressions()); if (!(expression instanceof InPredicate)) { return Result.empty(); } InPredicate inPredicate = (InPredicate) expression; Symbol semiJoinSymbol = getOnlyElement(applyNode.getSubqueryAssignments().getSymbols()); SemiJoinNode replacement = new SemiJoinNode(context.getIdAllocator().getNextId(), applyNode.getInput(), applyNode.getSubquery(), Symbol.from(inPredicate.getValue()), Symbol.from(inPredicate.getValueList()), semiJoinSymbol, Optional.empty(), Optional.empty(), Optional.empty()); return Result.ofPlanNode(replacement); } }
@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 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 PlanBuilder appendApplyNode( PlanBuilder subPlan, Node subquery, PlanNode subqueryNode, Assignments subqueryAssignments, boolean correlationAllowed) { Map<Expression, Expression> correlation = extractCorrelation(subPlan, subqueryNode); if (!correlationAllowed && !correlation.isEmpty()) { throw notSupportedException(subquery, "Correlated subquery in given context"); } subPlan = subPlan.appendProjections(correlation.keySet(), symbolAllocator, idAllocator); subqueryNode = replaceExpressionsWithSymbols(subqueryNode, correlation); TranslationMap translations = subPlan.copyTranslations(); PlanNode root = subPlan.getRoot(); return new PlanBuilder(translations, new ApplyNode(idAllocator.getNextId(), root, subqueryNode, subqueryAssignments, ImmutableList.copyOf(SymbolsExtractor.extractUnique(correlation.values())), subquery), analysis.getParameters()); }
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 Result apply(ApplyNode applyNode, Captures captures, Context context) { return Result.ofPlanNode(applyNode.getInput()); } }
@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, ImmutableList.Builder<Expression> context) { context.addAll(node.getSubqueryAssignments().getExpressions()); return super.visitApply(node, context); } }
@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 Result apply(ApplyNode applyNode, Captures captures, Context context) { if (applyNode.getSubqueryAssignments().size() != 1) { return Result.empty(); } Expression expression = getOnlyElement(applyNode.getSubqueryAssignments().getExpressions()); if (!(expression instanceof InPredicate)) { return Result.empty(); } InPredicate inPredicate = (InPredicate) expression; Symbol semiJoinSymbol = getOnlyElement(applyNode.getSubqueryAssignments().getSymbols()); SemiJoinNode replacement = new SemiJoinNode(context.getIdAllocator().getNextId(), applyNode.getInput(), applyNode.getSubquery(), Symbol.from(inPredicate.getValue()), Symbol.from(inPredicate.getValueList()), semiJoinSymbol, Optional.empty(), Optional.empty(), Optional.empty()); return Result.ofPlanNode(replacement); } }
@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 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 PlanBuilder appendApplyNode( PlanBuilder subPlan, Node subquery, PlanNode subqueryNode, Assignments subqueryAssignments, boolean correlationAllowed) { Map<Expression, Expression> correlation = extractCorrelation(subPlan, subqueryNode); if (!correlationAllowed && !correlation.isEmpty()) { throw notSupportedException(subquery, "Correlated subquery in given context"); } subPlan = subPlan.appendProjections(correlation.keySet(), symbolAllocator, idAllocator); subqueryNode = replaceExpressionsWithSymbols(subqueryNode, correlation); TranslationMap translations = subPlan.copyTranslations(); PlanNode root = subPlan.getRoot(); return new PlanBuilder(translations, new ApplyNode(idAllocator.getNextId(), root, subqueryNode, subqueryAssignments, ImmutableList.copyOf(SymbolsExtractor.extractUnique(correlation.values())), subquery), analysis.getParameters()); }