Merge pull request #3610 from influxdb/jw-derivative
Fix panic when running derivative on non-numeric valuespull/3612/head
commit
2b33302d07
|
@ -27,6 +27,7 @@
|
|||
- [#3580](https://github.com/influxdb/influxdb/issues/3580): Do not allow wildcards with fields in select statements
|
||||
- [#3530](https://github.com/influxdb/influxdb/pull/3530): Aliasing a column no longer works
|
||||
- [#3436](https://github.com/influxdb/influxdb/issues/3436): Fix panic in hinted handoff queue processor
|
||||
- [#3401](https://github.com/influxdb/influxdb/issues/3401): Derivative on non-numeric fields panics db
|
||||
|
||||
## v0.9.2 [2015-07-24]
|
||||
|
||||
|
|
|
@ -757,14 +757,31 @@ type RawQueryDerivativeProcessor struct {
|
|||
DerivativeInterval time.Duration
|
||||
}
|
||||
|
||||
func (rqdp *RawQueryDerivativeProcessor) canProcess(input []*MapperValue) bool {
|
||||
// If we only have 1 value, then the value did not change, so return
|
||||
// a single row with 0.0
|
||||
if len(input) == 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// See if the field value is numeric, if it's not, we can't process the derivative
|
||||
validType := false
|
||||
switch input[0].Value.(type) {
|
||||
case int64:
|
||||
validType = true
|
||||
case float64:
|
||||
validType = true
|
||||
}
|
||||
|
||||
return validType
|
||||
}
|
||||
|
||||
func (rqdp *RawQueryDerivativeProcessor) Process(input []*MapperValue) []*MapperValue {
|
||||
if len(input) == 0 {
|
||||
return input
|
||||
}
|
||||
|
||||
// If we only have 1 value, then the value did not change, so return
|
||||
// a single row with 0.0
|
||||
if len(input) == 1 {
|
||||
if !rqdp.canProcess(input) {
|
||||
return []*MapperValue{
|
||||
&MapperValue{
|
||||
Time: input[0].Time,
|
||||
|
@ -858,6 +875,22 @@ func ProcessAggregateDerivative(results [][]interface{}, isNonNegative bool, int
|
|||
}
|
||||
}
|
||||
|
||||
// Check the value's type to ensure it's an numeric, if not, return a 0 result. We only check the first value
|
||||
// because derivatives cannot be combined with other aggregates currently.
|
||||
validType := false
|
||||
switch results[0][1].(type) {
|
||||
case int64:
|
||||
validType = true
|
||||
case float64:
|
||||
validType = true
|
||||
}
|
||||
|
||||
if !validType {
|
||||
return [][]interface{}{
|
||||
[]interface{}{results[0][0], 0.0},
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise calculate the derivatives as the difference between consecutive
|
||||
// points divided by the elapsed time. Then normalize to the requested
|
||||
// interval.
|
||||
|
|
|
@ -579,7 +579,7 @@ func TestProcessAggregateDerivative(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "float derivatives",
|
||||
name: "integer derivatives",
|
||||
fn: "derivative",
|
||||
interval: 24 * time.Hour,
|
||||
in: [][]interface{}{
|
||||
|
@ -608,6 +608,30 @@ func TestProcessAggregateDerivative(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string derivatives",
|
||||
fn: "derivative",
|
||||
interval: 24 * time.Hour,
|
||||
in: [][]interface{}{
|
||||
[]interface{}{
|
||||
time.Unix(0, 0), "1.0",
|
||||
},
|
||||
[]interface{}{
|
||||
time.Unix(0, 0).Add(24 * time.Hour), "2.0",
|
||||
},
|
||||
[]interface{}{
|
||||
time.Unix(0, 0).Add(48 * time.Hour), "3.0",
|
||||
},
|
||||
[]interface{}{
|
||||
time.Unix(0, 0).Add(72 * time.Hour), "4.0",
|
||||
},
|
||||
},
|
||||
exp: [][]interface{}{
|
||||
[]interface{}{
|
||||
time.Unix(0, 0), 0.0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
@ -697,6 +721,43 @@ func TestProcessRawQueryDerivative(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "integer derivative",
|
||||
fn: "derivative",
|
||||
interval: 24 * time.Hour,
|
||||
in: []*tsdb.MapperValue{
|
||||
{
|
||||
Time: time.Unix(0, 0).Unix(),
|
||||
Value: int64(0),
|
||||
},
|
||||
{
|
||||
Time: time.Unix(0, 0).Add(24 * time.Hour).UnixNano(),
|
||||
Value: int64(3),
|
||||
},
|
||||
{
|
||||
Time: time.Unix(0, 0).Add(48 * time.Hour).UnixNano(),
|
||||
Value: int64(5),
|
||||
},
|
||||
{
|
||||
Time: time.Unix(0, 0).Add(72 * time.Hour).UnixNano(),
|
||||
Value: int64(9),
|
||||
},
|
||||
},
|
||||
exp: []*tsdb.MapperValue{
|
||||
{
|
||||
Time: time.Unix(0, 0).Add(24 * time.Hour).UnixNano(),
|
||||
Value: 3.0,
|
||||
},
|
||||
{
|
||||
Time: time.Unix(0, 0).Add(48 * time.Hour).UnixNano(),
|
||||
Value: 2.0,
|
||||
},
|
||||
{
|
||||
Time: time.Unix(0, 0).Add(72 * time.Hour).UnixNano(),
|
||||
Value: 4.0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "12h interval",
|
||||
fn: "derivative",
|
||||
|
@ -806,6 +867,35 @@ func TestProcessRawQueryDerivative(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string derivatives",
|
||||
fn: "derivative",
|
||||
interval: 24 * time.Hour,
|
||||
in: []*tsdb.MapperValue{
|
||||
{
|
||||
Time: time.Unix(0, 0).Unix(),
|
||||
Value: "1.0",
|
||||
},
|
||||
{
|
||||
Time: time.Unix(0, 0).Add(24 * time.Hour).UnixNano(),
|
||||
Value: "2.0",
|
||||
},
|
||||
{
|
||||
Time: time.Unix(0, 0).Add(48 * time.Hour).UnixNano(),
|
||||
Value: "3.0",
|
||||
},
|
||||
{
|
||||
Time: time.Unix(0, 0).Add(72 * time.Hour).UnixNano(),
|
||||
Value: "4.0",
|
||||
},
|
||||
},
|
||||
exp: []*tsdb.MapperValue{
|
||||
{
|
||||
Time: time.Unix(0, 0).Unix(),
|
||||
Value: 0.0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
Loading…
Reference in New Issue