From 6204350d6549c5813a77d23f60bbe67a319a9b3b Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Mon, 25 Jan 2016 10:36:04 -0700 Subject: [PATCH] fix math operations --- influxql/ast.go | 21 ++++++++++++++++++ influxql/select.go | 9 ++++---- tsdb/engine/tsm1/engine.go | 10 ++++++++- tsdb/engine/tsm1/iterator.gen.go | 32 +++++++++++++++++++++++++++ tsdb/engine/tsm1/iterator.gen.go.tmpl | 8 +++++++ 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/influxql/ast.go b/influxql/ast.go index 2f52481df1..d37bd173c9 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -3698,3 +3698,24 @@ func (v *NowValuer) Value(key string) (interface{}, bool) { } return nil, false } + +// ContainsVarRef returns true if expr is a VarRef or contains one. +func ContainsVarRef(expr Expr) bool { + var v containsVarRefVisitor + Walk(&v, expr) + return v.contains +} + +type containsVarRefVisitor struct { + contains bool +} + +func (v containsVarRefVisitor) Visit(n Node) Visitor { + switch n.(type) { + case *Call: + return nil + case *VarRef: + v.contains = true + } + return v +} diff --git a/influxql/select.go b/influxql/select.go index 0dd4f46603..eaad50c672 100644 --- a/influxql/select.go +++ b/influxql/select.go @@ -64,7 +64,7 @@ func Select(stmt *SelectStatement, ic IteratorCreator) ([]Iterator, error) { } } - return buildExprIterators(fields, ic, opt) + return buildFieldIterators(fields, ic, opt) } // buildAuxIterators creates a set of iterators from a single combined auxilary iterator. @@ -107,19 +107,20 @@ func buildAuxIterators(fields Fields, ic IteratorCreator, opt IteratorOptions) ( return itrs, nil } -// buildExprIterators creates an iterator for each field expression. -func buildExprIterators(fields Fields, ic IteratorCreator, opt IteratorOptions) ([]Iterator, error) { +// buildFieldIterators creates an iterator for each field expression. +func buildFieldIterators(fields Fields, ic IteratorCreator, opt IteratorOptions) ([]Iterator, error) { // Create iterators from fields against the iterator creator. itrs := make([]Iterator, len(fields)) if err := func() error { hasAuxFields := false + var input Iterator for i, f := range fields { // Build iterators for calls first and save the iterator. // We do this so we can keep the ordering provided by the user, but // still build the Call's iterator first. - if _, ok := f.Expr.(*Call); !ok { + if ContainsVarRef(f.Expr) { hasAuxFields = true continue } diff --git a/tsdb/engine/tsm1/engine.go b/tsdb/engine/tsm1/engine.go index a7b6537e79..75f0776f4b 100644 --- a/tsdb/engine/tsm1/engine.go +++ b/tsdb/engine/tsm1/engine.go @@ -734,11 +734,19 @@ func (e *Engine) createVarRefSeriesIterator(ref *influxql.VarRef, mm *tsdb.Measu if len(opt.Aux) > 0 { aux = make([]cursorAt, len(opt.Aux)) for i := range aux { + // Create cursor from field. cur := e.buildCursor(mm.Name, seriesKey, opt.Aux[i], opt) if cur != nil { aux[i] = newBufCursor(cur) + continue + } + + // If field doesn't exist, use the tag value. + // However, if the tag value is blank then return a null. + if v := tags.Value(opt.Aux[i]); v == "" { + aux[i] = &stringNilLiteralCursor{} } else { - aux[i] = &stringLiteralCursor{value: tags.Value(opt.Aux[i])} + aux[i] = &stringLiteralCursor{value: v} } } } diff --git a/tsdb/engine/tsm1/iterator.gen.go b/tsdb/engine/tsm1/iterator.gen.go index c4721865ea..72f41684b1 100644 --- a/tsdb/engine/tsm1/iterator.gen.go +++ b/tsdb/engine/tsm1/iterator.gen.go @@ -423,6 +423,14 @@ func (c *floatLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, func (c *floatLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value } func (c *floatLiteralCursor) nextAt(seek int64) interface{} { return c.value } +// floatNilLiteralCursor represents a cursor that always returns a typed nil value. +// It doesn't not have a time value so it can only be used with nextAt(). +type floatNilLiteralCursor struct{} + +func (c *floatNilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*float64)(nil) } +func (c *floatNilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*float64)(nil) } +func (c *floatNilLiteralCursor) nextAt(seek int64) interface{} { return (*float64)(nil) } + type integerIterator struct { cur integerCursor aux []cursorAt @@ -751,6 +759,14 @@ func (c *integerLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF func (c *integerLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value } func (c *integerLiteralCursor) nextAt(seek int64) interface{} { return c.value } +// integerNilLiteralCursor represents a cursor that always returns a typed nil value. +// It doesn't not have a time value so it can only be used with nextAt(). +type integerNilLiteralCursor struct{} + +func (c *integerNilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*int64)(nil) } +func (c *integerNilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*int64)(nil) } +func (c *integerNilLiteralCursor) nextAt(seek int64) interface{} { return (*int64)(nil) } + type stringIterator struct { cur stringCursor aux []cursorAt @@ -1079,6 +1095,14 @@ func (c *stringLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, func (c *stringLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value } func (c *stringLiteralCursor) nextAt(seek int64) interface{} { return c.value } +// stringNilLiteralCursor represents a cursor that always returns a typed nil value. +// It doesn't not have a time value so it can only be used with nextAt(). +type stringNilLiteralCursor struct{} + +func (c *stringNilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*string)(nil) } +func (c *stringNilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*string)(nil) } +func (c *stringNilLiteralCursor) nextAt(seek int64) interface{} { return (*string)(nil) } + type booleanIterator struct { cur booleanCursor aux []cursorAt @@ -1407,4 +1431,12 @@ func (c *booleanLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF func (c *booleanLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, c.value } func (c *booleanLiteralCursor) nextAt(seek int64) interface{} { return c.value } +// booleanNilLiteralCursor represents a cursor that always returns a typed nil value. +// It doesn't not have a time value so it can only be used with nextAt(). +type booleanNilLiteralCursor struct{} + +func (c *booleanNilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*bool)(nil) } +func (c *booleanNilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*bool)(nil) } +func (c *booleanNilLiteralCursor) nextAt(seek int64) interface{} { return (*bool)(nil) } + var _ = fmt.Print diff --git a/tsdb/engine/tsm1/iterator.gen.go.tmpl b/tsdb/engine/tsm1/iterator.gen.go.tmpl index be1ddfe40a..bfaddc4c4a 100644 --- a/tsdb/engine/tsm1/iterator.gen.go.tmpl +++ b/tsdb/engine/tsm1/iterator.gen.go.tmpl @@ -423,6 +423,14 @@ func (c *{{.name}}LiteralCursor) next() (t int64, v interface{}) { return tsdb.E func (c *{{.name}}LiteralCursor) nextAt(seek int64) interface{} { return c.value } +// {{.name}}NilLiteralCursor represents a cursor that always returns a typed nil value. +// It doesn't not have a time value so it can only be used with nextAt(). +type {{.name}}NilLiteralCursor struct {} + +func (c *{{.name}}NilLiteralCursor) peek() (t int64, v interface{}) { return tsdb.EOF, (*{{.Type}})(nil) } +func (c *{{.name}}NilLiteralCursor) next() (t int64, v interface{}) { return tsdb.EOF, (*{{.Type}})(nil) } +func (c *{{.name}}NilLiteralCursor) nextAt(seek int64) interface{} { return (*{{.Type}})(nil) } + {{end}} var _ = fmt.Print