Skip to content

Commit 3c25564

Browse files
authored
change "where" clause of agg functions to "filter" (#6465)
This commit changes the "where <expr>" clause on agg functions to use the SQL syntax "filter ( <expr> )". While we were here, we changed ast.Agg to ast.AggFuncExpr, removed the Where field from ast.CallExpr, and cleaned up the grammar for how agg functions are integrated into expressions and shortcuts. We also fixed a big where "count(*) where ..." did not previously parse, but "count(*) filter ( ... )" now works.
1 parent 46b2c4d commit 3c25564

38 files changed

+3939
-3929
lines changed

book/src/super-sql/aggregates/count.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ where grep("bar", this) | count()
6464
# expected output
6565
```
6666

67-
Count can return an explicit zero when using a `where` clause in the aggregation:
67+
Count can return an explicit zero when using a `filter` clause in the aggregation:
6868
```mdtest-spq
6969
# spq
70-
count() where grep("bar", this)
70+
count() filter (grep("bar", this))
7171
# input
7272
1
7373
"foo"

book/src/super-sql/operators/aggregate.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ where `<agg>` references an [aggregate function](../aggregates/intro.md)
1212
optionally structured as a [field assignment](intro.md#field-assignment)
1313
having the form:
1414
```
15-
[ <field> := ] <agg-func> ( [ all | distinct ] <expr> ) [ where <pred> ]
15+
[ <field> := ] <agg-func> ( [ all | distinct ] <expr> ) [ filter ( <pred> ) ]
1616
```
1717
and `<grouping>` is a grouping expression [field assignment](intro.md#field-assignment)
1818
having the form:
@@ -33,7 +33,7 @@ to the entire input optionally filtered by `<pred>`.
3333

3434
In the first form, the `aggregate` operator consumes all of its input,
3535
applies one or more aggregate functions `<agg>` to each input value
36-
optionally filtered by a `where` clause and/or organized with the grouping
36+
optionally filtered by a `filter` clause and/or organized with the grouping
3737
expressions specified after the `by` keyword, and at the end of input produces one
3838
or more aggregations for each unique set of grouping key values.
3939

@@ -44,10 +44,10 @@ keyword without applying any aggregate functions.
4444
The `aggregate` keyword is optional since it can be used as a
4545
[shortcut](intro.md#shortcuts).
4646

47-
Each aggregate function `<agg-func>` may be optionally followed by a `where` clause,
47+
Each aggregate function `<agg-func>` may be optionally followed by a `filter` clause,
4848
which applies a Boolean expression `<pred>` that indicates, for each input value,
4949
whether to include it in the values operated upon by the aggregate function.
50-
`where` clauses are analogous
50+
`filter` clauses are analogous
5151
to the [`where`](where.md) operator but apply their filter to the input
5252
argument stream to the aggregate function.
5353

@@ -152,10 +152,10 @@ set:=union(v) by key:=k | sort
152152

153153
---
154154

155-
_Use a `where` clause_
155+
_Use a `filter` clause_
156156
```mdtest-spq
157157
# spq
158-
set:=union(v) where v > 1 by key:=k | sort
158+
set:=union(v) filter (v > 1) by key:=k | sort
159159
# input
160160
{k:"foo",v:1}
161161
{k:"bar",v:2}
@@ -169,11 +169,11 @@ set:=union(v) where v > 1 by key:=k | sort
169169

170170
---
171171

172-
_Use a separate `where` clause on each aggregate function_
172+
_Use a separate `filter` clause on each aggregate function_
173173
```mdtest-spq
174174
# spq
175-
set:=union(v) where v > 1,
176-
array:=collect(v) where k=="foo"
175+
set:=union(v) filter (v > 1),
176+
array:=collect(v) filter (k=="foo")
177177
by key:=k
178178
| sort
179179
# input
@@ -189,11 +189,11 @@ array:=collect(v) where k=="foo"
189189

190190
---
191191

192-
_Results are included for `by` groupings that generate null results when `where`
192+
_Results are included for `by` groupings that generate null results when `filter`
193193
clauses are used inside `aggregate`_
194194
```mdtest-spq
195195
# spq
196-
sum(v) where k=="bar" by key:=k | sort
196+
sum(v) filter (k=="bar") by key:=k | sort
197197
# input
198198
{k:"foo",v:1}
199199
{k:"bar",v:2}

compiler/ast/expr.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ type Expr interface {
66
}
77

88
type (
9+
AggFuncExpr struct {
10+
Kind string `json:"kind" unpack:""`
11+
Name string `json:"name"`
12+
Distinct bool `json:"distinct"`
13+
Expr Expr `json:"expr"`
14+
Filter Expr `json:"filter"`
15+
Loc `json:"loc"`
16+
}
917
ArrayExpr struct {
1018
Kind string `json:"kind" unpack:""`
1119
Elems []ArrayElem `json:"elems"`
@@ -30,18 +38,18 @@ type (
3038
Loc `json:"loc"`
3139
}
3240
// A CallExpr represents different things dependending on its context.
33-
// As an operator (when wrapped in an OpExpr), it is either an aggregate
34-
// with no grouping keys and no duration, or a filter with a function
35-
// that is boolean valued. This is determined by the compiler rather than
36-
// the syntax tree based on the specific functions and aggregators that
41+
// As an operator (when wrapped in an ExprOp), it is either an aggregate
42+
// function (without grouping keys, filter, or distinct/all keywords),
43+
// or an implied where-operator that is boolean valued.
44+
// This is determined by the semantic analysis rather than
45+
// the syntax based on the specific functions and aggregators that
3746
// are defined at compile time. In expression context, a function call has
3847
// the standard semantics where it takes one or more arguments and returns a result.
3948
CallExpr struct {
40-
Kind string `json:"kind" unpack:""`
41-
Func Expr `json:"func"`
42-
Args []Expr `json:"args"`
43-
Where Expr `json:"where"`
44-
Loc `json:"loc"`
49+
Kind string `json:"kind" unpack:""`
50+
Func Expr `json:"func"`
51+
Args []Expr `json:"args"`
52+
Loc `json:"loc"`
4553
}
4654
CaseExpr struct {
4755
Kind string `json:"kind" unpack:""`
@@ -260,7 +268,7 @@ type (
260268
func (*FStringTextElem) fStringElemNode() {}
261269
func (*FStringExprElem) fStringElemNode() {}
262270

263-
func (*Agg) exprNode() {}
271+
func (*AggFuncExpr) exprNode() {}
264272
func (*ArrayExpr) exprNode() {}
265273
func (*BetweenExpr) exprNode() {}
266274
func (*BinaryExpr) exprNode() {}

compiler/ast/op.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -376,18 +376,3 @@ func (*ValuesOp) opNode() {}
376376
func (*WhereOp) opNode() {}
377377

378378
func (*DefaultScan) opNode() {}
379-
380-
// An Agg is an AST node that represents a aggregate function. The Name
381-
// field indicates the aggregation method while the Expr field indicates
382-
// an expression applied to the incoming records that is operated upon by them
383-
// aggregate function. If Expr isn't present, then the aggregator doesn't act
384-
// upon a function of the record, e.g., count() counts up records without
385-
// looking into them.
386-
type Agg struct {
387-
Kind string `json:"kind" unpack:""`
388-
Name string `json:"name"`
389-
Distinct bool `json:"distinct"`
390-
Expr Expr `json:"expr"`
391-
Where Expr `json:"where"`
392-
Loc `json:"loc"`
393-
}

compiler/ast/unpack.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
)
99

1010
var unpacker = unpack.New(
11-
Agg{},
11+
AggFuncExpr{},
1212
AggregateOp{},
1313
ArgExpr{},
1414
ArgText{},

compiler/dag/expr.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type (
3232
Name string `json:"name"`
3333
Distinct bool `json:"distinct"`
3434
Expr Expr `json:"expr"`
35-
Where Expr `json:"where"`
35+
Filter Expr `json:"filter"`
3636
}
3737
ArrayExpr struct {
3838
Kind string `json:"kind" unpack:""`

compiler/optimizer/demand.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func demandForExpr(expr dag.Expr) demand.Demand {
155155
case nil:
156156
return demand.None()
157157
case *dag.AggExpr:
158-
return demand.Union(demandForExpr(expr.Expr), demandForExpr(expr.Where))
158+
return demand.Union(demandForExpr(expr.Expr), demandForExpr(expr.Filter))
159159
case *dag.ArrayExpr:
160160
return demandForArrayOrSetExpr(expr.Elems)
161161
case *dag.BinaryExpr:

compiler/optimizer/vam.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func isCount(a dag.Assignment) bool {
2020
return false
2121
}
2222
agg, ok := a.RHS.(*dag.AggExpr)
23-
return ok && agg.Name == "count" && agg.Expr == nil && agg.Where == nil
23+
return ok && agg.Name == "count" && agg.Expr == nil && agg.Filter == nil
2424
}
2525

2626
func isSingleField(a dag.Assignment) (string, bool) {

0 commit comments

Comments
 (0)