Postgres/MySQL/MSSQL: Fix region annotations not displayed correctly (#38936)

Fix region annotations not displayed correctly when returning timeend column 
as epoch timestamp and by that making sure that the returned data frame field 
named timeend is treated as time type.

Fixes #38533
pull/38959/head
Marcus Efraimsson 4 years ago committed by GitHub
parent 9aa03acfa6
commit fbdaf56a84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      pkg/tsdb/mssql/mssql_test.go
  2. 26
      pkg/tsdb/mysql/mysql_test.go
  3. 26
      pkg/tsdb/postgres/postgres_test.go
  4. 33
      pkg/tsdb/sqleng/sql_engine.go

@ -1163,6 +1163,32 @@ func TestMSSQL(t *testing.T) {
// Should be in time.Time
require.Nil(t, frames[0].Fields[0].At(0))
})
t.Run("When doing an annotation query with a time and timeend column should return two fields of type time", func(t *testing.T) {
query := &backend.QueryDataRequest{
Queries: []backend.DataQuery{
{
JSON: []byte(`{
"rawSql": "SELECT 1631053772276 as time, 1631054012276 as timeend, '' as text, '' as tags",
"format": "table"
}`),
RefID: "A",
},
},
}
resp, err := endpoint.QueryData(context.Background(), query)
require.NoError(t, err)
queryResult := resp.Responses["A"]
require.NoError(t, queryResult.Error)
frames := queryResult.Frames
require.Equal(t, 1, len(frames))
require.Equal(t, 4, len(frames[0].Fields))
require.Equal(t, data.FieldTypeNullableTime, frames[0].Fields[0].Type())
require.Equal(t, data.FieldTypeNullableTime, frames[0].Fields[1].Type())
})
})
}

@ -1125,6 +1125,32 @@ func TestMySQL(t *testing.T) {
//Should be in time.Time
require.Nil(t, frames[0].Fields[0].At(0))
})
t.Run("When doing an annotation query with a time and timeend column should return two fields of type time", func(t *testing.T) {
query := &backend.QueryDataRequest{
Queries: []backend.DataQuery{
{
JSON: []byte(`{
"rawSql": "SELECT 1631053772276 as time, 1631054012276 as timeend, '' as text, '' as tags",
"format": "table"
}`),
RefID: "A",
},
},
}
resp, err := exe.QueryData(context.Background(), query)
require.NoError(t, err)
queryResult := resp.Responses["A"]
require.NoError(t, queryResult.Error)
frames := queryResult.Frames
require.Equal(t, 1, len(frames))
require.Equal(t, 4, len(frames[0].Fields))
require.Equal(t, data.FieldTypeNullableTime, frames[0].Fields[0].Type())
require.Equal(t, data.FieldTypeNullableTime, frames[0].Fields[1].Type())
})
})
}

@ -1199,6 +1199,32 @@ func TestPostgres(t *testing.T) {
// Should be in time.Time
assert.Nil(t, frames[0].Fields[0].At(0))
})
t.Run("When doing an annotation query with a time and timeend column should return two fields of type time", func(t *testing.T) {
query := &backend.QueryDataRequest{
Queries: []backend.DataQuery{
{
JSON: []byte(`{
"rawSql": "SELECT 1631053772276 as time, 1631054012276 as timeend, '' as text, '' as tags",
"format": "table"
}`),
RefID: "A",
},
},
}
resp, err := exe.QueryData(context.Background(), query)
require.NoError(t, err)
queryResult := resp.Responses["A"]
require.NoError(t, queryResult.Error)
frames := queryResult.Frames
require.Equal(t, 1, len(frames))
require.Equal(t, 4, len(frames[0].Fields))
require.Equal(t, data.FieldTypeNullableTime, frames[0].Fields[0].Type())
require.Equal(t, data.FieldTypeNullableTime, frames[0].Fields[1].Type())
})
})
}

@ -18,6 +18,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data/sqlutil"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
"github.com/grafana/grafana/pkg/util/errutil"
"xorm.io/core"
"xorm.io/xorm"
)
@ -300,11 +301,9 @@ func (e *DataSourceHandler) executeQuery(query backend.DataQuery, wg *sync.WaitG
return
}
if qm.timeIndex != -1 {
if err := convertSQLTimeColumnToEpochMS(frame, qm.timeIndex); err != nil {
errAppendDebug("db convert time column failed", err, interpolatedQuery)
return
}
if err := convertSQLTimeColumnsToEpochMS(frame, qm); err != nil {
errAppendDebug("converting time columns failed", err, interpolatedQuery)
return
}
if qm.Format == dataQueryFormatSeries {
@ -408,6 +407,7 @@ func (e *DataSourceHandler) newProcessCfg(query backend.DataQuery, queryContext
columnNames: columnNames,
rows: rows,
timeIndex: -1,
timeEndIndex: -1,
metricIndex: -1,
metricPrefix: false,
queryContext: queryContext,
@ -454,6 +454,12 @@ func (e *DataSourceHandler) newProcessCfg(query backend.DataQuery, queryContext
break
}
}
if qm.Format == dataQueryFormatTable && col == "timeend" {
qm.timeEndIndex = i
continue
}
switch col {
case "metric":
qm.metricIndex = i
@ -492,6 +498,7 @@ type dataQueryModel struct {
columnNames []string
columnTypes []*sql.ColumnType
timeIndex int
timeEndIndex int
metricIndex int
rows *core.Rows
metricPrefix bool
@ -821,6 +828,22 @@ func convertNullableFloat32ToEpochMS(origin *data.Field, newField *data.Field) {
}
}
func convertSQLTimeColumnsToEpochMS(frame *data.Frame, qm *dataQueryModel) error {
if qm.timeIndex != -1 {
if err := convertSQLTimeColumnToEpochMS(frame, qm.timeIndex); err != nil {
return errutil.Wrap("failed to convert time column", err)
}
}
if qm.timeEndIndex != -1 {
if err := convertSQLTimeColumnToEpochMS(frame, qm.timeEndIndex); err != nil {
return errutil.Wrap("failed to convert timeend column", err)
}
}
return nil
}
// convertSQLTimeColumnToEpochMS converts column named time to unix timestamp in milliseconds
// to make native datetime types and epoch dates work in annotation and table queries.
func convertSQLTimeColumnToEpochMS(frame *data.Frame, timeIndex int) error {

Loading…
Cancel
Save