From a5c5da41efd33e474d63c94d80b019a49c7ffa89 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. --- influxql/functions.go | 12 ++--------- influxql/select_test.go | 48 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 10 deletions(-) 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 f8f21cc3ea4..b03a1d2d2a0 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) {