private static boolean hasMultipleDistincts(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .filter(e -> e.getCall().isDistinct()) .map(Aggregation::getCall) .map(FunctionCall::getArguments) .map(HashSet::new) .distinct() .count() > 1; }
private static boolean hasMultipleDistincts(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .filter(e -> e.getCall().isDistinct()) .map(Aggregation::getCall) .map(FunctionCall::getArguments) .map(HashSet::new) .distinct() .count() > 1; }
private void checkFunctionCall(Map<Symbol, Aggregation> aggregations) { for (Map.Entry<Symbol, Aggregation> entry : aggregations.entrySet()) { checkCall(entry.getKey(), entry.getValue().getCall()); } }
@Override public Void visitAggregation(AggregationNode node, Void context) { StringBuilder builder = new StringBuilder(); for (Map.Entry<Symbol, Aggregation> entry : node.getAggregations().entrySet()) { if (entry.getValue().getMask().isPresent()) { builder.append(format("%s := %s (mask = %s)\\n", entry.getKey(), entry.getValue().getCall(), entry.getValue().getMask().get())); } else { builder.append(format("%s := %s\\n", entry.getKey(), entry.getValue().getCall())); } } printNode(node, format("Aggregate[%s]", node.getStep()), builder.toString(), NODE_COLORS.get(NodeType.AGGREGATE)); return node.getSource().accept(this, context); }
@Override public void validate(PlanNode plan, Session session, Metadata metadata, SqlParser sqlParser, TypeProvider types, WarningCollector warningCollector) { searchFrom(plan) .where(AggregationNode.class::isInstance) .<AggregationNode>findAll() .stream() .flatMap(node -> node.getAggregations().values().stream()) .filter(aggregation -> aggregation.getCall().getFilter().isPresent()) .forEach(ignored -> { throw new IllegalStateException("Generated plan contains unimplemented filtered aggregations"); }); } }
private static boolean isCountOverConstant(AggregationNode.Aggregation aggregation, Assignments inputs) { Signature signature = aggregation.getSignature(); if (!signature.getName().equals("count") || signature.getArgumentTypes().size() != 1) { return false; } Expression argument = aggregation.getCall().getArguments().get(0); if (argument instanceof SymbolReference) { argument = inputs.get(Symbol.from(argument)); } return argument instanceof Literal && !(argument instanceof NullLiteral); } }
private static boolean isCountOverConstant(AggregationNode.Aggregation aggregation, Assignments inputs) { Signature signature = aggregation.getSignature(); if (!signature.getName().equals("count") || signature.getArgumentTypes().size() != 1) { return false; } Expression argument = aggregation.getCall().getArguments().get(0); if (argument instanceof SymbolReference) { argument = inputs.get(Symbol.from(argument)); } return argument instanceof Literal && !(argument instanceof NullLiteral); } }
private static Stream<Symbol> getAggregationInputs(AggregationNode.Aggregation aggregation) { return Streams.concat( SymbolsExtractor.extractUnique(aggregation.getCall()).stream(), aggregation.getMask().map(Stream::of).orElse(Stream.empty())); } }
private static boolean hasFilters(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .anyMatch(e -> e.getCall().getFilter().isPresent() && !e.getMask().isPresent()); // can't handle filtered aggregations with DISTINCT (conservatively, if they have a mask) }
private static boolean isUsingSymbols(AggregationNode.Aggregation aggregation, Set<Symbol> sourceSymbols) { List<Expression> functionArguments = aggregation.getCall().getArguments(); return sourceSymbols.stream() .map(Symbol::toSymbolReference) .anyMatch(functionArguments::contains); }
private static boolean isUsingSymbols(AggregationNode.Aggregation aggregation, Set<Symbol> sourceSymbols) { List<Expression> functionArguments = aggregation.getCall().getArguments(); return sourceSymbols.stream() .map(Symbol::toSymbolReference) .anyMatch(functionArguments::contains); }
private static boolean hasFilters(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .anyMatch(e -> e.getCall().getFilter().isPresent() && !e.getMask().isPresent()); // can't handle filtered aggregations with DISTINCT (conservatively, if they have a mask) }
private void checkFunctionCall(Map<Symbol, Aggregation> aggregations) { for (Map.Entry<Symbol, Aggregation> entry : aggregations.entrySet()) { checkCall(entry.getKey(), entry.getValue().getCall()); } }
@Override public Void visitAggregation(AggregationNode node, ImmutableList.Builder<Expression> context) { node.getAggregations().values() .forEach(aggregation -> context.add(aggregation.getCall())); return super.visitAggregation(node, context); }
private Aggregation map(Aggregation aggregation) { return new Aggregation( (FunctionCall) map(aggregation.getCall()), aggregation.getSignature(), aggregation.getMask().map(this::map)); }
@Override public Void visitAggregation(AggregationNode node, ImmutableList.Builder<Expression> context) { node.getAggregations().values() .forEach(aggregation -> context.add(aggregation.getCall())); return super.visitAggregation(node, context); }
private Aggregation map(Aggregation aggregation) { return new Aggregation( (FunctionCall) map(aggregation.getCall()), aggregation.getSignature(), aggregation.getMask().map(this::map)); }
private static Stream<Symbol> getAggregationInputs(AggregationNode.Aggregation aggregation) { return Streams.concat( SymbolsExtractor.extractUnique(aggregation.getCall()).stream(), aggregation.getMask().map(Stream::of).orElse(Stream.empty())); } }