From c4a4f021cafab8ab7c88649d8f47c0bb56d31f3b Mon Sep 17 00:00:00 2001 From: Paul Dix Date: Wed, 4 Feb 2015 06:51:01 -0500 Subject: [PATCH 1/5] Update server test case to show failing on where time clause --- server_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server_test.go b/server_test.go index f17566b285..aac2a75ab9 100644 --- a/server_test.go +++ b/server_test.go @@ -720,6 +720,13 @@ func TestServer_ExecuteQuery(t *testing.T) { } else if s := mustMarshalJSON(res); s != `{"rows":[{"name":"cpu","tags":{"region":"us-east"},"columns":["time","sum"],"values":[["2000-01-01T00:00:00Z",20],["2000-01-01T00:00:10Z",30]]},{"name":"cpu","tags":{"region":"us-west"},"columns":["time","sum"],"values":[["2000-01-01T00:00:00Z",100]]}]}` { t.Fatalf("unexpected row(0): %s", s) } + + results = s.ExecuteQuery(MustParseQuery(`SELECT sum(value) FROM cpu WHERE time >= '2000-01-01T00:00:05Z' GROUP BY time(10s), region`), "foo", nil) + if res := results.Results[0]; res.Err != nil { + t.Fatalf("unexpected error: %s", res.Err) + } else if s := mustMarshalJSON(res); s != `{"rows":[{"name":"cpu","tags":{"region":"us-east"},"columns":["time","sum"],"values":[["2000-01-01T00:00:10Z",30]]}]}` { + t.Fatalf("unexpected row(0): %s", s) + } } func TestServer_CreateShardGroupIfNotExist(t *testing.T) { From bc813cc9da9b87f1561a29b93649e0a93847d190 Mon Sep 17 00:00:00 2001 From: Paul Dix Date: Thu, 5 Feb 2015 01:29:19 -0500 Subject: [PATCH 2/5] Fix queries with where clause only having time. * Add OnlyTimeDimensions to SelectStatement * Update the database to handle queries that only have a time statement * Fix server test to insert a time literal that can be parsed. --- database.go | 6 ++++++ influxql/ast.go | 25 +++++++++++++++++++++++++ influxql/ast_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ server_test.go | 2 +- 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/database.go b/database.go index e5c78ba20f..6f7d526f59 100644 --- a/database.go +++ b/database.go @@ -239,6 +239,12 @@ func (m *Measurement) seriesIDsAndFilters(stmt *influxql.SelectStatement) (serie return m.seriesIDs, nil } ids, _, _ := m.walkWhereForSeriesIds(stmt.Condition, seriesIdsToExpr) + + // ids will be empty if all they had was a time in the where clause. so return all measurement series ids + if len(ids) == 0 && stmt.OnlyTimeDimensions() { + return m.seriesIDs, nil + } + return ids, seriesIdsToExpr } diff --git a/influxql/ast.go b/influxql/ast.go index 5c44016d1a..4490f52899 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -657,6 +657,31 @@ func (s *SelectStatement) Aggregated() bool { return v } +// OnlyTimeDimensions returns true if the statement has a where clause with only time constraints +func (s *SelectStatement) OnlyTimeDimensions() bool { + return s.walkForTime(s.Condition) +} + +// walkForTime is called by the OnlyTimeDimensions method to walk the where clause to determine if +// the only things specified are based on time +func (s *SelectStatement) walkForTime(node Node) bool { + switch n := node.(type) { + case *BinaryExpr: + if n.Op == AND || n.Op == OR { + return s.walkForTime(n.LHS) && s.walkForTime(n.RHS) + } + if ref, ok := n.LHS.(*VarRef); ok && strings.ToLower(ref.Val) == "time" { + return true + } + return false + case *ParenExpr: + // walk down the tree + return s.walkForTime(n.Expr) + default: + return false + } +} + /* BinaryExpr diff --git a/influxql/ast_test.go b/influxql/ast_test.go index 33872e9082..0fd28d716c 100644 --- a/influxql/ast_test.go +++ b/influxql/ast_test.go @@ -146,6 +146,46 @@ func TestTimeRange(t *testing.T) { } } +// Ensure that we see if a where clause has only time limitations +func TestSelectStatement_OnlyTimeDimensions(t *testing.T) { + var tests = []struct { + stmt string + exp bool + }{ + { + stmt: `SELECT value FROM myseries WHERE value > 1`, + exp: false, + }, + { + stmt: `SELECT value FROM foo WHERE time >= '2000-01-01T00:00:05'`, + exp: true, + }, + { + stmt: `SELECT value FROM foo WHERE time >= '2000-01-01T00:00:05' AND time < '2000-01-01T00:00:05'`, + exp: true, + }, + { + stmt: `SELECT value FROM foo WHERE time >= '2000-01-01T00:00:05' AND asdf = 'bar'`, + exp: false, + }, + { + stmt: `SELECT value FROM foo WHERE asdf = 'jkl' AND (time >= '2000-01-01T00:00:05' AND time < '2000-01-01T00:00:05')`, + exp: false, + }, + } + + for i, tt := range tests { + // Parse statement. + stmt, err := influxql.NewParser(strings.NewReader(tt.stmt)).ParseStatement() + if err != nil { + t.Fatalf("invalid statement: %q: %s", tt.stmt, err) + } + if stmt.(*influxql.SelectStatement).OnlyTimeDimensions() != tt.exp { + t.Fatalf("%d. expected statement to return only time dimension to be %t: %s", i, tt.exp, tt.stmt) + } + } +} + // Ensure an AST node can be rewritten. func TestRewrite(t *testing.T) { expr := MustParseExpr(`time > 1 OR foo = 2`) diff --git a/server_test.go b/server_test.go index aac2a75ab9..2642944aa8 100644 --- a/server_test.go +++ b/server_test.go @@ -721,7 +721,7 @@ func TestServer_ExecuteQuery(t *testing.T) { t.Fatalf("unexpected row(0): %s", s) } - results = s.ExecuteQuery(MustParseQuery(`SELECT sum(value) FROM cpu WHERE time >= '2000-01-01T00:00:05Z' GROUP BY time(10s), region`), "foo", nil) + results = s.ExecuteQuery(MustParseQuery(`SELECT sum(value) FROM cpu WHERE time >= '2000-01-01T00:00:05' GROUP BY time(10s), region`), "foo", nil) if res := results.Results[0]; res.Err != nil { t.Fatalf("unexpected error: %s", res.Err) } else if s := mustMarshalJSON(res); s != `{"rows":[{"name":"cpu","tags":{"region":"us-east"},"columns":["time","sum"],"values":[["2000-01-01T00:00:10Z",30]]}]}` { From 095d210d59f8bcfd5519d9350e08b9ad6aeefc1d Mon Sep 17 00:00:00 2001 From: Philip O'Toole Date: Fri, 6 Feb 2015 20:36:38 -0800 Subject: [PATCH 3/5] Fix time range condition in unit test --- server_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_test.go b/server_test.go index 2642944aa8..eb56fb5784 100644 --- a/server_test.go +++ b/server_test.go @@ -721,7 +721,7 @@ func TestServer_ExecuteQuery(t *testing.T) { t.Fatalf("unexpected row(0): %s", s) } - results = s.ExecuteQuery(MustParseQuery(`SELECT sum(value) FROM cpu WHERE time >= '2000-01-01T00:00:05' GROUP BY time(10s), region`), "foo", nil) + results = s.ExecuteQuery(MustParseQuery(`SELECT sum(value) FROM cpu WHERE time >= '2000-01-01 00:00:05' GROUP BY time(10s), region`), "foo", nil) if res := results.Results[0]; res.Err != nil { t.Fatalf("unexpected error: %s", res.Err) } else if s := mustMarshalJSON(res); s != `{"rows":[{"name":"cpu","tags":{"region":"us-east"},"columns":["time","sum"],"values":[["2000-01-01T00:00:10Z",30]]}]}` { From 6c60c6397f9375f88aa77c6ac37079d3e9a89392 Mon Sep 17 00:00:00 2001 From: Philip O'Toole Date: Fri, 6 Feb 2015 21:55:28 -0800 Subject: [PATCH 4/5] Add simple non-aggregate test This makes it clearer what is going on. --- server_test.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/server_test.go b/server_test.go index eb56fb5784..6d24ab3aab 100644 --- a/server_test.go +++ b/server_test.go @@ -721,11 +721,20 @@ func TestServer_ExecuteQuery(t *testing.T) { t.Fatalf("unexpected row(0): %s", s) } + // Simple non-aggregation. + results = s.ExecuteQuery(MustParseQuery(`SELECT value FROM cpu WHERE time >= '2000-01-01 00:00:05'`), "foo", nil) + if res := results.Results[0]; res.Err != nil { + t.Fatalf("unexpected error during simple SELECT: %s", res.Err) + } else if s := mustMarshalJSON(res); s != `{"rows":[{"name":"cpu","columns":["time","value"],"values":[["2000-01-01T00:00:10Z",30]]}]}` { + t.Fatalf("unexpected row(0) during simple SELECT: %s", s) + } + + // Sum aggregation. results = s.ExecuteQuery(MustParseQuery(`SELECT sum(value) FROM cpu WHERE time >= '2000-01-01 00:00:05' GROUP BY time(10s), region`), "foo", nil) if res := results.Results[0]; res.Err != nil { - t.Fatalf("unexpected error: %s", res.Err) + t.Fatalf("unexpected error during SUM: %s", res.Err) } else if s := mustMarshalJSON(res); s != `{"rows":[{"name":"cpu","tags":{"region":"us-east"},"columns":["time","sum"],"values":[["2000-01-01T00:00:10Z",30]]}]}` { - t.Fatalf("unexpected row(0): %s", s) + t.Fatalf("unexpected row(0) during SUM: %s", s) } } From c6e7a7f9ea98a2885891bb38b2167023e4164acf Mon Sep 17 00:00:00 2001 From: Paul Dix Date: Sat, 7 Feb 2015 06:29:04 -0500 Subject: [PATCH 5/5] Fix mapper to check if the iterator is EOF before calling the map function --- influxql/engine.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/influxql/engine.go b/influxql/engine.go index a183063410..4069dbed8b 100644 --- a/influxql/engine.go +++ b/influxql/engine.go @@ -404,14 +404,14 @@ func (m *Mapper) run(e *Emitter) { bufItr.tmax = tmin + m.interval - 1 } - // Execute the map function. - m.fn(bufItr, e, tmin) - // Exit if there was only one interval or no more data is available. if bufItr.EOF() { break } + // Execute the map function. + m.fn(bufItr, e, tmin) + // Move the interval forward. tmin += m.interval }