diff --git a/cmd/influxd/run/server_test.go b/cmd/influxd/run/server_test.go index 05b6e2ee59..3cf8308ad6 100644 --- a/cmd/influxd/run/server_test.go +++ b/cmd/influxd/run/server_test.go @@ -807,37 +807,37 @@ func TestServer_Query_Math(t *testing.T) { &Query{ name: "SELECT multiple of float value", command: `SELECT value * 2 from db.rp.float`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time",""],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time","value"],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)), }, &Query{ name: "SELECT multiple of float value", command: `SELECT 2 * value from db.rp.float`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time",""],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time","value"],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)), }, &Query{ name: "SELECT multiple of integer value", command: `SELECT value * 2 from db.rp.integer`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value"],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)), }, &Query{ name: "SELECT float multiple of integer value", command: `SELECT value * 2.0 from db.rp.integer`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value"],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)), }, &Query{ name: "SELECT square of float value", command: `SELECT value * value from db.rp.float`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time",""],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time","value_value"],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)), }, &Query{ name: "SELECT square of integer value", command: `SELECT value * value from db.rp.integer`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value_value"],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)), }, &Query{ name: "SELECT square of integer, float value", command: `SELECT value * value,float from db.rp.integer`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","","float"],"values":[["%s",1764,null]]}]}]}`, now.Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value_value","float"],"values":[["%s",1764,null]]}]}]}`, now.Format(time.RFC3339Nano)), }, &Query{ name: "SELECT square of integer value with alias", @@ -847,17 +847,17 @@ func TestServer_Query_Math(t *testing.T) { &Query{ name: "SELECT sum of aggregates", command: `SELECT max(value) + min(value) from db.rp.integer`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["1970-01-01T00:00:00Z",84]]}]}]}`), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","max_min"],"values":[["1970-01-01T00:00:00Z",84]]}]}]}`), }, &Query{ name: "SELECT square of enclosed integer value", command: `SELECT ((value) * (value)) from db.rp.integer`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value_value"],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)), }, &Query{ name: "SELECT square of enclosed integer value", command: `SELECT (value * value) from db.rp.integer`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value_value"],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)), }, }...) @@ -2871,13 +2871,13 @@ func TestServer_Query_Aggregates_Load(t *testing.T) { name: "group by multiple dimensions", params: url.Values{"db": []string{"db0"}}, command: `SELECT sum(value)*2 FROM load`, - exp: `{"results":[{"series":[{"name":"load","columns":["time",""],"values":[["1970-01-01T00:00:00Z",300]]}]}]}`, + exp: `{"results":[{"series":[{"name":"load","columns":["time","sum"],"values":[["1970-01-01T00:00:00Z",300]]}]}]}`, }, &Query{ name: "group by multiple dimensions", params: url.Values{"db": []string{"db0"}}, command: `SELECT sum(value)/2 FROM load`, - exp: `{"results":[{"series":[{"name":"load","columns":["time",""],"values":[["1970-01-01T00:00:00Z",75]]}]}]}`, + exp: `{"results":[{"series":[{"name":"load","columns":["time","sum"],"values":[["1970-01-01T00:00:00Z",75]]}]}]}`, }, }...) diff --git a/influxql/ast.go b/influxql/ast.go index c07c07475d..93ce8e09dd 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -2642,6 +2642,11 @@ func (f *Field) Name() string { switch expr := f.Expr.(type) { case *Call: return expr.Name + case *BinaryExpr: + return BinaryExprName(expr) + case *ParenExpr: + f := Field{Expr: expr.Expr} + return f.Name() case *VarRef: return expr.Val } @@ -2922,6 +2927,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 ce5cd8f42b..0d04574327 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 { @@ -1070,12 +1093,12 @@ func Test_fieldsNames(t *testing.T) { { //case: binary expr(valRef) in: []string{"value+value"}, out: []string{"value", "value"}, - alias: []string{""}, + alias: []string{"value_value"}, }, { //case: binary expr + valRef in: []string{"value+value", "temperature"}, out: []string{"value", "value", "temperature"}, - alias: []string{"", "temperature"}, + alias: []string{"value_value", "temperature"}, }, { //case: aggregate expr in: []string{"mean(value)"}, @@ -1085,37 +1108,37 @@ func Test_fieldsNames(t *testing.T) { { //case: binary expr(aggregate expr) in: []string{"mean(value) + max(value)"}, out: []string{"value", "value"}, - alias: []string{""}, + alias: []string{"mean_max"}, }, { //case: binary expr(aggregate expr) + valRef in: []string{"mean(value) + max(value)", "temperature"}, out: []string{"value", "value", "temperature"}, - alias: []string{"", "temperature"}, + alias: []string{"mean_max", "temperature"}, }, { //case: mixed aggregate and varRef in: []string{"mean(value) + temperature"}, out: []string{"value", "temperature"}, - alias: []string{""}, + alias: []string{"mean_temperature"}, }, { //case: ParenExpr(varRef) in: []string{"(value)"}, out: []string{"value"}, - alias: []string{""}, + alias: []string{"value"}, }, { //case: ParenExpr(varRef + varRef) in: []string{"(value + value)"}, out: []string{"value", "value"}, - alias: []string{""}, + alias: []string{"value_value"}, }, { //case: ParenExpr(aggregate) in: []string{"(mean(value))"}, out: []string{"value"}, - alias: []string{""}, + alias: []string{"mean"}, }, { //case: ParenExpr(aggregate + aggregate) in: []string{"(mean(value) + max(value))"}, out: []string{"value", "value"}, - alias: []string{""}, + alias: []string{"mean_max"}, }, } { fields := influxql.Fields{} @@ -1125,11 +1148,11 @@ func Test_fieldsNames(t *testing.T) { } got := fields.Names() if !reflect.DeepEqual(got, test.out) { - t.Errorf("get fileds name:\nexp=%v\ngot=%v\n", test.out, got) + t.Errorf("get fields name:\nexp=%v\ngot=%v\n", test.out, got) } alias := fields.AliasNames() if !reflect.DeepEqual(alias, test.alias) { - t.Errorf("get fileds alias name:\nexp=%v\ngot=%v\n", test.alias, alias) + t.Errorf("get fields alias name:\nexp=%v\ngot=%v\n", test.alias, alias) } }