Refine search
private static AggregationNode.Aggregation countWithFilter(Expression condition) { FunctionCall countCall = new FunctionCall( QualifiedName.of("count"), Optional.empty(), Optional.of(condition), Optional.empty(), false, ImmutableList.<Expression>of()); /* arguments */ return new AggregationNode.Aggregation( countCall, new Signature("count", FunctionKind.AGGREGATE, BIGINT.getTypeSignature()), Optional.<Symbol>empty()); /* mask */ }
if (metadata.isAggregationFunction(node.getName())) { if (!node.getWindow().isPresent()) { List<FunctionCall> aggregateFunctions = extractAggregateFunctions(node.getArguments(), metadata.getFunctionRegistry()); List<FunctionCall> windowFunctions = extractWindowFunctions(node.getArguments()); node, "Cannot nest aggregations inside aggregation '%s': %s", node.getName(), aggregateFunctions); node, "Cannot nest window functions inside aggregation '%s': %s", node.getName(), windowFunctions); if (node.getOrderBy().isPresent()) { List<Expression> sortKeys = node.getOrderBy().get().getSortItems().stream() .map(SortItem::getSortKey) .collect(toImmutableList()); if (node.isDistinct()) { List<FieldId> fieldIds = node.getArguments().stream() .map(NodeRef::of) .collect(toImmutableList()); for (Expression sortKey : sortKeys) { if (!node.getArguments().contains(sortKey) && !fieldIds.contains(columnReferences.get(NodeRef.of(sortKey)))) { throw new SemanticException( ORDER_BY_MUST_BE_IN_AGGREGATE,
private static Predicate<FunctionCall> isAggregationPredicate(FunctionRegistry functionRegistry) { return ((functionCall) -> (functionRegistry.isAggregationFunction(functionCall.getName()) || functionCall.getFilter().isPresent()) && !functionCall.getWindow().isPresent() || functionCall.getOrderBy().isPresent()); }
private static AggregationNode.Aggregation removeDistinct(AggregationNode.Aggregation aggregation) { checkArgument(aggregation.getCall().isDistinct(), "Expected aggregation to have DISTINCT input"); FunctionCall call = aggregation.getCall(); return new AggregationNode.Aggregation( new FunctionCall( call.getName(), call.getWindow(), call.getFilter(), call.getOrderBy(), false, call.getArguments()), aggregation.getSignature(), aggregation.getMask()); } }
@Override protected R visitFunctionCall(FunctionCall node, C context) { for (Expression argument : node.getArguments()) { process(argument, context); } if (node.getOrderBy().isPresent()) { process(node.getOrderBy().get(), context); } if (node.getWindow().isPresent()) { process(node.getWindow().get(), context); } if (node.getFilter().isPresent()) { process(node.getFilter().get(), context); } return null; }
if (node.getAggregations().values().stream().map(Aggregation::getCall).map(FunctionCall::getFilter).anyMatch(Optional::isPresent)) { return context.defaultRewrite(node, Optional.empty()); return context.defaultRewrite(node, Optional.empty()); ImmutableMap.Builder<Symbol, Aggregation> aggregations = ImmutableMap.builder(); ImmutableMap.Builder<Symbol, Symbol> coalesceSymbolsBuilder = ImmutableMap.builder(); for (Map.Entry<Symbol, Aggregation> entry : node.getAggregations().entrySet()) { FunctionCall functionCall = entry.getValue().getCall(); if (entry.getValue().getMask().isPresent()) { aggregations.put(entry.getKey(), new Aggregation( new FunctionCall( functionCall.getName(), functionCall.getWindow(), false, ImmutableList.of(aggregateInfo.getNewDistinctAggregateSymbol().toSymbolReference())), entry.getValue().getSignature(), Optional.empty())); String signatureName = entry.getValue().getSignature().getName(); Aggregation aggregation = new Aggregation( new FunctionCall(functionName, functionCall.getWindow(), false, ImmutableList.of(argument.toSymbolReference())), getFunctionSignature(functionName, argument), Optional.empty());
for (Expression argument : aggregation.getCall().getArguments()) { if (!(argument instanceof LambdaExpression)) { Symbol argumentSymbol = Symbol.from(argument); List<LambdaExpression> lambdaExpressions = aggregation.getCall().getArguments().stream() .filter(LambdaExpression.class::isInstance) .map(LambdaExpression.class::cast) .collect(toImmutableList()); if (!lambdaExpressions.isEmpty()) { List<FunctionType> functionTypes = aggregation.getSignature().getArgumentTypes().stream() .filter(typeSignature -> typeSignature.getBase().equals(FunctionType.NAME)) .map(typeSignature -> (FunctionType) (metadata.getTypeManager().getType(typeSignature))) .collect(toImmutableList()); List<Class> lambdaInterfaces = internalAggregationFunction.getLambdaInterfaces(); verify(lambdaExpressions.size() == functionTypes.size()); Optional<Integer> maskChannel = aggregation.getMask().map(value -> source.getLayout().get(value)); List<SortOrder> sortOrders = ImmutableList.of(); List<Symbol> sortKeys = ImmutableList.of(); if (aggregation.getCall().getOrderBy().isPresent()) { OrderBy orderBy = aggregation.getCall().getOrderBy().get(); sortOrders, pagesIndexFactory, aggregation.getCall().isDistinct(), joinCompiler, lambdaProviders,
public List<Symbol> getOriginalNonDistinctAggregateArgs() { return aggregations.values().stream() .filter(aggregation -> !aggregation.getMask().isPresent()) .map(Aggregation::getCall) .flatMap(function -> function.getArguments().stream()) .distinct() .map(Symbol::from) .collect(Collectors.toList()); }
FunctionCall call = aggregation.getCall(); if (call.isDistinct() && !call.getFilter().isPresent() && !aggregation.getMask().isPresent()) { Set<Symbol> inputs = call.getArguments().stream() .map(Symbol::from) .collect(toSet()); .addAll(parent.getGroupingKeys()) .addAll(inputs); parent.getGroupIdSymbol().ifPresent(distinctSymbols::add); subPlan, marker, ImmutableList.copyOf(distinctSymbols.build()), Optional.empty()); new FunctionCall( call.getName(), call.getWindow(), call.getFilter(), call.getOrderBy(), false, call.getArguments()), aggregation.getSignature(), Optional.of(marker)));
if (!partitionBy.isEmpty()) { List<Symbol> prePartitioned = node.getPartitionBy().stream() .filter(node.getPrePartitionedInputs()::contains) .collect(toImmutableList()); .filter(column -> !node.getPrePartitionedInputs().contains(column)) .collect(toImmutableList()); if (node.getOrderingScheme().isPresent()) { OrderingScheme orderingScheme = node.getOrderingScheme().get(); args.add(format("order by (%s)", Stream.concat( orderingScheme.getOrderBy().stream() String frameInfo = formatFrame(entry.getValue().getFrame()); print(indent + 2, "%s := %s(%s) %s", entry.getKey(), call.getName(), Joiner.on(", ").join(call.getArguments()), frameInfo);
@Override public PlanNode visitWindow(WindowNode node, RewriteContext<Context> context) { if (!node.getWindowFunctions().values().stream() .map(function -> function.getFunctionCall().getName()) .allMatch(metadata.getFunctionRegistry()::isAggregationFunction)) { return node; } // Don't need this restriction if we can prove that all order by symbols are deterministically produced if (node.getOrderingScheme().isPresent()) { return node; } // Only RANGE frame type currently supported for aggregation functions because it guarantees the // same value for each peer group. // ROWS frame type requires the ordering to be fully deterministic (e.g. deterministically sorted on all columns) if (node.getFrames().stream().map(WindowNode.Frame::getType).anyMatch(type -> type != WindowFrame.Type.RANGE)) { // TODO: extract frames of type RANGE and allow optimization on them return node; } // Lookup symbols can only be passed through if they are part of the partitioning Set<Symbol> partitionByLookupSymbols = context.get().getLookupSymbols().stream() .filter(node.getPartitionBy()::contains) .collect(toImmutableSet()); if (partitionByLookupSymbols.isEmpty()) { return node; } return context.defaultRewrite(node, new Context(partitionByLookupSymbols, context.get().getSuccess())); }
Symbol intermediateSymbol = context.getSymbolAllocator().newSymbol(signature.getName(), function.getIntermediateType()); checkState(!originalAggregation.getCall().getOrderBy().isPresent(), "Aggregate with ORDER BY does not support partial aggregation"); intermediateAggregation.put(intermediateSymbol, new AggregationNode.Aggregation(originalAggregation.getCall(), signature, originalAggregation.getMask())); new FunctionCall( QualifiedName.of(signature.getName()), ImmutableList.<Expression>builder() .add(intermediateSymbol.toSymbolReference()) .addAll(originalAggregation.getCall().getArguments().stream() .filter(LambdaExpression.class::isInstance) .collect(toImmutableList())) .build()), Optional.empty())); ImmutableList.of(), PARTIAL, node.getHashSymbol(),
.map(columnToSymbolMap::get) .collect(toImmutableList()); ImmutableMap.Builder<Symbol, AggregationNode.Aggregation> aggregations = ImmutableMap.builder(); FunctionRegistry functionRegistry = metadata.getFunctionRegistry(); for (TableStatisticType type : statisticsMetadata.getTableStatistics()) { new FunctionCall(count, ImmutableList.of()), functionRegistry.resolveFunction(count, ImmutableList.of()), Optional.empty()); Symbol symbol = symbolAllocator.newSymbol("rowCount", BIGINT); aggregations.put(symbol, aggregation);
.filter(projectionFilter) .collect(toImmutableList())), p.window( Optional.of(new OrderingScheme( ImmutableList.of(orderKey), ImmutableMap.of(orderKey, SortOrder.ASC_NULLS_FIRST)))), ImmutableMap.of( output1, new WindowNode.Function( new FunctionCall(QualifiedName.of("min"), ImmutableList.of(input1.toSymbolReference())), signature, new WindowNode.Frame( WindowFrame.Type.RANGE, UNBOUNDED_PRECEDING, Optional.of(startValue1), CURRENT_ROW, Optional.of(endValue1), output2, new WindowNode.Function( new FunctionCall(QualifiedName.of("min"), ImmutableList.of(input2.toSymbolReference())), signature, new WindowNode.Frame( p.values( inputs.stream() .filter(sourceFilter)
public FunctionCall getExpectedValue(SymbolAliases aliases) { List<Expression> symbolReferences = toSymbolReferences(args, aliases); if (isWindowFunction) { return new ExpectedWindowFunctionCall(symbolReferences); } Optional<OrderBy> orderByClause = Optional.empty(); if (!orderBy.isEmpty()) { orderByClause = Optional.of(new OrderBy(orderBy.stream() .map(item -> new SortItem( Symbol.from(aliases.get(item.getField())).toSymbolReference(), item.getOrdering(), item.getNullOrdering())) .collect(Collectors.toList()))); } return new FunctionCall(name, Optional.empty(), Optional.empty(), orderByClause, distinct, symbolReferences); }
@Override protected String visitFunctionCall(FunctionCall node, Void context) { StringBuilder builder = new StringBuilder(); String arguments = joinExpressions(node.getArguments()); if (node.getArguments().isEmpty() && "count".equalsIgnoreCase(node.getName().getSuffix())) { arguments = "*"; } if (node.isDistinct()) { arguments = "DISTINCT " + arguments; } builder.append(formatQualifiedName(node.getName())) .append('(').append(arguments); if (node.getOrderBy().isPresent()) { builder.append(' ').append(formatOrderBy(node.getOrderBy().get(), parameters)); } builder.append(')'); if (node.getFilter().isPresent()) { builder.append(" FILTER ").append(visitFilter(node.getFilter().get(), context)); } if (node.getWindow().isPresent()) { builder.append(" OVER ").append(visitWindow(node.getWindow().get(), context)); } return builder.toString(); }
ImmutableMap.Builder<Symbol, Aggregation> aggregations = ImmutableMap.builder(); ImmutableList.Builder<Expression> maskSymbols = ImmutableList.builder(); boolean aggregateWithoutFilterPresent = false; Optional<Symbol> mask = entry.getValue().getMask(); if (call.getFilter().isPresent()) { Expression filter = call.getFilter().get(); Symbol symbol = context.getSymbolAllocator().newSymbol(filter, BOOLEAN); verify(!mask.isPresent(), "Expected aggregation without mask symbols, see Rule pattern"); newAssignments.put(symbol, filter); mask = Optional.of(symbol); new FunctionCall(call.getName(), call.getWindow(), Optional.empty(), call.getOrderBy(), call.isDistinct(), call.getArguments()), entry.getValue().getSignature(), mask)); aggregations.build(), aggregation.getGroupingSets(), ImmutableList.of(), aggregation.getStep(), aggregation.getHashSymbol(),
private WindowNode.Function newWindowNodeFunction(String functionName, String... symbols) { return new WindowNode.Function( new FunctionCall( QualifiedName.of(functionName), Arrays.stream(symbols).map(SymbolReference::new).collect(Collectors.toList())), signature, frame); }
@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"); }); } }