Skip to content

Commit 5e4c15e

Browse files
authored
Add support of GROUPING SETS syntax for the group by clause (#150)
1 parent 5b640ce commit 5e4c15e

10 files changed

+405
-7
lines changed

parser/ast.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5048,6 +5048,7 @@ func (w *PrewhereClause) Accept(visitor ASTVisitor) error {
50485048

50495049
type GroupByClause struct {
50505050
GroupByPos Pos
5051+
GroupByEnd Pos
50515052
AggregateType string
50525053
Expr Expr
50535054
WithCube bool
@@ -5060,7 +5061,7 @@ func (g *GroupByClause) Pos() Pos {
50605061
}
50615062

50625063
func (g *GroupByClause) End() Pos {
5063-
return g.Expr.End()
5064+
return g.GroupByEnd
50645065
}
50655066

50665067
func (g *GroupByClause) String() string {
@@ -5069,7 +5070,9 @@ func (g *GroupByClause) String() string {
50695070
if g.AggregateType != "" {
50705071
builder.WriteString(g.AggregateType)
50715072
}
5072-
builder.WriteString(g.Expr.String())
5073+
if g.Expr != nil {
5074+
builder.WriteString(g.Expr.String())
5075+
}
50735076
if g.WithCube {
50745077
builder.WriteString(" WITH CUBE")
50755078
}
@@ -5085,8 +5088,10 @@ func (g *GroupByClause) String() string {
50855088
func (g *GroupByClause) Accept(visitor ASTVisitor) error {
50865089
visitor.enter(g)
50875090
defer visitor.leave(g)
5088-
if err := g.Expr.Accept(visitor); err != nil {
5089-
return err
5091+
if g.Expr != nil {
5092+
if err := g.Expr.Accept(visitor); err != nil {
5093+
return err
5094+
}
50905095
}
50915096
return visitor.VisitGroupByExpr(g)
50925097
}

parser/keyword.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ const (
8989
KeywordGrant = "GRANT"
9090
KeywordGranularity = "GRANULARITY"
9191
KeywordGroup = "GROUP"
92+
KeywordGrouping = "GROUPING"
9293
KeywordHaving = "HAVING"
9394
KeywordHierarchical = "HIERARCHICAL"
9495
KeywordHour = "HOUR"
@@ -181,6 +182,7 @@ const (
181182
KeywordSemi = "SEMI"
182183
KeywordSends = "SENDS"
183184
KeywordSet = "SET"
185+
KeywordSets = "SETS"
184186
KeywordSettings = "SETTINGS"
185187
KeywordShow = "SHOW"
186188
KeywordShutdown = "SHUTDOWN"
@@ -317,6 +319,7 @@ var keywords = NewSet(
317319
KeywordGrant,
318320
KeywordGranularity,
319321
KeywordGroup,
322+
KeywordGrouping,
320323
KeywordHaving,
321324
KeywordHierarchical,
322325
KeywordHour,
@@ -409,6 +412,7 @@ var keywords = NewSet(
409412
KeywordSemi,
410413
KeywordSends,
411414
KeywordSet,
415+
KeywordSets,
412416
KeywordSettings,
413417
KeywordShow,
414418
KeywordShutdown,

parser/parser_query.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -419,17 +419,22 @@ func (p *Parser) parseGroupByClause(pos Pos) (*GroupByClause, error) {
419419
var expr Expr
420420
var err error
421421
aggregateType := ""
422-
if p.matchKeyword(KeywordCube) || p.matchKeyword(KeywordRollup) {
422+
switch {
423+
case p.matchKeyword(KeywordCube) || p.matchKeyword(KeywordRollup):
423424
aggregateType = p.last().String
424425
_ = p.lexer.consumeToken()
425426
expr, err = p.parseFunctionParams(p.Pos())
426-
} else {
427+
case p.tryConsumeKeywords(KeywordGrouping, KeywordSets):
428+
aggregateType = "GROUPING SETS"
429+
expr, err = p.parseFunctionParams(p.Pos())
430+
case p.tryConsumeKeywords(KeywordAll):
431+
aggregateType = "ALL"
432+
default:
427433
expr, err = p.parseColumnExprListWithLParen(p.Pos())
428434
}
429435
if err != nil {
430436
return nil, err
431437
}
432-
433438
groupBy := &GroupByClause{
434439
GroupByPos: pos,
435440
AggregateType: aggregateType,
@@ -449,6 +454,7 @@ func (p *Parser) parseGroupByClause(pos Pos) (*GroupByClause, error) {
449454
return nil, fmt.Errorf("expected CUBE, ROLLUP or TOTALS, got %s", p.lastTokenKind())
450455
}
451456
}
457+
groupBy.GroupByEnd = p.Pos()
452458

453459
return groupBy, nil
454460
}

parser/testdata/ddl/output/alter_table_add_projection.sql.golden.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
},
5151
"GroupBy": {
5252
"GroupByPos": 86,
53+
"GroupByEnd": 105,
5354
"AggregateType": "",
5455
"Expr": {
5556
"ListPos": 95,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
-- Origin SQL:
2+
SELECT
3+
datacenter,
4+
distro,
5+
SUM (quantity) AS qty
6+
FROM
7+
servers
8+
GROUP BY
9+
GROUPING SETS(
10+
(datacenter,distro),
11+
(datacenter),
12+
(distro),
13+
()
14+
);
15+
16+
SELECT
17+
datacenter,
18+
distro,
19+
SUM (quantity) AS qty
20+
FROM
21+
servers
22+
GROUP BY ALL;
23+
24+
-- Format SQL:
25+
SELECT datacenter, distro, SUM(quantity) AS qty FROM servers GROUP BY GROUPING SETS((datacenter, distro), (datacenter), (distro), ());
26+
SELECT datacenter, distro, SUM(quantity) AS qty FROM servers GROUP BY ALL;

parser/testdata/query/output/select_simple.sql.golden.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@
357357
},
358358
"GroupBy": {
359359
"GroupByPos": 239,
360+
"GroupByEnd": 258,
360361
"AggregateType": "",
361362
"Expr": {
362363
"ListPos": 248,

parser/testdata/query/output/select_simple_with_group_by_with_cube_totals.sql.golden.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"Where": null,
7979
"GroupBy": {
8080
"GroupByPos": 37,
81+
"GroupByEnd": 76,
8182
"AggregateType": "CUBE",
8283
"Expr": {
8384
"LeftParenPos": 50,

0 commit comments

Comments
 (0)