public Boolean visitGroupingOperation(GroupingOperation node, Void context) { // ensure that no output fields are referenced from ORDER BY clause if (orderByScope.isPresent()) { node.getGroupingColumns().forEach(groupingColumn -> verifyNoOrderByReferencesToOutputColumns( groupingColumn, REFERENCE_TO_OUTPUT_ATTRIBUTE_WITHIN_ORDER_BY_GROUPING, "Invalid reference to output of SELECT clause from grouping() expression in ORDER BY")); } Optional<Expression> argumentNotInGroupBy = node.getGroupingColumns().stream() .filter(argument -> !columnReferences.containsKey(NodeRef.of(argument)) || !isGroupingKey(argument)) .findAny(); if (argumentNotInGroupBy.isPresent()) { throw new SemanticException( INVALID_PROCEDURE_ARGUMENTS, node, "The arguments to GROUPING() must be expressions referenced by the GROUP BY at the associated query level. Mismatch due to %s.", argumentNotInGroupBy.get()); } return true; }
@Override protected Boolean visitSubqueryExpression(SubqueryExpression node, Void context) { /* * Column reference can resolve to (a) some subquery's scope, (b) a projection (ORDER BY scope), * (c) source scope or (d) outer query scope (effectively a constant). * From AggregationAnalyzer's perspective, only case (c) needs verification. */ getReferencesToScope(node, analysis, sourceScope) .filter(expression -> !isGroupingKey(expression)) .findFirst() .ifPresent(expression -> { throw new SemanticException(MUST_BE_AGGREGATE_OR_GROUP_BY, expression, "Subquery uses '%s' which must appear in GROUP BY clause", expression); }); return true; }
@Override protected Boolean visitIdentifier(Identifier node, Void context) { if (analysis.getLambdaArgumentReferences().containsKey(NodeRef.of(node))) { return true; } return isGroupingKey(node); }
@Override protected Boolean visitDereferenceExpression(DereferenceExpression node, Void context) { if (columnReferences.containsKey(NodeRef.<Expression>of(node))) { return isGroupingKey(node); } // Allow SELECT col1.f1 FROM table1 GROUP BY col1 return process(node.getBase(), context); }