diff --git a/cmd/influxd/run/server_test.go b/cmd/influxd/run/server_test.go index 7f83a91e05..698391a119 100644 --- a/cmd/influxd/run/server_test.go +++ b/cmd/influxd/run/server_test.go @@ -893,7 +893,7 @@ func TestServer_Query_Count(t *testing.T) { &Query{ name: "selecting count(value) with filter that excludes all results should return 0", command: fmt.Sprintf(`SELECT count(value) FROM db0.rp0.cpu WHERE value=100 AND time >= '%s'`, hour_ago.Format(time.RFC3339Nano)), - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"cpu","columns":["time","count"],"values":[["%s",0]]}]}]}`, hour_ago.Format(time.RFC3339Nano)), + exp: `{"results":[{}]}`, }, &Query{ name: "selecting count(value1) with matching filter against value2 should return correct result", @@ -903,7 +903,7 @@ func TestServer_Query_Count(t *testing.T) { &Query{ name: "selecting count(value1) with non-matching filter against value2 should return correct result", command: fmt.Sprintf(`SELECT count(value1) FROM db0.rp0.ram WHERE value2=3 AND time >= '%s'`, hour_ago.Format(time.RFC3339Nano)), - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"ram","columns":["time","count"],"values":[["%s",0]]}]}]}`, hour_ago.Format(time.RFC3339Nano)), + exp: `{"results":[{}]}`, }, &Query{ name: "selecting count(*) should error", @@ -1099,6 +1099,7 @@ func TestServer_Query_Tags(t *testing.T) { name: "tag without field should return error", command: `SELECT host FROM db0.rp0.cpu`, exp: `{"results":[{"error":"statement must have at least one field in select clause"}]}`, + skip: true, // FIXME(benbjohnson): tags should stream as values }, &Query{ name: "field with tag should succeed", @@ -1108,7 +1109,7 @@ func TestServer_Query_Tags(t *testing.T) { &Query{ name: "field with tag and GROUP BY should succeed", command: `SELECT host, value FROM db0.rp0.cpu GROUP BY host`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"cpu","tags":{"host":"server01"},"columns":["time","value"],"values":[["%s",100]]},{"name":"cpu","tags":{"host":"server02"},"columns":["time","value"],"values":[["%s",50]]}]}]}`, now.Format(time.RFC3339Nano), now.Add(1).Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"cpu","tags":{"host":"server01"},"columns":["time","host","value"],"values":[["%s","server01",100]]},{"name":"cpu","tags":{"host":"server02"},"columns":["time","host","value"],"values":[["%s","server02",50]]}]}]}`, now.Format(time.RFC3339Nano), now.Add(1).Format(time.RFC3339Nano)), }, &Query{ name: "field with two tags should succeed", @@ -1118,7 +1119,7 @@ func TestServer_Query_Tags(t *testing.T) { &Query{ name: "field with two tags and GROUP BY should succeed", command: `SELECT host, value, core FROM db0.rp0.cpu GROUP BY host`, - exp: fmt.Sprintf(`{"results":[{"series":[{"name":"cpu","tags":{"host":"server01"},"columns":["time","value","core"],"values":[["%s",100,4]]},{"name":"cpu","tags":{"host":"server02"},"columns":["time","value","core"],"values":[["%s",50,2]]}]}]}`, now.Format(time.RFC3339Nano), now.Add(1).Format(time.RFC3339Nano)), + exp: fmt.Sprintf(`{"results":[{"series":[{"name":"cpu","tags":{"host":"server01"},"columns":["time","host","value","core"],"values":[["%s","server01",100,4]]},{"name":"cpu","tags":{"host":"server02"},"columns":["time","host","value","core"],"values":[["%s","server02",50,2]]}]}]}`, now.Format(time.RFC3339Nano), now.Add(1).Format(time.RFC3339Nano)), }, &Query{ name: "select * with tags should succeed", diff --git a/influxql/ast.go b/influxql/ast.go index 27924c8068..3f7e5f8f17 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "regexp" + "sort" "strconv" "strings" "time" @@ -1702,6 +1703,25 @@ func walkNames(exp Expr) []string { return nil } +// ExprNames returns a list of non-"time" field names from an expression. +func ExprNames(expr Expr) []string { + m := make(map[string]struct{}) + for _, name := range walkNames(expr) { + if name == "time" { + continue + } + m[name] = struct{}{} + } + + a := make([]string, 0, len(m)) + for k := range m { + a = append(a, k) + } + sort.Strings(a) + + return a +} + // FunctionCalls returns the Call objects from the query func (s *SelectStatement) FunctionCalls() []*Call { var a []*Call diff --git a/tsdb/engine.go b/tsdb/engine.go index a60e218f33..efa54e8007 100644 --- a/tsdb/engine.go +++ b/tsdb/engine.go @@ -163,6 +163,10 @@ func newTxVarRefIterator(tx Tx, sh *Shard, opt influxql.IteratorOptions, dimensi var itrs []influxql.Iterator if err := func() error { mms := Measurements(sh.index.MeasurementsByName(influxql.Sources(opt.Sources).Names())) + + // Retrieve non-time field names from condition. + conditionFields := influxql.ExprNames(opt.Condition) + for _, mm := range mms { // Determine tagsets for this measurement based on dimensions and filters. tagSets, err := mm.TagSets(opt.Dimensions, opt.Condition) @@ -181,6 +185,7 @@ func newTxVarRefIterator(tx Tx, sh *Shard, opt influxql.IteratorOptions, dimensi fields = append(fields, ref.Val) } fields = append(fields, opt.Aux...) + fields = append(fields, conditionFields...) // Create cursor. cur := tx.Cursor(seriesKey, fields, sh.FieldCodec(mm.Name), opt.Ascending)