}
// 1.a Rewrite DISTINCT aggregates as a group by
// All DISTINCT argument lists must match see TupleAnalyzer::analyzeAggregations
if (Iterables.any(analysis.getAggregates(node), distinctPredicate())) {
AggregationNode aggregation = new AggregationNode(idAllocator.getNextId(),
subPlan.getRoot(),
subPlan.getRoot().getOutputSymbols(),
ImmutableMap.<Symbol, FunctionCall>of(),
ImmutableMap.<Symbol, FunctionHandle>of());
subPlan = new PlanBuilder(subPlan.getTranslations(), aggregation);
}
// 2. Aggregate
ImmutableMap.Builder<Symbol, FunctionCall> aggregationAssignments = ImmutableMap.builder();
ImmutableMap.Builder<Symbol, FunctionHandle> functions = ImmutableMap.builder();
// 2.a. Rewrite aggregates in terms of pre-projected inputs
TranslationMap translations = new TranslationMap(subPlan.getRelationPlan(), analysis);
for (FunctionCall aggregate : analysis.getAggregates(node)) {
FunctionCall rewritten = (FunctionCall) subPlan.rewrite(aggregate);
Symbol newSymbol = symbolAllocator.newSymbol(rewritten, analysis.getType(aggregate));
aggregationAssignments.put(newSymbol, rewritten);
translations.put(aggregate, newSymbol);
functions.put(newSymbol, analysis.getFunctionInfo(aggregate).getHandle());
}
// 2.b. Rewrite group by expressions in terms of pre-projected inputs
Set<Symbol> groupBySymbols = new LinkedHashSet<>();
for (FieldOrExpression fieldOrExpression : analysis.getGroupByExpressions(node)) {
Symbol symbol = subPlan.translate(fieldOrExpression);
groupBySymbols.add(symbol);
translations.put(fieldOrExpression, symbol);
}
return new PlanBuilder(translations, new AggregationNode(idAllocator.getNextId(), subPlan.getRoot(), ImmutableList.copyOf(groupBySymbols), aggregationAssignments.build(), functions.build()));
}