浏览代码

make timefilter macro aware of pg version

Sven Klemm 7 年之前
父节点
当前提交
9b61ffb48a
共有 2 个文件被更改,包括 70 次插入7 次删除
  1. 10 2
      pkg/tsdb/postgres/macros.go
  2. 60 5
      pkg/tsdb/postgres/macros_test.go

+ 10 - 2
pkg/tsdb/postgres/macros.go

@@ -79,11 +79,19 @@ func (m *PostgresMacroEngine) evaluateMacro(name string, args []string) (string,
 		}
 		return fmt.Sprintf("extract(epoch from %s) as \"time\"", args[0]), nil
 	case "__timeFilter":
-		// dont use to_timestamp in this macro for redshift compatibility #9566
 		if len(args) == 0 {
 			return "", fmt.Errorf("missing time column argument for macro %v", name)
 		}
-		return fmt.Sprintf("extract(epoch from %s) BETWEEN %d AND %d", args[0], m.TimeRange.GetFromAsSecondsEpoch(), m.TimeRange.GetToAsSecondsEpoch()), nil
+
+		pg_version := m.Query.DataSource.JsonData.Get("postgresVersion").MustInt(0)
+		if pg_version >= 80100 {
+			// postgres has to_timestamp(double) starting with 8.1
+			return fmt.Sprintf("%s BETWEEN to_timestamp(%d) AND to_timestamp(%d)", args[0], m.TimeRange.GetFromAsSecondsEpoch(), m.TimeRange.GetToAsSecondsEpoch()), nil
+		}
+
+		// dont use to_timestamp in this macro for redshift compatibility #9566
+		return fmt.Sprintf("%s BETWEEN 'epoch'::timestamptz + %d * '1s'::interval AND 'epoch'::timestamptz + %d * '1s'::interval", args[0], m.TimeRange.GetFromAsSecondsEpoch(), m.TimeRange.GetToAsSecondsEpoch()), nil
+
 	case "__timeFrom":
 		return fmt.Sprintf("to_timestamp(%d)", m.TimeRange.GetFromAsSecondsEpoch()), nil
 	case "__timeTo":

+ 60 - 5
pkg/tsdb/postgres/macros_test.go

