@Override public PlanNode replaceChildren(List<PlanNode> newChildren) { return new FilterNode(getId(), Iterables.getOnlyElement(newChildren), predicate); } }
@Override public PlanNode visitMarkDistinct(MarkDistinctNode node, RewriteContext<Expression> context) { Set<Symbol> pushDownableSymbols = ImmutableSet.copyOf(node.getDistinctSymbols()); Map<Boolean, List<Expression>> conjuncts = extractConjuncts(context.get()).stream() .collect(Collectors.partitioningBy(conjunct -> SymbolsExtractor.extractUnique(conjunct).stream().allMatch(pushDownableSymbols::contains))); PlanNode rewrittenNode = context.defaultRewrite(node, combineConjuncts(conjuncts.get(true))); if (!conjuncts.get(false).isEmpty()) { rewrittenNode = new FilterNode(idAllocator.getNextId(), rewrittenNode, combineConjuncts(conjuncts.get(false))); } return rewrittenNode; }
@Override public PlanNode visitGroupId(GroupIdNode node, RewriteContext<Expression> context) { Map<Symbol, SymbolReference> commonGroupingSymbolMapping = node.getGroupingColumns().entrySet().stream() .filter(entry -> node.getCommonGroupingColumns().contains(entry.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().toSymbolReference())); Predicate<Expression> pushdownEligiblePredicate = conjunct -> SymbolsExtractor.extractUnique(conjunct).stream() .allMatch(commonGroupingSymbolMapping.keySet()::contains); Map<Boolean, List<Expression>> conjuncts = extractConjuncts(context.get()).stream().collect(Collectors.partitioningBy(pushdownEligiblePredicate)); // Push down conjuncts from the inherited predicate that apply to common grouping symbols PlanNode rewrittenNode = context.defaultRewrite(node, inlineSymbols(commonGroupingSymbolMapping, combineConjuncts(conjuncts.get(true)))); // All other conjuncts, if any, will be in the filter node. if (!conjuncts.get(false).isEmpty()) { rewrittenNode = new FilterNode(idAllocator.getNextId(), rewrittenNode, combineConjuncts(conjuncts.get(false))); } return rewrittenNode; }
@Override public PlanNode visitFilter(FilterNode node, RewriteContext<Set<Symbol>> context) { Set<Symbol> expectedInputs = ImmutableSet.<Symbol>builder() .addAll(SymbolsExtractor.extractUnique(node.getPredicate())) .addAll(context.get()) .build(); PlanNode source = context.rewrite(node.getSource(), expectedInputs); return new FilterNode(node.getId(), source, node.getPredicate()); }
public FilterNode filter(Expression predicate, PlanNode source) { return new FilterNode(idAllocator.getNextId(), source, predicate); }
private static FilterNode filter(PlanNode source, Expression predicate) { return new FilterNode(newId(), source, predicate); }
private FilterNode addFilterForIntersect(AggregationNode aggregation) { ImmutableList<Expression> predicates = aggregation.getAggregations().keySet().stream() .map(column -> new ComparisonExpression(GREATER_THAN_OR_EQUAL, column.toSymbolReference(), new GenericLiteral("BIGINT", "1"))) .collect(toImmutableList()); return new FilterNode(idAllocator.getNextId(), aggregation, ExpressionUtils.and(predicates)); }
private JoinEnumerationResult getJoinSource(LinkedHashSet<PlanNode> nodes, List<Symbol> outputSymbols) { if (nodes.size() == 1) { PlanNode planNode = getOnlyElement(nodes); ImmutableList.Builder<Expression> predicates = ImmutableList.builder(); predicates.addAll(allFilterInference.generateEqualitiesPartitionedBy(outputSymbols::contains).getScopeEqualities()); stream(nonInferrableConjuncts(allFilter)) .map(conjunct -> allFilterInference.rewriteExpression(conjunct, outputSymbols::contains)) .filter(Objects::nonNull) .forEach(predicates::add); Expression filter = combineConjuncts(predicates.build()); if (!TRUE_LITERAL.equals(filter)) { planNode = new FilterNode(idAllocator.getNextId(), planNode, filter); } return createJoinEnumerationResult(planNode); } return chooseJoinOrder(nodes, outputSymbols); }
@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; }
@Override public PlanNode visitWindow(WindowNode node, RewriteContext<Expression> context) { List<Symbol> partitionSymbols = node.getPartitionBy(); // TODO: This could be broader. We can push down conjucts if they are constant for all rows in a window partition. // The simplest way to guarantee this is if the conjucts are deterministic functions of the partitioning symbols. // This can leave out cases where they're both functions of some set of common expressions and the partitioning // function is injective, but that's a rare case. The majority of window nodes are expected to be partitioned by // pre-projected symbols. Predicate<Expression> isSupported = conjunct -> DeterminismEvaluator.isDeterministic(conjunct) && SymbolsExtractor.extractUnique(conjunct).stream() .allMatch(partitionSymbols::contains); Map<Boolean, List<Expression>> conjuncts = extractConjuncts(context.get()).stream().collect(Collectors.partitioningBy(isSupported)); PlanNode rewrittenNode = context.defaultRewrite(node, combineConjuncts(conjuncts.get(true))); if (!conjuncts.get(false).isEmpty()) { rewrittenNode = new FilterNode(idAllocator.getNextId(), rewrittenNode, combineConjuncts(conjuncts.get(false))); } return rewrittenNode; }
private FilterNode addFilterForExcept(AggregationNode aggregation, Symbol firstSource, List<Symbol> remainingSources) { ImmutableList.Builder<Expression> predicatesBuilder = ImmutableList.builder(); predicatesBuilder.add(new ComparisonExpression(GREATER_THAN_OR_EQUAL, firstSource.toSymbolReference(), new GenericLiteral("BIGINT", "1"))); for (Symbol symbol : remainingSources) { predicatesBuilder.add(new ComparisonExpression(EQUAL, symbol.toSymbolReference(), new GenericLiteral("BIGINT", "0"))); } return new FilterNode(idAllocator.getNextId(), aggregation, ExpressionUtils.and(predicatesBuilder.build())); }
@Override public PlanNode visitTableScan(TableScanNode node, RewriteContext<Expression> context) { Expression predicate = simplifyExpression(context.get()); if (!TRUE_LITERAL.equals(predicate)) { return new FilterNode(idAllocator.getNextId(), node, predicate); } return node; }
private PlanNode rewriteFilterSource(FilterNode filterNode, PlanNode source, Symbol rowNumberSymbol, int upperBound) { ExtractionResult extractionResult = fromPredicate(metadata, session, filterNode.getPredicate(), types); TupleDomain<Symbol> tupleDomain = extractionResult.getTupleDomain(); if (!isEqualRange(tupleDomain, rowNumberSymbol, upperBound)) { return new FilterNode(filterNode.getId(), source, filterNode.getPredicate()); } // Remove the row number domain because it is absorbed into the node Map<Symbol, Domain> newDomains = tupleDomain.getDomains().get().entrySet().stream() .filter(entry -> !entry.getKey().equals(rowNumberSymbol)) .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); // Construct a new predicate TupleDomain<Symbol> newTupleDomain = TupleDomain.withColumnDomains(newDomains); Expression newPredicate = ExpressionUtils.combineConjuncts( extractionResult.getRemainingExpression(), domainTranslator.toPredicate(newTupleDomain)); if (newPredicate.equals(BooleanLiteral.TRUE_LITERAL)) { return source; } return new FilterNode(filterNode.getId(), source, newPredicate); }
@Override public PlanNode visitFilter(FilterNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getSource()); return new FilterNode(node.getId(), source, canonicalize(node.getPredicate())); }
@Override public PlanNode visitFilter(FilterNode node, RewriteContext<Void> context) { FilterNode rewrittenNode = (FilterNode) context.defaultRewrite(node); return new FilterNode(idAllocator.getNextId(), rewrittenNode.getSource(), replaceExpression(rewrittenNode.getPredicate(), mapping)); }
@Override public PlanNode visitPlan(PlanNode node, RewriteContext<Expression> context) { PlanNode rewrittenNode = context.defaultRewrite(node, TRUE_LITERAL); if (!context.get().equals(TRUE_LITERAL)) { // Drop in a FilterNode b/c we cannot push our predicate down any further rewrittenNode = new FilterNode(idAllocator.getNextId(), rewrittenNode, context.get()); } return rewrittenNode; }
private PlanBuilder filter(PlanBuilder subPlan, Expression predicate, Node node) { if (predicate == null) { return subPlan; } // rewrite expressions which contain already handled subqueries Expression rewrittenBeforeSubqueries = subPlan.rewrite(predicate); subPlan = subqueryPlanner.handleSubqueries(subPlan, rewrittenBeforeSubqueries, node); Expression rewrittenAfterSubqueries = subPlan.rewrite(predicate); return subPlan.withNewRoot(new FilterNode(idAllocator.getNextId(), subPlan.getRoot(), rewrittenAfterSubqueries)); }
@Override public Result apply(SampleNode sample, Captures captures, Context context) { return Result.ofPlanNode(new FilterNode( sample.getId(), sample.getSource(), new ComparisonExpression( ComparisonExpression.Operator.LESS_THAN, new FunctionCall(QualifiedName.of("rand"), ImmutableList.of()), new DoubleLiteral(Double.toString(sample.getSampleRatio()))))); } }
@Override public Result apply(FilterNode parent, Captures captures, Context context) { FilterNode child = captures.get(CHILD); return Result.ofPlanNode( new FilterNode( parent.getId(), child.getSource(), combineConjuncts(child.getPredicate(), parent.getPredicate()))); } }
@Override public Result apply(FilterNode filterNode, Captures captures, Context context) { Expression rewritten = rewriter.rewrite(filterNode.getPredicate(), context); if (filterNode.getPredicate().equals(rewritten)) { return Result.empty(); } return Result.ofPlanNode(new FilterNode(filterNode.getId(), filterNode.getSource(), rewritten)); } }