Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2595,6 +2595,12 @@ private void analyzeSelectSingleColumn(
private Analysis.GroupingSetAnalysis analyzeGroupBy(
QuerySpecification node, Scope scope, List<Expression> outputExpressions) {
if (node.getGroupBy().isPresent()) {

// Handle GROUP BY ALL: infer grouping columns from SELECT expressions
if (node.getGroupBy().get().isAll()) {
return analyzeGroupByAll(node, scope, outputExpressions);
}

ImmutableList.Builder<List<Set<FieldId>>> cubes = ImmutableList.builder();
ImmutableList.Builder<List<Set<FieldId>>> rollups = ImmutableList.builder();
ImmutableList.Builder<List<Set<FieldId>>> sets = ImmutableList.builder();
Expand Down Expand Up @@ -2718,6 +2724,69 @@ private Analysis.GroupingSetAnalysis analyzeGroupBy(
return result;
}

private Analysis.GroupingSetAnalysis analyzeGroupByAll(
QuerySpecification node, Scope scope, List<Expression> outputExpressions) {
ImmutableList.Builder<List<Set<FieldId>>> sets = ImmutableList.builder();
ImmutableList.Builder<Expression> complexExpressions = ImmutableList.builder();
ImmutableList.Builder<Expression> groupingExpressions = ImmutableList.builder();
FunctionCall gapFillColumn = null;
ImmutableList.Builder<Expression> gapFillGroupingExpressions = ImmutableList.builder();

for (Expression outputExpression : outputExpressions) {
List<FunctionCall> aggregates =
extractAggregateFunctions(ImmutableList.of(outputExpression));
List<FunctionCall> windowFunctions =
extractWindowFunctions(ImmutableList.of(outputExpression));
if (!aggregates.isEmpty() || !windowFunctions.isEmpty()) {
continue;
}

analyzeExpression(outputExpression, scope);
ResolvedField field =
analysis.getColumnReferenceFields().get(NodeRef.of(outputExpression));
if (field != null) {
sets.add(ImmutableList.of(ImmutableSet.of(field.getFieldId())));
} else {
complexExpressions.add(outputExpression);
}

if (isDateBinGapFill(outputExpression)) {
if (gapFillColumn != null) {
throw new SemanticException("multiple date_bin_gapfill calls not allowed");
}
gapFillColumn = (FunctionCall) outputExpression;
} else {
gapFillGroupingExpressions.add(outputExpression);
}

groupingExpressions.add(outputExpression);
}

List<Expression> expressions = groupingExpressions.build();
for (Expression expression : expressions) {
Type type = analysis.getType(expression);
if (!type.isComparable()) {
throw new SemanticException(
String.format(
"%s is not comparable, and therefore cannot be used in GROUP BY", type));
}
}

Analysis.GroupingSetAnalysis groupingSets =
new Analysis.GroupingSetAnalysis(
expressions,
ImmutableList.of(),
ImmutableList.of(),
sets.build(),
complexExpressions.build());
analysis.setGroupingSets(node, groupingSets);
if (gapFillColumn != null) {
analysis.setGapFill(node, gapFillColumn);
analysis.setGapFillGroupingKeys(node, gapFillGroupingExpressions.build());
}
return groupingSets;
}

private boolean isDateBinGapFill(Expression column) {
return column instanceof FunctionCall
&& DATE_BIN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,39 @@ public class GroupBy extends Node {
private static final long INSTANCE_SIZE = RamUsageEstimator.shallowSizeOfInstance(GroupBy.class);

private final boolean isDistinct;
private final boolean isAll;
private final List<GroupingElement> groupingElements;

public GroupBy(boolean isDistinct, List<GroupingElement> groupingElements) {
super(null);
this.isDistinct = isDistinct;
this.isAll = false;
this.groupingElements = ImmutableList.copyOf(requireNonNull(groupingElements));
}

public GroupBy(
NodeLocation location, boolean isDistinct, List<GroupingElement> groupingElements) {
super(requireNonNull(location, "location is null"));
this.isDistinct = isDistinct;
this.isAll = false;
this.groupingElements = ImmutableList.copyOf(requireNonNull(groupingElements));
}

public GroupBy(NodeLocation location, boolean isAll) {
super(requireNonNull(location, "location is null"));
this.isDistinct = false;
this.isAll = isAll;
this.groupingElements = ImmutableList.of();
}

public boolean isDistinct() {
return isDistinct;
}

public boolean isAll() {
return isAll;
}

public List<GroupingElement> getGroupingElements() {
return groupingElements;
}
Expand All @@ -76,18 +90,20 @@ public boolean equals(Object o) {
}
GroupBy groupBy = (GroupBy) o;
return isDistinct == groupBy.isDistinct
&& isAll == groupBy.isAll
&& Objects.equals(groupingElements, groupBy.groupingElements);
}

@Override
public int hashCode() {
return Objects.hash(isDistinct, groupingElements);
return Objects.hash(isDistinct, isAll, groupingElements);
}

@Override
public String toString() {
return toStringHelper(this)
.add("isDistinct", isDistinct)
.add("isAll", isAll)
.add("groupingElements", groupingElements)
.toString();
}
Expand All @@ -98,7 +114,7 @@ public boolean shallowEquals(Node other) {
return false;
}

return isDistinct == ((GroupBy) other).isDistinct;
return isDistinct == ((GroupBy) other).isDistinct && isAll == ((GroupBy) other).isAll;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2419,6 +2419,9 @@ public Node visitSelectAll(RelationalSqlParser.SelectAllContext ctx) {

@Override
public Node visitGroupBy(RelationalSqlParser.GroupByContext ctx) {
if (ctx.ALL() != null && ctx.groupingElement().isEmpty()) {
return new GroupBy(getLocation(ctx), true);
}
return new GroupBy(
getLocation(ctx),
isDistinct(ctx.setQuantifier()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,13 +248,18 @@ protected Void visitQuerySpecification(QuerySpecification node, Integer indent)

node.getGroupBy()
.ifPresent(
groupBy ->
groupBy -> {
if (groupBy.isAll()) {
append(indent, "GROUP BY ALL").append('\n');
} else {
append(
indent,
"GROUP BY "
+ (groupBy.isDistinct() ? " DISTINCT " : "")
+ formatGroupBy(groupBy.getGroupingElements()))
.append('\n'));
.append('\n');
}
});

node.getHaving()
.ifPresent(having -> append(indent, "HAVING " + formatExpression(having)).append('\n'));
Expand Down
Loading