From 4d57175745d87a96be94cfac01ff2b6dc5d31801 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Sternberg" Date: Fri, 8 Apr 2016 15:00:47 -0400 Subject: [PATCH] Allow derivative() function to be used with ORDER BY desc The derivative function had an arbitrary limitation that would cause it to set the value to zero if the previous value was after the next value. This caused all `ORDER BY desc` queries with `derivative()` to always return zero values. Fixes #4675. --- CHANGELOG.md | 1 + influxql/functions.go | 12 ++--------- influxql/select_test.go | 48 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae28217e3b6..432192e336b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - [#6334](https://github.com/influxdata/influxdb/pull/6334): Allow environment variables to be set per input type. - [#6394](https://github.com/influxdata/influxdb/pull/6394): Allow time math with integer timestamps. - [#3247](https://github.com/influxdata/influxdb/issues/3247): Implement derivatives across intervals for aggregate queries. +- [#4675](https://github.com/influxdata/influxdb/issues/4675): Allow derivative() function to be used with ORDER BY desc. ### Bugfixes diff --git a/influxql/functions.go b/influxql/functions.go index ffd8402bc3e..40661f2f4e8 100644 --- a/influxql/functions.go +++ b/influxql/functions.go @@ -98,11 +98,7 @@ func (r *FloatDerivativeReducer) Emit() []FloatPoint { if !r.ascending { elapsed = -elapsed } - - value := 0.0 - if elapsed > 0 { - value = diff / (float64(elapsed) / float64(r.interval.Duration)) - } + value := diff / (float64(elapsed) / float64(r.interval.Duration)) // Drop negative values for non-negative derivatives. if r.isNonNegative && diff < 0 { @@ -149,11 +145,7 @@ func (r *IntegerDerivativeReducer) Emit() []FloatPoint { if !r.ascending { elapsed = -elapsed } - - value := 0.0 - if elapsed > 0 { - value = diff / (float64(elapsed) / float64(r.interval.Duration)) - } + value := diff / (float64(elapsed) / float64(r.interval.Duration)) // Drop negative values for non-negative derivatives. if r.isNonNegative && diff < 0 { diff --git a/influxql/select_test.go b/influxql/select_test.go index 3c752e8d4e7..1f4c14e6fe3 100644 --- a/influxql/select_test.go +++ b/influxql/select_test.go @@ -1895,6 +1895,54 @@ func TestSelect_Derivative_Integer(t *testing.T) { } } +func TestSelect_Derivative_Desc_Float(t *testing.T) { + var ic IteratorCreator + ic.CreateIteratorFn = func(opt influxql.IteratorOptions) (influxql.Iterator, error) { + return &FloatIterator{Points: []influxql.FloatPoint{ + {Name: "cpu", Time: 12 * Second, Value: 3}, + {Name: "cpu", Time: 8 * Second, Value: 19}, + {Name: "cpu", Time: 4 * Second, Value: 10}, + {Name: "cpu", Time: 0 * Second, Value: 20}, + }}, nil + } + + // Execute selection. + itrs, err := influxql.Select(MustParseSelectStatement(`SELECT derivative(value, 1s) FROM cpu WHERE time >= '1970-01-01T00:00:00Z' AND time < '1970-01-01T00:00:16Z' ORDER BY desc`), &ic, nil) + if err != nil { + t.Fatal(err) + } else if a := Iterators(itrs).ReadAll(); !deep.Equal(a, [][]influxql.Point{ + {&influxql.FloatPoint{Name: "cpu", Time: 8 * Second, Value: 4}}, + {&influxql.FloatPoint{Name: "cpu", Time: 4 * Second, Value: -2.25}}, + {&influxql.FloatPoint{Name: "cpu", Time: 0 * Second, Value: 2.5}}, + }) { + t.Fatalf("unexpected points: %s", spew.Sdump(a)) + } +} + +func TestSelect_Derivative_Desc_Integer(t *testing.T) { + var ic IteratorCreator + ic.CreateIteratorFn = func(opt influxql.IteratorOptions) (influxql.Iterator, error) { + return &IntegerIterator{Points: []influxql.IntegerPoint{ + {Name: "cpu", Time: 12 * Second, Value: 3}, + {Name: "cpu", Time: 8 * Second, Value: 19}, + {Name: "cpu", Time: 4 * Second, Value: 10}, + {Name: "cpu", Time: 0 * Second, Value: 20}, + }}, nil + } + + // Execute selection. + itrs, err := influxql.Select(MustParseSelectStatement(`SELECT derivative(value, 1s) FROM cpu WHERE time >= '1970-01-01T00:00:00Z' AND time < '1970-01-01T00:00:16Z' ORDER BY desc`), &ic, nil) + if err != nil { + t.Fatal(err) + } else if a := Iterators(itrs).ReadAll(); !deep.Equal(a, [][]influxql.Point{ + {&influxql.FloatPoint{Name: "cpu", Time: 8 * Second, Value: 4}}, + {&influxql.FloatPoint{Name: "cpu", Time: 4 * Second, Value: -2.25}}, + {&influxql.FloatPoint{Name: "cpu", Time: 0 * Second, Value: 2.5}}, + }) { + t.Fatalf("unexpected points: %s", spew.Sdump(a)) + } +} + func TestSelect_Difference_Float(t *testing.T) { var ic IteratorCreator ic.CreateIteratorFn = func(opt influxql.IteratorOptions) (influxql.Iterator, error) {