@@ -6,14 +6,27 @@ import (
 	"testing"
 	"time"
 
+	"github.com/grafana/grafana/pkg/components/simplejson"
+	"github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/tsdb"
 	. "github.com/smartystreets/goconvey/convey"
 )
 
 func TestMacroEngine(t *testing.T) {
 	Convey("MacroEngine", t, func() {
-		engine := &PostgresMacroEngine{}
-		query := &tsdb.Query{}
+		engine := NewPostgresMacroEngine()
+		// datasource with no pg version specified
+		ds := &models.DataSource{Id: 1, Type: "postgres", JsonData: simplejson.New()}
+		// datasource with postgres 8.0 configured
+		ds_80 := &models.DataSource{Id: 2, Type: "postgres", JsonData: simplejson.New()}
+		ds_80.JsonData.Set("postgresVersion", 80000)
+		// datasource with postgres 8.1 configured
+		ds_81 := &models.DataSource{Id: 3, Type: "postgres", JsonData: simplejson.New()}
+		ds_81.JsonData.Set("postgresVersion", 80100)
+
+		query := &tsdb.Query{RefId: "A", DataSource: ds}
+		query_80 := &tsdb.Query{RefId: "A", DataSource: ds_80}
+		query_81 := &tsdb.Query{RefId: "A", DataSource: ds_81}
 
 		Convey("Given a time range between 2018-04-12 00:00 and 2018-04-12 00:05", func() {
 			from := time.Date(2018, 4, 12, 18, 0, 0, 0, time.UTC)
@@ -38,7 +51,21 @@ func TestMacroEngine(t *testing.T) {
 				sql, err := engine.Interpolate(query, timeRange, "WHERE $__timeFilter(time_column)")
 				So(err, ShouldBeNil)
 
-				So(sql, ShouldEqual, fmt.Sprintf("WHERE extract(epoch from time_column) BETWEEN %d AND %d", from.Unix(), to.Unix()))
+				So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN 'epoch'::timestamptz + %d * '1s'::interval AND 'epoch'::timestamptz + %d * '1s'::interval", from.Unix(), to.Unix()))
+			})
+
+			Convey("interpolate __timeFilter function for postgres 8.0", func() {
+				sql, err := engine.Interpolate(query_80, timeRange, "WHERE $__timeFilter(time_column)")
+				So(err, ShouldBeNil)
+
+				So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN 'epoch'::timestamptz + %d * '1s'::interval AND 'epoch'::timestamptz + %d * '1s'::interval", from.Unix(), to.Unix()))
+			})
+
+			Convey("interpolate __timeFilter function for postgres 8.1", func() {
+				sql, err := engine.Interpolate(query_81, timeRange, "WHERE $__timeFilter(time_column)")
+				So(err, ShouldBeNil)
+
+				So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN to_timestamp(%d) AND to_timestamp(%d)", from.Unix(), to.Unix()))
 			})
 
 			Convey("interpolate __timeFrom function", func() {
@@ -102,7 +129,21 @@ func TestMacroEngine(t *testing.T) {
 				sql, err := engine.Interpolate(query, timeRange, "WHERE $__timeFilter(time_column)")
 				So(err, ShouldBeNil)
 
-				So(sql, ShouldEqual, fmt.Sprintf("WHERE extract(epoch from time_column) BETWEEN %d AND %d", from.Unix(), to.Unix()))
+				So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN 'epoch'::timestamptz + %d * '1s'::interval AND 'epoch'::timestamptz + %d * '1s'::interval", from.Unix(), to.Unix()))
+			})
+
+			Convey("interpolate __timeFilter function for 8.0", func() {
+				sql, err := engine.Interpolate(query_80, timeRange, "WHERE $__timeFilter(time_column)")
+				So(err, ShouldBeNil)
+
+				So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN 'epoch'::timestamptz + %d * '1s'::interval AND 'epoch'::timestamptz + %d * '1s'::interval", from.Unix(), to.Unix()))
+			})
+
+			Convey("interpolate __timeFilter function for 8.1", func() {
+				sql, err := engine.Interpolate(query_81, timeRange, "WHERE $__timeFilter(time_column)")
+				So(err, ShouldBeNil)
+
+				So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN to_timestamp(%d) AND to_timestamp(%d)", from.Unix(), to.Unix()))
 			})
 
 			Convey("interpolate __timeFrom function", func() {
@@ -150,7 +191,21 @@ func TestMacroEngine(t *testing.T) {
 				sql, err := engine.Interpolate(query, timeRange, "WHERE $__timeFilter(time_column)")
 				So(err, ShouldBeNil)
 
-				So(sql, ShouldEqual, fmt.Sprintf("WHERE extract(epoch from time_column) BETWEEN %d AND %d", from.Unix(), to.Unix()))
+				So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN 'epoch'::timestamptz + %d * '1s'::interval AND 'epoch'::timestamptz + %d * '1s'::interval", from.Unix(), to.Unix()))
+			})
+
+			Convey("interpolate __timeFilter function for 8.0", func() {
+				sql, err := engine.Interpolate(query_80, timeRange, "WHERE $__timeFilter(time_column)")
+				So(err, ShouldBeNil)
+
+				So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN 'epoch'::timestamptz + %d * '1s'::interval AND 'epoch'::timestamptz + %d * '1s'::interval", from.Unix(), to.Unix()))
+			})
+
+			Convey("interpolate __timeFilter function for 8.1", func() {
+				sql, err := engine.Interpolate(query_81, timeRange, "WHERE $__timeFilter(time_column)")
+				So(err, ShouldBeNil)
+
+				So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN to_timestamp(%d) AND to_timestamp(%d)", from.Unix(), to.Unix()))
 			})
 
 			Convey("interpolate __timeFrom function", func() {