From 7948379e85c27334b5463fb0ba7842885f5595dd Mon Sep 17 00:00:00 2001 From: "Jonathan A. Sternberg" Date: Wed, 17 Feb 2016 19:24:13 -0500 Subject: [PATCH] Assign a name to columns with binary expressions in them The name of the column will be every measurement located inside of the math expression in the order they are encountered in within the expression. Fixes #5730. --- influxql/ast.go | 23 +++++++++++++++++++++++ influxql/ast_test.go | 23 +++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/influxql/ast.go b/influxql/ast.go index 6cca54403eb..6a9c0fa2578 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -1055,6 +1055,8 @@ func (s *SelectStatement) ColumnNames() []string { continue } columnNames = append(columnNames, field.Name()) + case *BinaryExpr: + columnNames = append(columnNames, BinaryExprName(f)) default: // time is always first, and we already added it, so ignore it if they asked for it anywhere else. if field.Name() != "time" { @@ -2919,6 +2921,27 @@ func (e *BinaryExpr) String() string { return fmt.Sprintf("%s %s %s", e.LHS.String(), e.Op.String(), e.RHS.String()) } +func BinaryExprName(expr *BinaryExpr) string { + v := binaryExprNameVisitor{} + Walk(&v, expr) + return strings.Join(v.names, "_") +} + +type binaryExprNameVisitor struct { + names []string +} + +func (v *binaryExprNameVisitor) Visit(n Node) Visitor { + switch n := n.(type) { + case *VarRef: + v.names = append(v.names, n.Val) + case *Call: + v.names = append(v.names, n.Name) + return nil + } + return v +} + // ParenExpr represents a parenthesized expression. type ParenExpr struct { Expr Expr diff --git a/influxql/ast_test.go b/influxql/ast_test.go index ce5cd8f42b2..82dedcb0e3b 100644 --- a/influxql/ast_test.go +++ b/influxql/ast_test.go @@ -717,6 +717,29 @@ func TestSelectStatement_HasCountDistinct(t *testing.T) { } } +// Ensure binary expression names can be evaluated. +func TestBinaryExprName(t *testing.T) { + for i, tt := range []struct { + expr string + name string + }{ + {expr: `value + 1`, name: `value`}, + {expr: `"user" / total`, name: `user_total`}, + {expr: `("user" + total) / total`, name: `user_total_total`}, + } { + expr := influxql.MustParseExpr(tt.expr) + switch expr := expr.(type) { + case *influxql.BinaryExpr: + name := influxql.BinaryExprName(expr) + if name != tt.name { + t.Errorf("%d. unexpected name %s, got %s", i, name, tt.name) + } + default: + t.Errorf("%d. unexpected expr type: %T", i, expr) + } + } +} + // Ensure the time range of an expression can be extracted. func TestTimeRange(t *testing.T) { for i, tt := range []struct {