spanner/spansql: parse GROUP BY clauses
These aren't implemented by spannertest yet.
Change-Id: Iab675f35c91bd7a8842233e8cb4ab46d0cb4d819
Reviewed-on: https://code-review.googlesource.com/c/gocloud/+/52733
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Shanika Kuruppu <skuruppu@google.com>
diff --git a/spanner/spansql/keywords.go b/spanner/spansql/keywords.go
index e9b6e5a..c243b7a 100644
--- a/spanner/spansql/keywords.go
+++ b/spanner/spansql/keywords.go
@@ -131,6 +131,7 @@
// Aggregate functions.
"BIT_XOR": true,
"COUNT": true,
+ "SUM": true,
// Mathematical functions.
"ABS": true,
diff --git a/spanner/spansql/parser.go b/spanner/spansql/parser.go
index 838ef3e..e59b360 100644
--- a/spanner/spansql/parser.go
+++ b/spanner/spansql/parser.go
@@ -1484,18 +1484,11 @@
}
// Read expressions for the SELECT list.
- for {
- expr, err := p.parseExpr()
- if err != nil {
- return Select{}, err
- }
- sel.List = append(sel.List, expr)
-
- if p.eat(",") {
- continue
- }
- break
+ list, err := p.parseExprList()
+ if err != nil {
+ return Select{}, err
}
+ sel.List = list
if p.eat("FROM") {
for {
@@ -1527,7 +1520,15 @@
sel.Where = where
}
- // TODO: GROUP BY, HAVING
+ if p.eat("GROUP", "BY") {
+ list, err := p.parseExprList()
+ if err != nil {
+ return Select{}, err
+ }
+ sel.GroupBy = list
+ }
+
+ // TODO: HAVING
return sel, nil
}
@@ -1631,6 +1632,23 @@
func (p *parser) parseExprList() ([]Expr, *parseError) {
var list []Expr
+ for {
+ expr, err := p.parseExpr()
+ if err != nil {
+ return nil, err
+ }
+ list = append(list, expr)
+
+ if p.eat(",") {
+ continue
+ }
+ break
+ }
+ return list, nil
+}
+
+func (p *parser) parseParenExprList() ([]Expr, *parseError) {
+ var list []Expr
err := p.parseCommaList(func(p *parser) *parseError {
e, err := p.parseExpr()
if err != nil {
@@ -1943,7 +1961,7 @@
// this is a function invocation.
// TODO: Case-insensitivity.
if name := tok.value; funcs[name] && p.sniff("(") {
- list, err := p.parseExprList()
+ list, err := p.parseParenExprList()
if err != nil {
return nil, err
}
diff --git a/spanner/spansql/parser_test.go b/spanner/spansql/parser_test.go
index 4d0177a..8c31515 100644
--- a/spanner/spansql/parser_test.go
+++ b/spanner/spansql/parser_test.go
@@ -78,6 +78,19 @@
},
},
},
+ {`SELECT SUM(PointsScored), FirstName, LastName FROM PlayerStats GROUP BY FirstName, LastName`,
+ Query{
+ Select: Select{
+ List: []Expr{
+ Func{Name: "SUM", Args: []Expr{ID("PointsScored")}},
+ ID("FirstName"),
+ ID("LastName"),
+ },
+ From: []SelectFrom{{Table: "PlayerStats"}},
+ GroupBy: []Expr{ID("FirstName"), ID("LastName")},
+ },
+ },
+ },
}
for _, test := range tests {
got, err := ParseQuery(test.in)
diff --git a/spanner/spansql/sql.go b/spanner/spansql/sql.go
index 8f536a7..9f6f4a4 100644
--- a/spanner/spansql/sql.go
+++ b/spanner/spansql/sql.go
@@ -212,6 +212,15 @@
if sel.Where != nil {
str += " WHERE " + sel.Where.SQL()
}
+ if len(sel.GroupBy) > 0 {
+ str += " GROUP BY "
+ for i, gb := range sel.GroupBy {
+ if i > 0 {
+ str += ", "
+ }
+ str += gb.SQL()
+ }
+ }
return str
}
diff --git a/spanner/spansql/types.go b/spanner/spansql/types.go
index c634bdc..79fe888 100644
--- a/spanner/spansql/types.go
+++ b/spanner/spansql/types.go
@@ -224,7 +224,8 @@
List []Expr
From []SelectFrom
Where BoolExpr
- // TODO: GroupBy, Having
+ GroupBy []Expr
+ // TODO: Having
}
type SelectFrom struct {