mirror of
https://github.com/grafana/grafana.git
synced 2024-11-23 09:26:43 -06:00
postgres: fix precision for time columns in time series query mode
This commit is contained in:
parent
af62646624
commit
1783c534fd
@ -7,7 +7,6 @@ import (
|
||||
"math"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/go-xorm/core"
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
@ -219,13 +218,16 @@ func (e PostgresQueryEndpoint) transformToTimeSeries(query *tsdb.Query, rows *co
|
||||
return err
|
||||
}
|
||||
|
||||
// converts column named time to unix timestamp in milliseconds to make
|
||||
// native mysql datetime types and epoch dates work in
|
||||
// annotation and table queries.
|
||||
tsdb.ConvertSqlTimeColumnToEpochMs(values, timeIndex)
|
||||
|
||||
switch columnValue := values[timeIndex].(type) {
|
||||
case int64:
|
||||
timestamp = float64(columnValue * 1000)
|
||||
timestamp = float64(columnValue)
|
||||
case float64:
|
||||
timestamp = columnValue * 1000
|
||||
case time.Time:
|
||||
timestamp = float64(columnValue.UnixNano() / 1e6)
|
||||
timestamp = columnValue
|
||||
default:
|
||||
return fmt.Errorf("Invalid type for column time, must be of type timestamp or unix timestamp, got: %T %v", columnValue, columnValue)
|
||||
}
|
||||
|
@ -156,8 +156,7 @@ func TestPostgres(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
for _, s := range series {
|
||||
_, err = sess.Insert(s)
|
||||
_, err = sess.InsertMulti(series)
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
|
||||
@ -280,10 +279,18 @@ func TestPostgres(t *testing.T) {
|
||||
|
||||
Convey("Given a table with metrics having multiple values and measurements", func() {
|
||||
type metric_values struct {
|
||||
Time time.Time
|
||||
Measurement string
|
||||
ValueOne int64 `xorm:"integer 'valueOne'"`
|
||||
ValueTwo int64 `xorm:"integer 'valueTwo'"`
|
||||
Time time.Time
|
||||
TimeInt64 int64 `xorm:"bigint 'timeInt64' not null"`
|
||||
TimeInt64Nullable *int64 `xorm:"bigint 'timeInt64Nullable' null"`
|
||||
TimeFloat64 float64 `xorm:"double 'timeFloat64' not null"`
|
||||
TimeFloat64Nullable *float64 `xorm:"double 'timeFloat64Nullable' null"`
|
||||
TimeInt32 int32 `xorm:"int(11) 'timeInt32' not null"`
|
||||
TimeInt32Nullable *int32 `xorm:"int(11) 'timeInt32Nullable' null"`
|
||||
TimeFloat32 float32 `xorm:"double 'timeFloat32' not null"`
|
||||
TimeFloat32Nullable *float32 `xorm:"double 'timeFloat32Nullable' null"`
|
||||
Measurement string
|
||||
ValueOne int64 `xorm:"integer 'valueOne'"`
|
||||
ValueTwo int64 `xorm:"integer 'valueTwo'"`
|
||||
}
|
||||
|
||||
if exist, err := sess.IsTableExist(metric_values{}); err != nil || exist {
|
||||
@ -298,27 +305,220 @@ func TestPostgres(t *testing.T) {
|
||||
return rand.Int63n(max-min) + min
|
||||
}
|
||||
|
||||
var tInitial time.Time
|
||||
|
||||
series := []*metric_values{}
|
||||
for _, t := range genTimeRangeByInterval(fromStart.Add(-30*time.Minute), 90*time.Minute, 5*time.Minute) {
|
||||
series = append(series, &metric_values{
|
||||
Time: t,
|
||||
Measurement: "Metric A",
|
||||
ValueOne: rnd(0, 100),
|
||||
ValueTwo: rnd(0, 100),
|
||||
})
|
||||
series = append(series, &metric_values{
|
||||
Time: t,
|
||||
Measurement: "Metric B",
|
||||
ValueOne: rnd(0, 100),
|
||||
ValueTwo: rnd(0, 100),
|
||||
})
|
||||
for i, t := range genTimeRangeByInterval(fromStart.Add(-30*time.Minute), 90*time.Minute, 5*time.Minute) {
|
||||
if i == 0 {
|
||||
tInitial = t
|
||||
}
|
||||
tSeconds := t.Unix()
|
||||
tSecondsInt32 := int32(tSeconds)
|
||||
tSecondsFloat32 := float32(tSeconds)
|
||||
tMilliseconds := tSeconds * 1e3
|
||||
tMillisecondsFloat := float64(tMilliseconds)
|
||||
first := metric_values{
|
||||
Time: t,
|
||||
TimeInt64: tMilliseconds,
|
||||
TimeInt64Nullable: &(tMilliseconds),
|
||||
TimeFloat64: tMillisecondsFloat,
|
||||
TimeFloat64Nullable: &tMillisecondsFloat,
|
||||
TimeInt32: tSecondsInt32,
|
||||
TimeInt32Nullable: &tSecondsInt32,
|
||||
TimeFloat32: tSecondsFloat32,
|
||||
TimeFloat32Nullable: &tSecondsFloat32,
|
||||
Measurement: "Metric A",
|
||||
ValueOne: rnd(0, 100),
|
||||
ValueTwo: rnd(0, 100),
|
||||
}
|
||||
second := first
|
||||
second.Measurement = "Metric B"
|
||||
second.ValueOne = rnd(0, 100)
|
||||
second.ValueTwo = rnd(0, 100)
|
||||
|
||||
series = append(series, &first)
|
||||
series = append(series, &second)
|
||||
}
|
||||
|
||||
for _, s := range series {
|
||||
_, err := sess.Insert(s)
|
||||
_, err = sess.InsertMulti(series)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("When doing a metric query using epoch (int64) as time column should return metric with time in milliseconds", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"rawSql": `SELECT "timeInt64" as time, "valueOne" FROM metric_values ORDER BY time LIMIT 1`,
|
||||
"format": "time_series",
|
||||
}),
|
||||
RefId: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := endpoint.Query(nil, nil, query)
|
||||
So(err, ShouldBeNil)
|
||||
queryResult := resp.Results["A"]
|
||||
So(queryResult.Error, ShouldBeNil)
|
||||
|
||||
So(len(queryResult.Series), ShouldEqual, 1)
|
||||
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(tInitial.UnixNano()/1e6))
|
||||
})
|
||||
|
||||
Convey("When doing a metric query using epoch (int64 nullable) as time column should return metric with time in milliseconds", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"rawSql": `SELECT "timeInt64Nullable" as time, "valueOne" FROM metric_values ORDER BY time LIMIT 1`,
|
||||
"format": "time_series",
|
||||
}),
|
||||
RefId: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := endpoint.Query(nil, nil, query)
|
||||
So(err, ShouldBeNil)
|
||||
queryResult := resp.Results["A"]
|
||||
So(queryResult.Error, ShouldBeNil)
|
||||
|
||||
So(len(queryResult.Series), ShouldEqual, 1)
|
||||
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(tInitial.UnixNano()/1e6))
|
||||
})
|
||||
|
||||
Convey("When doing a metric query using epoch (float64) as time column should return metric with time in milliseconds", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"rawSql": `SELECT "timeFloat64" as time, "valueOne" FROM metric_values ORDER BY time LIMIT 1`,
|
||||
"format": "time_series",
|
||||
}),
|
||||
RefId: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := endpoint.Query(nil, nil, query)
|
||||
So(err, ShouldBeNil)
|
||||
queryResult := resp.Results["A"]
|
||||
So(queryResult.Error, ShouldBeNil)
|
||||
|
||||
So(len(queryResult.Series), ShouldEqual, 1)
|
||||
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(tInitial.UnixNano()/1e6))
|
||||
})
|
||||
|
||||
Convey("When doing a metric query using epoch (float64 nullable) as time column should return metric with time in milliseconds", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"rawSql": `SELECT "timeFloat64Nullable" as time, "valueOne" FROM metric_values ORDER BY time LIMIT 1`,
|
||||
"format": "time_series",
|
||||
}),
|
||||
RefId: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := endpoint.Query(nil, nil, query)
|
||||
So(err, ShouldBeNil)
|
||||
queryResult := resp.Results["A"]
|
||||
So(queryResult.Error, ShouldBeNil)
|
||||
|
||||
So(len(queryResult.Series), ShouldEqual, 1)
|
||||
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(tInitial.UnixNano()/1e6))
|
||||
})
|
||||
|
||||
Convey("When doing a metric query using epoch (int32) as time column should return metric with time in milliseconds", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"rawSql": `SELECT "timeInt32" as time, "valueOne" FROM metric_values ORDER BY time LIMIT 1`,
|
||||
"format": "time_series",
|
||||
}),
|
||||
RefId: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := endpoint.Query(nil, nil, query)
|
||||
So(err, ShouldBeNil)
|
||||
queryResult := resp.Results["A"]
|
||||
So(queryResult.Error, ShouldBeNil)
|
||||
|
||||
So(len(queryResult.Series), ShouldEqual, 1)
|
||||
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(tInitial.UnixNano()/1e6))
|
||||
})
|
||||
|
||||
Convey("When doing a metric query using epoch (int32 nullable) as time column should return metric with time in milliseconds", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"rawSql": `SELECT "timeInt32Nullable" as time, "valueOne" FROM metric_values ORDER BY time LIMIT 1`,
|
||||
"format": "time_series",
|
||||
}),
|
||||
RefId: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := endpoint.Query(nil, nil, query)
|
||||
So(err, ShouldBeNil)
|
||||
queryResult := resp.Results["A"]
|
||||
So(queryResult.Error, ShouldBeNil)
|
||||
|
||||
So(len(queryResult.Series), ShouldEqual, 1)
|
||||
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(tInitial.UnixNano()/1e6))
|
||||
})
|
||||
|
||||
Convey("When doing a metric query using epoch (float32) as time column should return metric with time in milliseconds", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"rawSql": `SELECT "timeFloat32" as time, "valueOne" FROM metric_values ORDER BY time LIMIT 1`,
|
||||
"format": "time_series",
|
||||
}),
|
||||
RefId: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := endpoint.Query(nil, nil, query)
|
||||
So(err, ShouldBeNil)
|
||||
queryResult := resp.Results["A"]
|
||||
So(queryResult.Error, ShouldBeNil)
|
||||
|
||||
So(len(queryResult.Series), ShouldEqual, 1)
|
||||
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float64(float32(tInitial.Unix())))*1e3)
|
||||
})
|
||||
|
||||
Convey("When doing a metric query using epoch (float32 nullable) as time column should return metric with time in milliseconds", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"rawSql": `SELECT "timeFloat32Nullable" as time, "valueOne" FROM metric_values ORDER BY time LIMIT 1`,
|
||||
"format": "time_series",
|
||||
}),
|
||||
RefId: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := endpoint.Query(nil, nil, query)
|
||||
So(err, ShouldBeNil)
|
||||
queryResult := resp.Results["A"]
|
||||
So(queryResult.Error, ShouldBeNil)
|
||||
|
||||
So(len(queryResult.Series), ShouldEqual, 1)
|
||||
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float64(float32(tInitial.Unix())))*1e3)
|
||||
})
|
||||
|
||||
Convey("When doing a metric query grouping by time and select metric column should return correct series", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
@ -473,7 +673,7 @@ func TestPostgres(t *testing.T) {
|
||||
columns := queryResult.Tables[0].Rows[0]
|
||||
|
||||
//Should be in milliseconds
|
||||
So(columns[0].(float64), ShouldEqual, float64(dt.Unix()*1000))
|
||||
So(columns[0].(float64), ShouldEqual, float64(dt.UnixNano()/1e6))
|
||||
})
|
||||
|
||||
Convey("When doing an annotation query with a time column in epoch second format should return ms", func() {
|
||||
|
Loading…
Reference in New Issue
Block a user