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
|
// 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.
|
// 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")
|
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
|
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
|
// 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 {
|
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 {
|
} else if len(c.Args) != 1 {
|
||||||
return nil, fmt.Errorf("expected one argument for %s()", c.Name)
|
return nil, fmt.Errorf("expected one argument for %s()", c.Name)
|
||||||
|
@ -86,10 +86,6 @@ func InitializeMapFunc(c *Call) (MapFunc, error) {
|
||||||
}
|
}
|
||||||
return MapEcho, nil
|
return MapEcho, nil
|
||||||
case "derivative":
|
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
|
// If the arg is another aggregate e.g. derivative(mean(value)), then
|
||||||
// use the map func for that nested aggregate
|
// use the map func for that nested aggregate
|
||||||
if fn, ok := c.Args[0].(*Call); ok {
|
if fn, ok := c.Args[0].(*Call); ok {
|
||||||
|
@ -136,10 +132,6 @@ func InitializeReduceFunc(c *Call) (ReduceFunc, error) {
|
||||||
}
|
}
|
||||||
return ReducePercentile(lit.Val), nil
|
return ReducePercentile(lit.Val), nil
|
||||||
case "derivative":
|
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
|
// If the arg is another aggregate e.g. derivative(mean(value)), then
|
||||||
// use the map func for that nested aggregate
|
// use the map func for that nested aggregate
|
||||||
if fn, ok := c.Args[0].(*Call); ok {
|
if fn, ok := c.Args[0].(*Call); ok {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package influxql
|
package influxql
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
import "sort"
|
import "sort"
|
||||||
|
|
||||||
|
@ -117,6 +120,7 @@ func TestInitializeMapFuncDerivative(t *testing.T) {
|
||||||
Name: "derivative",
|
Name: "derivative",
|
||||||
Args: []Expr{
|
Args: []Expr{
|
||||||
&VarRef{Val: " field1"},
|
&VarRef{Val: " field1"},
|
||||||
|
&DurationLiteral{Val: time.Hour},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +134,7 @@ func TestInitializeMapFuncDerivative(t *testing.T) {
|
||||||
Name: "derivative",
|
Name: "derivative",
|
||||||
Args: []Expr{
|
Args: []Expr{
|
||||||
&Call{Name: "mean", Args: []Expr{&VarRef{Val: "field1"}}},
|
&Call{Name: "mean", Args: []Expr{&VarRef{Val: "field1"}}},
|
||||||
|
&DurationLiteral{Val: time.Hour},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue