Skip to content

Commit

Permalink
builtins: add avg for interval
Browse files Browse the repository at this point in the history
This PR adds the ability to average intervals. Comes with a few extra
tests for aggregation functions over intervals.

Release note (sql change): Adds the ability to run `avg` over intervals.
  • Loading branch information
otan committed Nov 13, 2019
1 parent 0e9dd73 commit 5de5fc1
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 7 deletions.
2 changes: 2 additions & 0 deletions docs/generated/sql/aggregates.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
</span></td></tr>
<tr><td><a name="avg"></a><code>avg(arg1: <a href="int.html">int</a>) &rarr; <a href="decimal.html">decimal</a></code></td><td><span class="funcdesc"><p>Calculates the average of the selected values.</p>
</span></td></tr>
<tr><td><a name="avg"></a><code>avg(arg1: <a href="interval.html">interval</a>) &rarr; <a href="interval.html">interval</a></code></td><td><span class="funcdesc"><p>Calculates the average of the selected values.</p>
</span></td></tr>
<tr><td><a name="bit_and"></a><code>bit_and(arg1: <a href="int.html">int</a>) &rarr; <a href="int.html">int</a></code></td><td><span class="funcdesc"><p>Calculates the bitwise AND of all non-null input values, or null if none.</p>
</span></td></tr>
<tr><td><a name="bit_or"></a><code>bit_or(arg1: <a href="int.html">int</a>) &rarr; <a href="int.html">int</a></code></td><td><span class="funcdesc"><p>Calculates the bitwise OR of all non-null input values, or null if none.</p>
Expand Down
25 changes: 18 additions & 7 deletions pkg/sql/logictest/testdata/logic_test/aggregate
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ CREATE TABLE kv (
k INT PRIMARY KEY,
v INT,
w INT,
s STRING
s STRING,
i INTERVAL
)

# Aggregate functions return NULL if there are no rows.
Expand Down Expand Up @@ -36,6 +37,11 @@ SELECT jsonb_agg(1) FROM kv
----
NULL

query TTTT
SELECT min(i), avg(i), max(i), sum(i) FROM kv
----
NULL NULL NULL NULL

query IIIIRRRRBBT
SELECT min(v), max(v), count(v), sum_int(1), avg(v), sum(v), stddev(v), variance(v), bool_and(v = 1), bool_and(v = 1), xor_agg(s::bytes) FROM kv
----
Expand Down Expand Up @@ -147,12 +153,12 @@ SELECT (SELECT COALESCE(max(1), 0) FROM generate_series(1,0))

statement OK
INSERT INTO kv VALUES
(1, 2, 3, 'a'),
(3, 4, 5, 'a'),
(5, NULL, 5, NULL),
(6, 2, 3, 'b'),
(7, 2, 2, 'b'),
(8, 4, 2, 'A')
(1, 2, 3, 'a', '1min'::interval),
(3, 4, 5, 'a', '2sec'::interval),
(5, NULL, 5, NULL, NULL),
(6, 2, 3, 'b', '1ms'::interval),
(7, 2, 2, 'b', '4 days'::interval),
(8, 4, 2, 'A', '3 years'::interval)

# Aggregate functions triggers aggregation and computation for every row even when applied to a constant.
# NB: The XOR result is 00 because \x01 is XOR'd an even number of times.
Expand Down Expand Up @@ -595,6 +601,11 @@ SELECT avg(k), avg(v), sum(k), sum(v) FROM kv
----
5 2.8 30 14

query TTTT
SELECT min(i), avg(i), max(i), sum(i) FROM kv
----
00:00:00.001 7 mons 6 days 19:12:12.4002 3 years 3 years 4 days 00:01:02.001

query RRRR
SELECT avg(k::decimal), avg(v::decimal), sum(k::decimal), sum(v::decimal) FROM kv
----
Expand Down
9 changes: 9 additions & 0 deletions pkg/sql/sem/builtins/aggregate_builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ var aggregates = map[string]builtinDefinition{
"Calculates the average of the selected values."),
makeAggOverload([]*types.T{types.Decimal}, types.Decimal, newDecimalAvgAggregate,
"Calculates the average of the selected values."),
makeAggOverload([]*types.T{types.Interval}, types.Interval, newIntervalAvgAggregate,
"Calculates the average of the selected values."),
),

"bit_and": makeBuiltin(aggProps(),
Expand Down Expand Up @@ -571,6 +573,11 @@ func newDecimalAvgAggregate(
) tree.AggregateFunc {
return &avgAggregate{agg: newDecimalSumAggregate(params, evalCtx, arguments)}
}
func newIntervalAvgAggregate(
params []*types.T, evalCtx *tree.EvalContext, arguments tree.Datums,
) tree.AggregateFunc {
return &avgAggregate{agg: newIntervalSumAggregate(params, evalCtx, arguments)}
}

// Add accumulates the passed datum into the average.
func (a *avgAggregate) Add(ctx context.Context, datum tree.Datum, other ...tree.Datum) error {
Expand Down Expand Up @@ -600,6 +607,8 @@ func (a *avgAggregate) Result() (tree.Datum, error) {
count := apd.New(int64(a.count), 0)
_, err := tree.DecimalCtx.Quo(&t.Decimal, &t.Decimal, count)
return t, err
case *tree.DInterval:
return &tree.DInterval{Duration: t.Duration.Div(int64(a.count))}, nil
default:
return nil, errors.AssertionFailedf("unexpected SUM result type: %s", t)
}
Expand Down
13 changes: 13 additions & 0 deletions pkg/sql/sem/builtins/aggregate_builtins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ func TestAvgDecimalResultDeepCopy(t *testing.T) {
testAggregateResultDeepCopy(t, newDecimalAvgAggregate, makeDecimalTestDatum(10))
}

func TestAvgIntervalResultDeepCopy(t *testing.T) {
defer leaktest.AfterTest(t)()
testAggregateResultDeepCopy(t, newIntervalAvgAggregate, makeIntervalTestDatum(10))
}

func TestBitAndIntResultDeepCopy(t *testing.T) {
defer leaktest.AfterTest(t)()
t.Run("all null", func(t *testing.T) {
Expand Down Expand Up @@ -405,6 +410,14 @@ func BenchmarkAvgAggregateDecimal(b *testing.B) {
}
}

func BenchmarkAvgAggregateInterval(b *testing.B) {
for _, count := range []int{1000} {
b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) {
runBenchmarkAggregate(b, newIntervalAvgAggregate, makeIntervalTestDatum(count))
})
}
}

func BenchmarkCountAggregate(b *testing.B) {
for _, count := range []int{1000} {
b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) {
Expand Down

0 comments on commit 5de5fc1

Please sign in to comment.