SQL datasources: Consistent interval handling (#78517)

sql: apply the received interval-value
This commit is contained in:
Gábor Farkas 2024-01-24 08:47:07 +01:00 committed by GitHub
parent 6484f4a2ac
commit fd73b75ef7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 38 additions and 30 deletions

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -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()))

View File

@ -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()")