Remove restrictions on where derivative can be used entirely

This removes the previous restrictions that kept derivative as only
capable of being used in a single field and only at the top level.
This lets users determine how they want to use derivative more freely
and opens up the possibility of also using math between derivatives.

This may open up some problems when it comes to math between derivatives
as timestamps may not match correctly. That is likely a problem related
to any binary math to begin with though and can probably be ignored by
the derivatives. I'm also not sure it makes sense to perform any math
between a derivative and a difference or perform math between a
derivative and a mean.

Fixes #6118.
pull/6375/head
Jonathan A. Sternberg 2016-04-13 19:27:23 -04:00
parent bfa225f149
commit 22a0505559
2 changed files with 31 additions and 45 deletions

View File

@ -1344,10 +1344,6 @@ func (s *SelectStatement) validate(tr targetRequirement) error {
return err
}
if err := s.validateDerivative(); err != nil {
return err
}
return nil
}
@ -1719,47 +1715,6 @@ func (s *SelectStatement) validateCountDistinct() error {
return nil
}
func (s *SelectStatement) validateDerivative() error {
if !s.HasDerivative() {
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 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) == 0 {
return fmt.Errorf("derivative requires a field 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")
}
// If a duration arg is passed, make sure it's a duration
if len(derivativeCall.Args) == 2 {
// 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
}
// GroupByInterval extracts the time interval, if specified.
func (s *SelectStatement) GroupByInterval() (time.Duration, error) {
// return if we've already pulled it out

View File

@ -197,6 +197,37 @@ func TestParser_ParseStatement(t *testing.T) {
},
},
{
s: `SELECT derivative(field1, 1h) / derivative(field2, 1h) FROM myseries`,
stmt: &influxql.SelectStatement{
IsRawQuery: false,
Fields: []*influxql.Field{
{
Expr: &influxql.BinaryExpr{
LHS: &influxql.Call{
Name: "derivative",
Args: []influxql.Expr{
&influxql.VarRef{Val: "field1"},
&influxql.DurationLiteral{Val: time.Hour},
},
},
RHS: &influxql.Call{
Name: "derivative",
Args: []influxql.Expr{
&influxql.VarRef{Val: "field2"},
&influxql.DurationLiteral{Val: time.Hour},
},
},
Op: influxql.DIV,
},
},
},
Sources: []influxql.Source{
&influxql.Measurement{Name: "myseries"},
},
},
},
// difference
{
s: `SELECT difference(field1) FROM myseries;`,