Add validation for derivative arguments

Derivative must be of the form derviative(field, duration) or
derivative(agg(field), duration).
pull/2569/head
Jason Wilder 2015-05-12 14:34:12 -06:00
parent eb1d7a659f
commit 7fd9a0acd3
3 changed files with 45 additions and 12 deletions

View File

@ -885,12 +885,48 @@ func (s *SelectStatement) Validate(tr targetRequirement) error {
}
}
if err := s.validateDerivative(); err != nil {
return err
}
return nil
}
func (s *SelectStatement) validateDerivative() error {
if !s.IsNonNestedDerivative() {
return nil
}
// If a derivative is requested, it must be the only field in the query. We don't support
// multiple fields in combination w/ derivaties yet.
if s.IsNonNestedDerivative() && len(s.Fields) != 1 {
if len(s.Fields) != 1 {
return fmt.Errorf("derivative cannot be used with other fields")
}
aggr := s.FunctionCalls()
if len(aggr) != 1 {
return fmt.Errorf("derivative cannot be used with other fields")
}
// Derivative requires two arguments
derivativeCall := aggr[0]
if len(derivativeCall.Args) != 2 {
return fmt.Errorf("derivative requires a field and duration argument")
}
// First arg must be a field or aggr over a field e.g. (mean(field))
_, callOk := derivativeCall.Args[0].(*Call)
_, varOk := derivativeCall.Args[0].(*VarRef)
if !(callOk || varOk) {
return fmt.Errorf("derivative requires a field argument")
}
// Second must be a duration .e.g (1h)
if _, ok := derivativeCall.Args[1].(*DurationLiteral); !ok {
return fmt.Errorf("derivative requires a duration argument")
}
return nil
}

View File

@ -39,9 +39,9 @@ func InitializeMapFunc(c *Call) (MapFunc, error) {
}
// Ensure that there is either a single argument or if for percentile, two
if c.Name == "percentile" {
if c.Name == "percentile" || c.Name == "derivative" {
if len(c.Args) != 2 {
return nil, fmt.Errorf("expected two arguments for percentile()")
return nil, fmt.Errorf("expected two arguments for %s()", c.Name)
}
} else if len(c.Args) != 1 {
return nil, fmt.Errorf("expected one argument for %s()", c.Name)
@ -86,10 +86,6 @@ func InitializeMapFunc(c *Call) (MapFunc, error) {
}
return MapEcho, nil
case "derivative":
if len(c.Args) == 0 {
return nil, fmt.Errorf("expected argument in derivative()")
}
// If the arg is another aggregate e.g. derivative(mean(value)), then
// use the map func for that nested aggregate
if fn, ok := c.Args[0].(*Call); ok {
@ -136,10 +132,6 @@ func InitializeReduceFunc(c *Call) (ReduceFunc, error) {
}
return ReducePercentile(lit.Val), nil
case "derivative":
if len(c.Args) == 0 {
return nil, fmt.Errorf("expected argument in derivative()")
}
// If the arg is another aggregate e.g. derivative(mean(value)), then
// use the map func for that nested aggregate
if fn, ok := c.Args[0].(*Call); ok {

View File

@ -1,6 +1,9 @@
package influxql
import "testing"
import (
"testing"
"time"
)
import "sort"
@ -117,6 +120,7 @@ func TestInitializeMapFuncDerivative(t *testing.T) {
Name: "derivative",
Args: []Expr{
&VarRef{Val: " field1"},
&DurationLiteral{Val: time.Hour},
},
}
@ -130,6 +134,7 @@ func TestInitializeMapFuncDerivative(t *testing.T) {
Name: "derivative",
Args: []Expr{
&Call{Name: "mean", Args: []Expr{&VarRef{Val: "field1"}}},
&DurationLiteral{Val: time.Hour},
},
}