Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support GROUP BY alias of the expression in the SELECT list. #5581

Closed
Closed
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 @@ -1723,24 +1723,53 @@ private List<Set<Expression>> computeGroupingSetsCrossProduct(List<List<Set<Expr
private List<Expression> analyzeGroupingColumns(Set<Expression> groupingColumns, QuerySpecification node, RelationType tupleDescriptor, AnalysisContext context, List<Expression> outputExpressions)
{
ImmutableList.Builder<Expression> groupingColumnsBuilder = ImmutableList.builder();

// Compute aliased output terms so we can resolve group by expressions against them first
ImmutableMultimap.Builder<QualifiedName, Expression> byAliasBuilder = ImmutableMultimap.builder();
for (SelectItem item : node.getSelect().getSelectItems()) {
if (item instanceof SingleColumn) {
Optional<String> alias = ((SingleColumn) item).getAlias();
if (alias.isPresent()) {
byAliasBuilder.put(QualifiedName.of(alias.get()), ((SingleColumn) item).getExpression()); // TODO: need to know if alias was quoted
}
}
}
Multimap<QualifiedName, Expression> byAlias = byAliasBuilder.build();

for (Expression groupingColumn : groupingColumns) {
// first, see if this is an ordinal
Expression groupByExpression;
Expression groupByExpression = null;
if (groupingColumn instanceof QualifiedNameReference && !((QualifiedNameReference) groupingColumn).getName().getPrefix().isPresent()) {
// if this is a simple name reference, try to resolve against output columns

QualifiedName name = ((QualifiedNameReference) groupingColumn).getName();
Collection<Expression> expressions = byAlias.get(name);
if (expressions.size() > 1) {
throw new SemanticException(AMBIGUOUS_ATTRIBUTE, groupingColumn, "'%s' in GROUP BY is ambiguous", name.getSuffix());
}
if (expressions.size() == 1) {
groupByExpression = Iterables.getOnlyElement(expressions);
}

if (groupingColumn instanceof LongLiteral) {
// otherwise, couldn't resolve name against output aliases, so fall through...
}
else if (groupingColumn instanceof LongLiteral) {
long ordinal = ((LongLiteral) groupingColumn).getValue();
if (ordinal < 1 || ordinal > outputExpressions.size()) {
throw new SemanticException(INVALID_ORDINAL, groupingColumn, "GROUP BY position %s is not in select list", ordinal);
}

groupByExpression = outputExpressions.get(Ints.checkedCast(ordinal - 1));
}
else {
ExpressionAnalysis expressionAnalysis = analyzeExpression(groupingColumn, tupleDescriptor, context);
analysis.recordSubqueries(node, expressionAnalysis);

// otherwise, just use the expression as is
if (groupByExpression == null) {
groupByExpression = groupingColumn;
}

ExpressionAnalysis expressionAnalysis = analyzeExpression(groupByExpression, tupleDescriptor, context);
analysis.recordSubqueries(node, expressionAnalysis);

Analyzer.verifyNoAggregatesOrWindowFunctions(metadata, groupByExpression, "GROUP BY");
Type type = analysis.getType(groupByExpression);
if (!type.isComparable()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,26 @@ public void testGroupByWithRowExpression()
analyze("SELECT (a, b) FROM t1 GROUP BY a, b");
}

@Test
public void testGroupByExpressionOnOutputColumn()
throws Exception
{
assertFails(MISSING_ATTRIBUTE, "SELECT a x FROM t1 GROUP BY x + 1");
}

@Test
public void testGroupByExpressionOnOutputColumn2()
throws Exception
{
// TODO: validate output
analyze("SELECT a x FROM t1 GROUP BY x");
analyze("SELECT a AS x FROM t1 GROUP BY x");
analyze("SELECT a AS x FROM (SELECT b AS a FROM t1 GROUP BY a) t2 GROUP BY x");
analyze("SELECT (a + 1) AS x FROM (SELECT b AS a FROM t1 GROUP BY a) t2 GROUP BY x");
analyze("SELECT (a + 1) AS x FROM (SELECT (b + 1) AS a FROM t1 GROUP BY a) t2 GROUP BY x");
analyze("SELECT (a + 1) AS x, c AS y, d FROM (SELECT (b + 1) AS a, c, d FROM t1 GROUP BY a, 2, 3) t2 GROUP BY x, y, 3");
}

@Test
public void testHaving()
throws Exception
Expand Down