Add validation for derivative arguments
Derivative must be of the form derviative(field, duration) or derivative(agg(field), duration).pull/2569/head
parent
eb1d7a659f
commit
7fd9a0acd3
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue