Merge pull request #5025 from influxdb/nc-issue#4761
Fix parsing of functions ending in 'derivative'pull/5125/head
commit
314f48114d
|
@ -772,7 +772,7 @@ func (s *SelectStatement) SourceNames() []string {
|
||||||
// derivative aggregate
|
// derivative aggregate
|
||||||
func (s *SelectStatement) HasDerivative() bool {
|
func (s *SelectStatement) HasDerivative() bool {
|
||||||
for _, f := range s.FunctionCalls() {
|
for _, f := range s.FunctionCalls() {
|
||||||
if strings.HasSuffix(f.Name, "derivative") {
|
if f.Name == "derivative" || f.Name == "non_negative_derivative" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -783,7 +783,7 @@ func (s *SelectStatement) HasDerivative() bool {
|
||||||
// variable ref as the first arg
|
// variable ref as the first arg
|
||||||
func (s *SelectStatement) IsSimpleDerivative() bool {
|
func (s *SelectStatement) IsSimpleDerivative() bool {
|
||||||
for _, f := range s.FunctionCalls() {
|
for _, f := range s.FunctionCalls() {
|
||||||
if strings.HasSuffix(f.Name, "derivative") {
|
if f.Name == "derivative" || f.Name == "non_negative_derivative" {
|
||||||
// it's nested if the first argument is an aggregate function
|
// it's nested if the first argument is an aggregate function
|
||||||
if _, ok := f.Args[0].(*VarRef); ok {
|
if _, ok := f.Args[0].(*VarRef); ok {
|
||||||
return true
|
return true
|
||||||
|
@ -799,7 +799,7 @@ func (s *SelectStatement) HasSimpleCount() bool {
|
||||||
// recursively check for a simple count(varref) function
|
// recursively check for a simple count(varref) function
|
||||||
var hasCount func(f *Call) bool
|
var hasCount func(f *Call) bool
|
||||||
hasCount = func(f *Call) bool {
|
hasCount = func(f *Call) bool {
|
||||||
if strings.HasSuffix(f.Name, "count") {
|
if f.Name == "count" {
|
||||||
// it's nested if the first argument is an aggregate function
|
// it's nested if the first argument is an aggregate function
|
||||||
if _, ok := f.Args[0].(*VarRef); ok {
|
if _, ok := f.Args[0].(*VarRef); ok {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -465,6 +465,237 @@ func TestSelectStatement_IsRawQuerySet(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSelectStatement_HasDerivative(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
stmt string
|
||||||
|
derivative bool
|
||||||
|
}{
|
||||||
|
// No derivatives
|
||||||
|
{
|
||||||
|
stmt: `SELECT value FROM cpu`,
|
||||||
|
derivative: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Query derivative
|
||||||
|
{
|
||||||
|
stmt: `SELECT derivative(value) FROM cpu`,
|
||||||
|
derivative: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// No GROUP BY time only
|
||||||
|
{
|
||||||
|
stmt: `SELECT mean(value) FROM cpu where time < now() GROUP BY time(5ms)`,
|
||||||
|
derivative: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// No GROUP BY derivatives, time only
|
||||||
|
{
|
||||||
|
stmt: `SELECT derivative(mean(value)) FROM cpu where time < now() GROUP BY time(5ms)`,
|
||||||
|
derivative: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
stmt: `SELECT value FROM cpu`,
|
||||||
|
derivative: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Query derivative
|
||||||
|
{
|
||||||
|
stmt: `SELECT non_negative_derivative(value) FROM cpu`,
|
||||||
|
derivative: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// No GROUP BY derivatives, time only
|
||||||
|
{
|
||||||
|
stmt: `SELECT non_negative_derivative(mean(value)) FROM cpu where time < now() GROUP BY time(5ms)`,
|
||||||
|
derivative: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Invalid derivative function name
|
||||||
|
{
|
||||||
|
stmt: `SELECT typoDerivative(value) FROM cpu where time < now()`,
|
||||||
|
derivative: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
// Parse statement.
|
||||||
|
t.Logf("index: %d, statement: %s", i, tt.stmt)
|
||||||
|
stmt, err := influxql.NewParser(strings.NewReader(tt.stmt)).ParseStatement()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invalid statement: %q: %s", tt.stmt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test derivative detection.
|
||||||
|
if d := stmt.(*influxql.SelectStatement).HasDerivative(); tt.derivative != d {
|
||||||
|
t.Errorf("%d. %q: unexpected derivative detection:\n\nexp=%v\n\ngot=%v\n\n", i, tt.stmt, tt.derivative, d)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSelectStatement_IsSimpleDerivative(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
stmt string
|
||||||
|
derivative bool
|
||||||
|
}{
|
||||||
|
// No derivatives
|
||||||
|
{
|
||||||
|
stmt: `SELECT value FROM cpu`,
|
||||||
|
derivative: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Query derivative
|
||||||
|
{
|
||||||
|
stmt: `SELECT derivative(value) FROM cpu`,
|
||||||
|
derivative: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Query derivative
|
||||||
|
{
|
||||||
|
stmt: `SELECT non_negative_derivative(value) FROM cpu`,
|
||||||
|
derivative: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// No GROUP BY time only
|
||||||
|
{
|
||||||
|
stmt: `SELECT mean(value) FROM cpu where time < now() GROUP BY time(5ms)`,
|
||||||
|
derivative: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// No GROUP BY derivatives, time only
|
||||||
|
{
|
||||||
|
stmt: `SELECT non_negative_derivative(mean(value)) FROM cpu where time < now() GROUP BY time(5ms)`,
|
||||||
|
derivative: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Invalid derivative function name
|
||||||
|
{
|
||||||
|
stmt: `SELECT typoDerivative(value) FROM cpu where time < now()`,
|
||||||
|
derivative: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
// Parse statement.
|
||||||
|
t.Logf("index: %d, statement: %s", i, tt.stmt)
|
||||||
|
stmt, err := influxql.NewParser(strings.NewReader(tt.stmt)).ParseStatement()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invalid statement: %q: %s", tt.stmt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test derivative detection.
|
||||||
|
if d := stmt.(*influxql.SelectStatement).IsSimpleDerivative(); tt.derivative != d {
|
||||||
|
t.Errorf("%d. %q: unexpected derivative detection:\n\nexp=%v\n\ngot=%v\n\n", i, tt.stmt, tt.derivative, d)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSelectStatement_HasSimpleCount(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
stmt string
|
||||||
|
count bool
|
||||||
|
}{
|
||||||
|
// No counts
|
||||||
|
{
|
||||||
|
stmt: `SELECT value FROM cpu`,
|
||||||
|
count: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Query count
|
||||||
|
{
|
||||||
|
stmt: `SELECT count(value) FROM cpu`,
|
||||||
|
count: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// No GROUP BY time only
|
||||||
|
{
|
||||||
|
stmt: `SELECT count(distinct(value)) FROM cpu where time < now() GROUP BY time(5ms)`,
|
||||||
|
count: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Query count
|
||||||
|
{
|
||||||
|
stmt: `SELECT typoCount(value) FROM cpu`,
|
||||||
|
count: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// No GROUP BY time only
|
||||||
|
{
|
||||||
|
stmt: `SELECT typoCount(distinct(value)) FROM cpu where time < now() GROUP BY time(5ms)`,
|
||||||
|
count: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
// Parse statement.
|
||||||
|
t.Logf("index: %d, statement: %s", i, tt.stmt)
|
||||||
|
stmt, err := influxql.NewParser(strings.NewReader(tt.stmt)).ParseStatement()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invalid statement: %q: %s", tt.stmt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test count detection.
|
||||||
|
if c := stmt.(*influxql.SelectStatement).HasSimpleCount(); tt.count != c {
|
||||||
|
t.Errorf("%d. %q: unexpected count detection:\n\nexp=%v\n\ngot=%v\n\n", i, tt.stmt, tt.count, c)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSelectStatement_HasCountDistinct(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
stmt string
|
||||||
|
count bool
|
||||||
|
}{
|
||||||
|
// No counts
|
||||||
|
{
|
||||||
|
stmt: `SELECT value FROM cpu`,
|
||||||
|
count: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Query count
|
||||||
|
{
|
||||||
|
stmt: `SELECT count(value) FROM cpu`,
|
||||||
|
count: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// No GROUP BY time only
|
||||||
|
{
|
||||||
|
stmt: `SELECT count(distinct(value)) FROM cpu where time < now() GROUP BY time(5ms)`,
|
||||||
|
count: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Query count
|
||||||
|
{
|
||||||
|
stmt: `SELECT typoCount(value) FROM cpu`,
|
||||||
|
count: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// No GROUP BY time only
|
||||||
|
{
|
||||||
|
stmt: `SELECT typoCount(distinct(value)) FROM cpu where time < now() GROUP BY time(5ms)`,
|
||||||
|
count: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
// Parse statement.
|
||||||
|
t.Logf("index: %d, statement: %s", i, tt.stmt)
|
||||||
|
stmt, err := influxql.NewParser(strings.NewReader(tt.stmt)).ParseStatement()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invalid statement: %q: %s", tt.stmt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test count detection.
|
||||||
|
if c := stmt.(*influxql.SelectStatement).HasCountDistinct(); tt.count != c {
|
||||||
|
t.Errorf("%d. %q: unexpected count detection:\n\nexp=%v\n\ngot=%v\n\n", i, tt.stmt, tt.count, c)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the time range of an expression can be extracted.
|
// Ensure the time range of an expression can be extracted.
|
||||||
func TestTimeRange(t *testing.T) {
|
func TestTimeRange(t *testing.T) {
|
||||||
for i, tt := range []struct {
|
for i, tt := range []struct {
|
||||||
|
|
Loading…
Reference in New Issue