From c2c22c142bad47db4ba9f468eab8c0e63784faf5 Mon Sep 17 00:00:00 2001 From: Sven Klemm <31455525+svenklemm@users.noreply.github.com> Date: Sun, 1 Jul 2018 15:55:46 +0200 Subject: [PATCH] [postgres] fix timeGroup macro rounding (#12468) * fix timeGroup tests to check for correct grouping * do explicit floor rounding in $__timeGroup macro * fix typo in comments --- pkg/tsdb/postgres/macros.go | 2 +- pkg/tsdb/postgres/macros_test.go | 4 ++-- pkg/tsdb/postgres/postgres_test.go | 26 +++++++++++++++++--------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/pkg/tsdb/postgres/macros.go b/pkg/tsdb/postgres/macros.go index 05e39f2c762..61e88418ff4 100644 --- a/pkg/tsdb/postgres/macros.go +++ b/pkg/tsdb/postgres/macros.go @@ -109,7 +109,7 @@ func (m *PostgresMacroEngine) evaluateMacro(name string, args []string) (string, m.Query.Model.Set("fillValue", floatVal) } } - return fmt.Sprintf("(extract(epoch from %s)/%v)::bigint*%v AS time", args[0], interval.Seconds(), interval.Seconds()), nil + return fmt.Sprintf("floor(extract(epoch from %s)/%v)*%v AS time", args[0], interval.Seconds(), interval.Seconds()), nil case "__unixEpochFilter": if len(args) == 0 { return "", fmt.Errorf("missing time column argument for macro %v", name) diff --git a/pkg/tsdb/postgres/macros_test.go b/pkg/tsdb/postgres/macros_test.go index c3c15691e42..8c581850430 100644 --- a/pkg/tsdb/postgres/macros_test.go +++ b/pkg/tsdb/postgres/macros_test.go @@ -53,7 +53,7 @@ func TestMacroEngine(t *testing.T) { sql, err := engine.Interpolate(query, timeRange, "GROUP BY $__timeGroup(time_column,'5m')") So(err, ShouldBeNil) - So(sql, ShouldEqual, "GROUP BY (extract(epoch from time_column)/300)::bigint*300 AS time") + So(sql, ShouldEqual, "GROUP BY floor(extract(epoch from time_column)/300)*300 AS time") }) Convey("interpolate __timeGroup function with spaces between args", func() { @@ -61,7 +61,7 @@ func TestMacroEngine(t *testing.T) { sql, err := engine.Interpolate(query, timeRange, "GROUP BY $__timeGroup(time_column , '5m')") So(err, ShouldBeNil) - So(sql, ShouldEqual, "GROUP BY (extract(epoch from time_column)/300)::bigint*300 AS time") + So(sql, ShouldEqual, "GROUP BY floor(extract(epoch from time_column)/300)*300 AS time") }) Convey("interpolate __timeTo function", func() { diff --git a/pkg/tsdb/postgres/postgres_test.go b/pkg/tsdb/postgres/postgres_test.go index 7f24d5a2063..18ceecb1080 100644 --- a/pkg/tsdb/postgres/postgres_test.go +++ b/pkg/tsdb/postgres/postgres_test.go @@ -189,21 +189,23 @@ func TestPostgres(t *testing.T) { So(queryResult.Error, ShouldBeNil) points := queryResult.Series[0].Points - So(len(points), ShouldEqual, 6) + // without fill this should result in 4 buckets + So(len(points), ShouldEqual, 4) dt := fromStart - for i := 0; i < 3; i++ { + for i := 0; i < 2; i++ { aValue := points[i][0].Float64 aTime := time.Unix(int64(points[i][1].Float64)/1000, 0) So(aValue, ShouldEqual, 15) So(aTime, ShouldEqual, dt) + So(aTime.Unix()%300, ShouldEqual, 0) dt = dt.Add(5 * time.Minute) } - // adjust for 5 minute gap - dt = dt.Add(5 * time.Minute) - for i := 3; i < 6; i++ { + // adjust for 10 minute gap between first and second set of points + dt = dt.Add(10 * time.Minute) + for i := 2; i < 4; i++ { aValue := points[i][0].Float64 aTime := time.Unix(int64(points[i][1].Float64)/1000, 0) So(aValue, ShouldEqual, 20) @@ -239,7 +241,7 @@ func TestPostgres(t *testing.T) { dt := fromStart - for i := 0; i < 3; i++ { + for i := 0; i < 2; i++ { aValue := points[i][0].Float64 aTime := time.Unix(int64(points[i][1].Float64)/1000, 0) So(aValue, ShouldEqual, 15) @@ -247,17 +249,23 @@ func TestPostgres(t *testing.T) { dt = dt.Add(5 * time.Minute) } + // check for NULL values inserted by fill + So(points[2][0].Valid, ShouldBeFalse) So(points[3][0].Valid, ShouldBeFalse) - // adjust for 5 minute gap - dt = dt.Add(5 * time.Minute) - for i := 4; i < 7; i++ { + // adjust for 10 minute gap between first and second set of points + dt = dt.Add(10 * time.Minute) + for i := 4; i < 6; i++ { aValue := points[i][0].Float64 aTime := time.Unix(int64(points[i][1].Float64)/1000, 0) So(aValue, ShouldEqual, 20) So(aTime, ShouldEqual, dt) dt = dt.Add(5 * time.Minute) } + + // check for NULL values inserted by fill + So(points[6][0].Valid, ShouldBeFalse) + }) Convey("When doing a metric query using timeGroup with float fill enabled", func() {