From fd73b75ef75e24ee734998ad1b8d537386548f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Wed, 24 Jan 2024 08:47:07 +0100 Subject: [PATCH] SQL datasources: Consistent interval handling (#78517) sql: apply the received interval-value --- .../postgres_test.go | 3 +- pkg/tsdb/mssql/mssql_test.go | 3 +- pkg/tsdb/mysql/mysql_test.go | 3 +- pkg/tsdb/sqleng/sql_engine.go | 10 +--- pkg/tsdb/sqleng/sql_engine_test.go | 49 ++++++++++++------- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go b/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go index d82b91f446f..3f903b901e4 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go +++ b/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go @@ -420,7 +420,8 @@ func TestIntegrationPostgres(t *testing.T) { "rawSql": "SELECT $__timeGroup(time, $__interval) AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1", "format": "time_series" }`), - RefID: "A", + RefID: "A", + Interval: time.Second * 60, TimeRange: backend.TimeRange{ From: fromStart, To: fromStart.Add(30 * time.Minute), diff --git a/pkg/tsdb/mssql/mssql_test.go b/pkg/tsdb/mssql/mssql_test.go index 50c30e34c0f..cfdb0dea313 100644 --- a/pkg/tsdb/mssql/mssql_test.go +++ b/pkg/tsdb/mssql/mssql_test.go @@ -319,7 +319,8 @@ func TestMSSQL(t *testing.T) { JSON: []byte(`{ "rawSql": "SELECT $__timeGroup(time, $__interval) AS time, avg(value) as value FROM metric GROUP BY $__timeGroup(time, $__interval) ORDER BY 1", "format": "time_series"}`), - RefID: "A", + RefID: "A", + Interval: time.Second * 60, TimeRange: backend.TimeRange{ From: fromStart, To: fromStart.Add(30 * time.Minute), diff --git a/pkg/tsdb/mysql/mysql_test.go b/pkg/tsdb/mysql/mysql_test.go index 87d47671a29..41c06f2534a 100644 --- a/pkg/tsdb/mysql/mysql_test.go +++ b/pkg/tsdb/mysql/mysql_test.go @@ -330,7 +330,8 @@ func TestIntegrationMySQL(t *testing.T) { "rawSql": "SELECT $__timeGroup(time, $__interval) AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1", "format": "time_series" }`), - RefID: "A", + RefID: "A", + Interval: time.Second * 60, TimeRange: backend.TimeRange{ From: fromStart, To: fromStart.Add(30 * time.Minute), diff --git a/pkg/tsdb/sqleng/sql_engine.go b/pkg/tsdb/sqleng/sql_engine.go index 71869f17437..1ed0311abd3 100644 --- a/pkg/tsdb/sqleng/sql_engine.go +++ b/pkg/tsdb/sqleng/sql_engine.go @@ -42,8 +42,6 @@ type SqlQueryResultTransformer interface { GetConverterList() []sqlutil.StringConverter } -var sqlIntervalCalculator = intervalv2.NewCalculator() - type JsonData struct { MaxOpenConns int `json:"maxOpenConns"` MaxIdleConns int `json:"maxIdleConns"` @@ -371,14 +369,10 @@ func (e *DataSourceHandler) executeQuery(query backend.DataQuery, wg *sync.WaitG // Interpolate provides global macros/substitutions for all sql datasources. var Interpolate = func(query backend.DataQuery, timeRange backend.TimeRange, timeInterval string, sql string) (string, error) { - minInterval, err := intervalv2.GetIntervalFrom(timeInterval, query.Interval.String(), query.Interval.Milliseconds(), time.Second*60) - if err != nil { - return "", err - } - interval := sqlIntervalCalculator.Calculate(timeRange, minInterval, query.MaxDataPoints) + interval := query.Interval sql = strings.ReplaceAll(sql, "$__interval_ms", strconv.FormatInt(interval.Milliseconds(), 10)) - sql = strings.ReplaceAll(sql, "$__interval", interval.Text) + sql = strings.ReplaceAll(sql, "$__interval", intervalv2.FormatDuration(interval)) sql = strings.ReplaceAll(sql, "$__unixEpochFrom()", fmt.Sprintf("%d", timeRange.From.UTC().Unix())) sql = strings.ReplaceAll(sql, "$__unixEpochTo()", fmt.Sprintf("%d", timeRange.To.UTC().Unix())) diff --git a/pkg/tsdb/sqleng/sql_engine_test.go b/pkg/tsdb/sqleng/sql_engine_test.go index 6aef946fadb..9231e8eb4e8 100644 --- a/pkg/tsdb/sqleng/sql_engine_test.go +++ b/pkg/tsdb/sqleng/sql_engine_test.go @@ -19,29 +19,40 @@ import ( func TestSQLEngine(t *testing.T) { dt := time.Date(2018, 3, 14, 21, 20, 6, int(527345*time.Microsecond), time.UTC) + t.Run("Handle interpolating $__interval and $__interval_ms", func(t *testing.T) { + from := time.Date(2018, 4, 12, 18, 0, 0, 0, time.UTC) + to := from.Add(5 * time.Minute) + timeRange := backend.TimeRange{From: from, To: to} + + text := "$__interval $__timeGroupAlias(time,$__interval) $__interval_ms" + + t.Run("interpolate 10 minutes $__interval", func(t *testing.T) { + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Minute * 10} + sql, err := Interpolate(query, timeRange, "", text) + require.NoError(t, err) + require.Equal(t, "10m $__timeGroupAlias(time,10m) 600000", sql) + }) + + t.Run("interpolate 4seconds $__interval", func(t *testing.T) { + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Second * 4} + sql, err := Interpolate(query, timeRange, "", text) + require.NoError(t, err) + require.Equal(t, "4s $__timeGroupAlias(time,4s) 4000", sql) + }) + + t.Run("interpolate 200 milliseconds $__interval", func(t *testing.T) { + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Millisecond * 200} + sql, err := Interpolate(query, timeRange, "", text) + require.NoError(t, err) + require.Equal(t, "200ms $__timeGroupAlias(time,200ms) 200", sql) + }) + }) + t.Run("Given a time range between 2018-04-12 00:00 and 2018-04-12 00:05", func(t *testing.T) { from := time.Date(2018, 4, 12, 18, 0, 0, 0, time.UTC) to := from.Add(5 * time.Minute) timeRange := backend.TimeRange{From: from, To: to} - query := backend.DataQuery{JSON: []byte("{}")} - - t.Run("interpolate $__interval", func(t *testing.T) { - sql, err := Interpolate(query, timeRange, "", "select $__interval ") - require.NoError(t, err) - require.Equal(t, "select 1m ", sql) - }) - - t.Run("interpolate $__interval in $__timeGroup", func(t *testing.T) { - sql, err := Interpolate(query, timeRange, "", "select $__timeGroupAlias(time,$__interval)") - require.NoError(t, err) - require.Equal(t, "select $__timeGroupAlias(time,1m)", sql) - }) - - t.Run("interpolate $__interval_ms", func(t *testing.T) { - sql, err := Interpolate(query, timeRange, "", "select $__interval_ms ") - require.NoError(t, err) - require.Equal(t, "select 60000 ", sql) - }) + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Second * 60} t.Run("interpolate __unixEpochFrom function", func(t *testing.T) { sql, err := Interpolate(query, timeRange, "", "select $__unixEpochFrom()")