@Override public Range<Long> visitGroupReference(GroupReference node, Void context) { return lookup.resolve(node).accept(this, context); }
@Override public Void visitGroupReference(GroupReference node, ImmutableList.Builder<Expression> context) { return lookup.resolve(node).accept(this, context); }
@Override public PlanNode visitGroupReference(GroupReference node, Void context) { return lookup.resolve(node).accept(this, context); } }
public Optional<Decorrelated> decorrelate(PlanNode reference) { return lookup.resolve(reference).accept(this, reference); }
private <T extends PlanNode> void findAllRecursive(PlanNode node, ImmutableList.Builder<T> nodes) { node = lookup.resolve(node); if (where.test(node)) { nodes.add((T) node); } if (recurseOnlyWhen.test(node)) { for (PlanNode source : node.getSources()) { findAllRecursive(source, nodes); } } }
private <T extends PlanNode> Optional<T> findFirstRecursive(PlanNode node) { node = lookup.resolve(node); if (where.test(node)) { return Optional.of((T) node); } if (recurseOnlyWhen.test(node)) { for (PlanNode source : node.getSources()) { Optional<T> found = findFirstRecursive(source); if (found.isPresent()) { return found; } } } return Optional.empty(); }
@Override public Optional<DecorrelationResult> visitEnforceSingleRow(EnforceSingleRowNode node, Void context) { Optional<DecorrelationResult> childDecorrelationResultOptional = lookup.resolve(node.getSource()).accept(this, null); return childDecorrelationResultOptional.filter(result -> result.atMostSingleRow); }
private PlanNode replaceFirstRecursive(PlanNode node, PlanNode nodeToReplace) { node = lookup.resolve(node); if (where.test(node)) { return nodeToReplace; } List<PlanNode> sources = node.getSources(); if (sources.isEmpty()) { return node; } else if (sources.size() == 1) { return replaceChildren(node, ImmutableList.of(replaceFirstRecursive(node, sources.get(0)))); } else { throw new IllegalArgumentException("Unable to replace first node when a node has multiple children, use replaceAll instead"); } }
private PlanNode replaceAllRecursive(PlanNode node, PlanNode nodeToReplace) { node = lookup.resolve(node); if (where.test(node)) { return nodeToReplace; } if (recurseOnlyWhen.test(node)) { List<PlanNode> sources = node.getSources().stream() .map(source -> replaceAllRecursive(source, nodeToReplace)) .collect(toImmutableList()); return replaceChildren(node, sources); } return node; }
public Optional<DecorrelatedNode> decorrelateFilters(PlanNode node, List<Symbol> correlation) { // TODO: when correlations list empty this should return immediately. However this isn't correct // right now, because for nested subqueries correlation list is empty while there might exists usages // of the outer most correlated symbols Optional<DecorrelationResult> decorrelationResultOptional = lookup.resolve(node).accept(new DecorrelatingVisitor(correlation), null); return decorrelationResultOptional.flatMap(decorrelationResult -> decorrelatedNode( decorrelationResult.correlatedPredicates, decorrelationResult.node, correlation)); }
private PlanNode removeAllRecursive(PlanNode node) { node = lookup.resolve(node); if (where.test(node)) { checkArgument( node.getSources().size() == 1, "Unable to remove plan node as it contains 0 or more than 1 children"); return node.getSources().get(0); } if (recurseOnlyWhen.test(node)) { List<PlanNode> sources = node.getSources().stream() .map(this::removeAllRecursive) .collect(toImmutableList()); return replaceChildren(node, sources); } return node; }
private PlanNode removeFirstRecursive(PlanNode node) { node = lookup.resolve(node); if (where.test(node)) { checkArgument( node.getSources().size() == 1, "Unable to remove plan node as it contains 0 or more than 1 children"); return node.getSources().get(0); } if (recurseOnlyWhen.test(node)) { List<PlanNode> sources = node.getSources(); if (sources.isEmpty()) { return node; } else if (sources.size() == 1) { return replaceChildren(node, ImmutableList.of(removeFirstRecursive(sources.get(0)))); } else { throw new IllegalArgumentException("Unable to remove first node when a node has multiple children, use removeAll instead"); } } return node; }
@Override protected Optional<PlanNodeStatsEstimate> doCalculate(FilterNode node, StatsProvider sourceStats, Lookup lookup, Session session, TypeProvider types) { PlanNode nodeSource = lookup.resolve(node.getSource()); SemiJoinNode semiJoinNode; if (nodeSource instanceof ProjectNode) { ProjectNode projectNode = (ProjectNode) nodeSource; if (!projectNode.isIdentity()) { return Optional.empty(); } PlanNode projectNodeSource = lookup.resolve(projectNode.getSource()); if (!(projectNodeSource instanceof SemiJoinNode)) { return Optional.empty(); } semiJoinNode = (SemiJoinNode) projectNodeSource; } else if (nodeSource instanceof SemiJoinNode) { semiJoinNode = (SemiJoinNode) nodeSource; } else { return Optional.empty(); } return calculate(node, semiJoinNode, sourceStats, session, types); }
/** * Recurse through a series of preceding ExchangeNodes and ProjectNodes to find the preceding PARTIAL aggregation */ private Optional<PlanNode> recurseToPartial(PlanNode node, Lookup lookup, PlanNodeIdAllocator idAllocator) { if (node instanceof AggregationNode && ((AggregationNode) node).getStep() == AggregationNode.Step.PARTIAL) { return Optional.of(addGatheringIntermediate((AggregationNode) node, idAllocator)); } if (!(node instanceof ExchangeNode) && !(node instanceof ProjectNode)) { return Optional.empty(); } ImmutableList.Builder<PlanNode> builder = ImmutableList.builder(); for (PlanNode source : node.getSources()) { Optional<PlanNode> planNode = recurseToPartial(lookup.resolve(source), lookup, idAllocator); if (!planNode.isPresent()) { return Optional.empty(); } builder.add(planNode.get()); } return Optional.of(node.replaceChildren(builder.build())); }
@Override public <T> Match<T> matchWith(WithPattern<T> withPattern, Object object, Captures captures) { Function<? super T, Optional<?>> property = withPattern.getProperty().getFunction(); Optional<?> propertyValue = property.apply((T) object); Optional<?> resolvedValue = propertyValue .map(value -> value instanceof GroupReference ? lookup.resolve(((GroupReference) value)) : value); Match<?> propertyMatch = resolvedValue .map(value -> match(withPattern.getPattern(), value, captures)) .orElse(Match.empty()); return propertyMatch.map(ignored -> (T) object); } }
@Override public JoinGraph visitGroupReference(GroupReference node, Context context) { PlanNode dereferenced = lookup.resolve(node); JoinGraph graph = dereferenced.accept(this, context); if (isTrivialGraph(graph)) { return replacementGraph(dereferenced, node, context); } return graph; }
private void flattenNode(PlanNode node, int limit) { PlanNode resolved = lookup.resolve(node); // (limit - 2) because you need to account for adding left and right side if (!(resolved instanceof JoinNode) || (sources.size() > (limit - 2))) { sources.add(node); return; } JoinNode joinNode = (JoinNode) resolved; if (joinNode.getType() != INNER || !isDeterministic(joinNode.getFilter().orElse(TRUE_LITERAL)) || joinNode.getDistributionType().isPresent()) { sources.add(node); return; } // we set the left limit to limit - 1 to account for the node on the right flattenNode(joinNode.getLeft(), limit - 1); flattenNode(joinNode.getRight(), limit); joinNode.getCriteria().stream() .map(EquiJoinClause::toExpression) .forEach(filters::add); joinNode.getFilter().ifPresent(filters::add); }
@Override public Optional<DecorrelationResult> visitProject(ProjectNode node, Void context) { Optional<DecorrelationResult> childDecorrelationResultOptional = lookup.resolve(node.getSource()).accept(this, null); if (!childDecorrelationResultOptional.isPresent()) { return Optional.empty(); } DecorrelationResult childDecorrelationResult = childDecorrelationResultOptional.get(); Set<Symbol> nodeOutputSymbols = ImmutableSet.copyOf(node.getOutputSymbols()); List<Symbol> symbolsToAdd = childDecorrelationResult.symbolsToPropagate.stream() .filter(symbol -> !nodeOutputSymbols.contains(symbol)) .collect(toImmutableList()); Assignments assignments = Assignments.builder() .putAll(node.getAssignments()) .putIdentities(symbolsToAdd) .build(); return Optional.of(new DecorrelationResult( new ProjectNode(idAllocator.getNextId(), childDecorrelationResult.node, assignments), childDecorrelationResult.symbolsToPropagate, childDecorrelationResult.correlatedPredicates, childDecorrelationResult.correlatedSymbolsMapping, childDecorrelationResult.atMostSingleRow)); }
public PlanNode rewriteScalarAggregation(LateralJoinNode lateralJoinNode, AggregationNode aggregation) { List<Symbol> correlation = lateralJoinNode.getCorrelation(); Optional<DecorrelatedNode> source = planNodeDecorrelator.decorrelateFilters(lookup.resolve(aggregation.getSource()), correlation); if (!source.isPresent()) { return lateralJoinNode; } Symbol nonNull = symbolAllocator.newSymbol("non_null", BooleanType.BOOLEAN); Assignments scalarAggregationSourceAssignments = Assignments.builder() .putIdentities(source.get().getNode().getOutputSymbols()) .put(nonNull, TRUE_LITERAL) .build(); ProjectNode scalarAggregationSourceWithNonNullableSymbol = new ProjectNode( idAllocator.getNextId(), source.get().getNode(), scalarAggregationSourceAssignments); return rewriteScalarAggregation( lateralJoinNode, aggregation, scalarAggregationSourceWithNonNullableSymbol, source.get().getCorrelatedPredicates(), nonNull); }
@Override public MatchResult visitGroupReference(GroupReference node, PlanMatchPattern pattern) { MatchResult match = lookup.resolve(node).accept(this, pattern); if (match.isMatch()) { return match; } return matchLeaf(node, pattern, pattern.shapeMatches(node)); }