diff --git a/docs/sources/features/datasources/mysql.md b/docs/sources/features/datasources/mysql.md index bc4e4df6cf9..371c92cde70 100644 --- a/docs/sources/features/datasources/mysql.md +++ b/docs/sources/features/datasources/mysql.md @@ -133,9 +133,9 @@ Macro example | Description ------------ | ------------- *$__time(dateColumn)* | Will be replaced by an expression to convert to a UNIX timestamp and rename the column to `time_sec`. For example, *UNIX_TIMESTAMP(dateColumn) as time_sec* *$__timeEpoch(dateColumn)* | Will be replaced by an expression to convert to a UNIX timestamp and rename the column to `time_sec`. For example, *UNIX_TIMESTAMP(dateColumn) as time_sec* -*$__timeFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name. For example, *dateColumn BETWEEN '2017-04-21T05:01:17Z' AND '2017-04-21T05:06:17Z'* -*$__timeFrom()* | Will be replaced by the start of the currently active time selection. For example, *'2017-04-21T05:01:17Z'* -*$__timeTo()* | Will be replaced by the end of the currently active time selection. For example, *'2017-04-21T05:06:17Z'* +*$__timeFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name. For example, *dateColumn BETWEEN FROM_UNIXTIME(1494410783) AND FROM_UNIXTIME(1494410983)* +*$__timeFrom()* | Will be replaced by the start of the currently active time selection. For example, *FROM_UNIXTIME(1494410783)* +*$__timeTo()* | Will be replaced by the end of the currently active time selection. For example, *FROM_UNIXTIME(1494410983)* *$__timeGroup(dateColumn,'5m')* | Will be replaced by an expression usable in GROUP BY clause. For example, *cast(cast(UNIX_TIMESTAMP(dateColumn)/(300) as signed)*300 as signed),* *$__timeGroup(dateColumn,'5m', 0)* | Same as above but with a fill parameter so missing points in that series will be added by grafana and 0 will be used as value. *$__timeGroup(dateColumn,'5m', NULL)* | Same as above but NULL will be used as value for missing points. diff --git a/pkg/tsdb/mssql/macros.go b/pkg/tsdb/mssql/macros.go index 0a260f7ad70..dac18f3ac03 100644 --- a/pkg/tsdb/mssql/macros.go +++ b/pkg/tsdb/mssql/macros.go @@ -66,6 +66,10 @@ func (m *msSqlMacroEngine) evaluateMacro(name string, args []string) (string, er } return fmt.Sprintf("%s BETWEEN '%s' AND '%s'", args[0], m.timeRange.GetFromAsTimeUTC().Format(time.RFC3339), m.timeRange.GetToAsTimeUTC().Format(time.RFC3339)), nil + case "__timeFrom": + return fmt.Sprintf("'%s'", m.timeRange.GetFromAsTimeUTC().Format(time.RFC3339)), nil + case "__timeTo": + return fmt.Sprintf("'%s'", m.timeRange.GetToAsTimeUTC().Format(time.RFC3339)), nil case "__timeGroup": if len(args) < 2 { return "", fmt.Errorf("macro %v needs time column and interval", name) diff --git a/pkg/tsdb/mssql/macros_test.go b/pkg/tsdb/mssql/macros_test.go index 7456238efa4..43cbe9fefda 100644 --- a/pkg/tsdb/mssql/macros_test.go +++ b/pkg/tsdb/mssql/macros_test.go @@ -52,6 +52,20 @@ func TestMacroEngine(t *testing.T) { So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN '%s' AND '%s'", from.Format(time.RFC3339), to.Format(time.RFC3339))) }) + Convey("interpolate __timeFrom function", func() { + sql, err := engine.Interpolate(query, timeRange, "select $__timeFrom()") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, "select '2018-04-12T18:00:00Z'") + }) + + Convey("interpolate __timeTo function", func() { + sql, err := engine.Interpolate(query, timeRange, "select $__timeTo()") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, "select '2018-04-12T18:05:00Z'") + }) + Convey("interpolate __timeGroup function", func() { sql, err := engine.Interpolate(query, timeRange, "GROUP BY $__timeGroup(time_column,'5m')") So(err, ShouldBeNil) diff --git a/pkg/tsdb/mysql/macros.go b/pkg/tsdb/mysql/macros.go index 839f805568e..c0ed64aa65c 100644 --- a/pkg/tsdb/mysql/macros.go +++ b/pkg/tsdb/mysql/macros.go @@ -61,6 +61,10 @@ func (m *mySqlMacroEngine) evaluateMacro(name string, args []string) (string, er } return fmt.Sprintf("%s BETWEEN FROM_UNIXTIME(%d) AND FROM_UNIXTIME(%d)", args[0], m.timeRange.GetFromAsSecondsEpoch(), m.timeRange.GetToAsSecondsEpoch()), nil + case "__timeFrom": + return fmt.Sprintf("FROM_UNIXTIME(%d)", m.timeRange.GetFromAsSecondsEpoch()), nil + case "__timeTo": + return fmt.Sprintf("FROM_UNIXTIME(%d)", m.timeRange.GetToAsSecondsEpoch()), nil case "__timeGroup": if len(args) < 2 { return "", fmt.Errorf("macro %v needs time column and interval", name) diff --git a/pkg/tsdb/mysql/macros_test.go b/pkg/tsdb/mysql/macros_test.go index 24bf18873d5..49633347a4c 100644 --- a/pkg/tsdb/mysql/macros_test.go +++ b/pkg/tsdb/mysql/macros_test.go @@ -63,6 +63,20 @@ func TestMacroEngine(t *testing.T) { So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN FROM_UNIXTIME(%d) AND FROM_UNIXTIME(%d)", from.Unix(), to.Unix())) }) + Convey("interpolate __timeFrom function", func() { + sql, err := engine.Interpolate(query, timeRange, "select $__timeFrom()") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, fmt.Sprintf("select FROM_UNIXTIME(%d)", from.Unix())) + }) + + Convey("interpolate __timeTo function", func() { + sql, err := engine.Interpolate(query, timeRange, "select $__timeTo()") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, fmt.Sprintf("select FROM_UNIXTIME(%d)", to.Unix())) + }) + Convey("interpolate __unixEpochFilter function", func() { sql, err := engine.Interpolate(query, timeRange, "select $__unixEpochFilter(time)") So(err, ShouldBeNil) diff --git a/pkg/tsdb/mysql/mysql_test.go b/pkg/tsdb/mysql/mysql_test.go index 476e3ba6586..fe59a4b9d9d 100644 --- a/pkg/tsdb/mysql/mysql_test.go +++ b/pkg/tsdb/mysql/mysql_test.go @@ -761,7 +761,7 @@ func TestMySQL(t *testing.T) { { DataSource: &models.DataSource{JsonData: simplejson.New()}, Model: simplejson.NewFromAny(map[string]interface{}{ - "rawSql": `SELECT time FROM metric_values WHERE time > $__timeFrom() OR time < $__timeFrom() OR 1 < $__unixEpochFrom() OR $__unixEpochTo() > 1 ORDER BY 1`, + "rawSql": `SELECT time FROM metric_values WHERE time > $__timeFrom() OR time < $__timeTo() OR 1 < $__unixEpochFrom() OR $__unixEpochTo() > 1 ORDER BY 1`, "format": "time_series", }), RefId: "A", @@ -773,7 +773,7 @@ func TestMySQL(t *testing.T) { So(err, ShouldBeNil) queryResult := resp.Results["A"] So(queryResult.Error, ShouldBeNil) - So(queryResult.Meta.Get("sql").MustString(), ShouldEqual, "SELECT time FROM metric_values WHERE time > '2018-03-15T12:55:00Z' OR time < '2018-03-15T12:55:00Z' OR 1 < 1521118500 OR 1521118800 > 1 ORDER BY 1") + So(queryResult.Meta.Get("sql").MustString(), ShouldEqual, "SELECT time FROM metric_values WHERE time > FROM_UNIXTIME(1521118500) OR time < FROM_UNIXTIME(1521118800) OR 1 < 1521118500 OR 1521118800 > 1 ORDER BY 1") }) diff --git a/pkg/tsdb/postgres/macros.go b/pkg/tsdb/postgres/macros.go index 0fa5d8077e1..26a3d1e53ee 100644 --- a/pkg/tsdb/postgres/macros.go +++ b/pkg/tsdb/postgres/macros.go @@ -87,6 +87,10 @@ func (m *postgresMacroEngine) evaluateMacro(name string, args []string) (string, } return fmt.Sprintf("%s BETWEEN '%s' AND '%s'", args[0], m.timeRange.GetFromAsTimeUTC().Format(time.RFC3339), m.timeRange.GetToAsTimeUTC().Format(time.RFC3339)), nil + case "__timeFrom": + return fmt.Sprintf("'%s'", m.timeRange.GetFromAsTimeUTC().Format(time.RFC3339)), nil + case "__timeTo": + return fmt.Sprintf("'%s'", m.timeRange.GetToAsTimeUTC().Format(time.RFC3339)), nil case "__timeGroup": if len(args) < 2 { return "", fmt.Errorf("macro %v needs time column and interval and optional fill value", name) diff --git a/pkg/tsdb/postgres/macros_test.go b/pkg/tsdb/postgres/macros_test.go index 8a3699f82b2..6a71caedeb9 100644 --- a/pkg/tsdb/postgres/macros_test.go +++ b/pkg/tsdb/postgres/macros_test.go @@ -44,6 +44,20 @@ func TestMacroEngine(t *testing.T) { So(sql, ShouldEqual, fmt.Sprintf("WHERE time_column BETWEEN '%s' AND '%s'", from.Format(time.RFC3339), to.Format(time.RFC3339))) }) + Convey("interpolate __timeFrom function", func() { + sql, err := engine.Interpolate(query, timeRange, "select $__timeFrom()") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, "select '2018-04-12T18:00:00Z'") + }) + + Convey("interpolate __timeTo function", func() { + sql, err := engine.Interpolate(query, timeRange, "select $__timeTo()") + So(err, ShouldBeNil) + + So(sql, ShouldEqual, "select '2018-04-12T18:05:00Z'") + }) + Convey("interpolate __timeGroup function pre 5.3 compatibility", func() { sql, err := engine.Interpolate(query, timeRange, "SELECT $__timeGroup(time_column,'5m'), value") diff --git a/pkg/tsdb/sql_engine.go b/pkg/tsdb/sql_engine.go index 1a4e2bd3943..ab7230e9b02 100644 --- a/pkg/tsdb/sql_engine.go +++ b/pkg/tsdb/sql_engine.go @@ -196,8 +196,6 @@ var Interpolate = func(query *Query, timeRange *TimeRange, sql string) (string, sql = strings.Replace(sql, "$__interval_ms", strconv.FormatInt(interval.Milliseconds(), 10), -1) sql = strings.Replace(sql, "$__interval", interval.Text, -1) - sql = strings.Replace(sql, "$__timeFrom()", fmt.Sprintf("'%s'", timeRange.GetFromAsTimeUTC().Format(time.RFC3339)), -1) - sql = strings.Replace(sql, "$__timeTo()", fmt.Sprintf("'%s'", timeRange.GetToAsTimeUTC().Format(time.RFC3339)), -1) sql = strings.Replace(sql, "$__unixEpochFrom()", fmt.Sprintf("%d", timeRange.GetFromAsSecondsEpoch()), -1) sql = strings.Replace(sql, "$__unixEpochTo()", fmt.Sprintf("%d", timeRange.GetToAsSecondsEpoch()), -1) diff --git a/pkg/tsdb/sql_engine_test.go b/pkg/tsdb/sql_engine_test.go index bfcc82aac47..bc77a95734d 100644 --- a/pkg/tsdb/sql_engine_test.go +++ b/pkg/tsdb/sql_engine_test.go @@ -44,20 +44,6 @@ func TestSqlEngine(t *testing.T) { So(sql, ShouldEqual, "select 60000 ") }) - Convey("interpolate __timeFrom function", func() { - sql, err := Interpolate(query, timeRange, "select $__timeFrom()") - So(err, ShouldBeNil) - - So(sql, ShouldEqual, fmt.Sprintf("select '%s'", from.Format(time.RFC3339))) - }) - - Convey("interpolate __timeTo function", func() { - sql, err := Interpolate(query, timeRange, "select $__timeTo()") - So(err, ShouldBeNil) - - So(sql, ShouldEqual, fmt.Sprintf("select '%s'", to.Format(time.RFC3339))) - }) - Convey("interpolate __unixEpochFrom function", func() { sql, err := Interpolate(query, timeRange, "select $__unixEpochFrom()") So(err, ShouldBeNil) diff --git a/public/app/plugins/datasource/mysql/partials/annotations.editor.html b/public/app/plugins/datasource/mysql/partials/annotations.editor.html index 5f2e44887ba..79f3c782898 100644 --- a/public/app/plugins/datasource/mysql/partials/annotations.editor.html +++ b/public/app/plugins/datasource/mysql/partials/annotations.editor.html @@ -28,12 +28,12 @@ An annotation is an event that is overlaid on top of graphs. The query can have Macros: - $__time(column) -> UNIX_TIMESTAMP(column) as time (or as time_sec) - $__timeEpoch(column) -> UNIX_TIMESTAMP(column) as time (or as time_sec) -- $__timeFilter(column) -> column BETWEEN '2017-04-21T05:01:17Z' AND '2017-04-21T05:01:17Z' +- $__timeFilter(column) -> column BETWEEN FROM_UNIXTIME(1492750877) AND FROM_UNIXTIME(1492750877) - $__unixEpochFilter(column) -> time_unix_epoch > 1492750877 AND time_unix_epoch < 1492750877 Or build your own conditionals using these macros which just return the values: -- $__timeFrom() -> '2017-04-21T05:01:17Z' -- $__timeTo() -> '2017-04-21T05:01:17Z' +- $__timeFrom() -> FROM_UNIXTIME(1492750877) +- $__timeTo() -> FROM_UNIXTIME(1492750877) - $__unixEpochFrom() -> 1492750877 - $__unixEpochTo() -> 1492750877 diff --git a/public/app/plugins/datasource/mysql/partials/query.editor.html b/public/app/plugins/datasource/mysql/partials/query.editor.html index f857244b438..90680ed104f 100644 --- a/public/app/plugins/datasource/mysql/partials/query.editor.html +++ b/public/app/plugins/datasource/mysql/partials/query.editor.html @@ -151,7 +151,7 @@ Table: Macros: - $__time(column) -> UNIX_TIMESTAMP(column) as time_sec - $__timeEpoch(column) -> UNIX_TIMESTAMP(column) as time_sec -- $__timeFilter(column) -> column BETWEEN '2017-04-21T05:01:17Z' AND '2017-04-21T05:01:17Z' +- $__timeFilter(column) -> column BETWEEN FROM_UNIXTIME(1492750877) AND FROM_UNIXTIME(1492750877) - $__unixEpochFilter(column) -> time_unix_epoch > 1492750877 AND time_unix_epoch < 1492750877 - $__timeGroup(column,'5m'[, fillvalue]) -> cast(cast(UNIX_TIMESTAMP(column)/(300) as signed)*300 as signed) by setting fillvalue grafana will fill in missing values according to the interval @@ -169,8 +169,8 @@ GROUP BY 1 ORDER BY 1 Or build your own conditionals using these macros which just return the values: -- $__timeFrom() -> '2017-04-21T05:01:17Z' -- $__timeTo() -> '2017-04-21T05:01:17Z' +- $__timeFrom() -> FROM_UNIXTIME(1492750877) +- $__timeTo() -> FROM_UNIXTIME(1492750877) - $__unixEpochFrom() -> 1492750877 - $__unixEpochTo() -> 1492750877