From f0f8006d8d675127624ca0d8c26f099acbce6299 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Fri, 16 Mar 2018 14:37:16 +0100 Subject: [PATCH] mssql: support money, smallmoney and decimal data types --- pkg/tsdb/mssql/mssql.go | 22 +++++++++++++++++++++- pkg/tsdb/mssql/mssql_test.go | 17 ++++++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/pkg/tsdb/mssql/mssql.go b/pkg/tsdb/mssql/mssql.go index f11923b499a..38e10d77eec 100644 --- a/pkg/tsdb/mssql/mssql.go +++ b/pkg/tsdb/mssql/mssql.go @@ -5,17 +5,19 @@ import ( "context" "database/sql" "fmt" + "strconv" "strings" "time" + "math" + _ "github.com/denisenkom/go-mssqldb" "github.com/go-xorm/core" "github.com/grafana/grafana/pkg/components/null" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/tsdb" - "math" ) type MssqlQueryEndpoint struct { @@ -133,6 +135,24 @@ func (e MssqlQueryEndpoint) getTypedRowData(types []*sql.ColumnType, rows *core. return nil, err } + // convert types not handled by denisenkom/go-mssqldb + // unhandled types are returned as []byte + for i := 0; i < len(types); i++ { + if value, ok := values[i].([]byte); ok == true { + switch types[i].DatabaseTypeName() { + case "MONEY", "SMALLMONEY", "DECIMAL": + if v, err := strconv.ParseFloat(string(value), 64); err == nil { + values[i] = v + } else { + e.log.Debug("Rows", "Error converting numeric to float", value) + } + default: + e.log.Debug("Rows", "Unknown database type", types[i].DatabaseTypeName(), "value", value) + values[i] = string(value) + } + } + } + return values, nil } diff --git a/pkg/tsdb/mssql/mssql_test.go b/pkg/tsdb/mssql/mssql_test.go index 01b930080d8..a6752a0a87f 100644 --- a/pkg/tsdb/mssql/mssql_test.go +++ b/pkg/tsdb/mssql/mssql_test.go @@ -34,6 +34,8 @@ func TestMSSQL(t *testing.T) { sess := x.NewSession() defer sess.Close() + fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC) + Convey("Given a table with different native data types", func() { sql := ` IF OBJECT_ID('dbo.[mssql_types]', 'U') IS NOT NULL @@ -41,14 +43,15 @@ func TestMSSQL(t *testing.T) { CREATE TABLE [mssql_types] ( c_bit bit, + c_tinyint tinyint, c_smallint smallint, c_int int, c_bigint bigint, + c_money money, c_smallmoney smallmoney, c_numeric numeric(10,5), - c_real real, c_decimal decimal(10,2), c_float float, @@ -113,17 +116,17 @@ func TestMSSQL(t *testing.T) { column := queryResult.Tables[0].Rows[0] So(column[0].(bool), ShouldEqual, true) + So(column[1].(int64), ShouldEqual, 5) So(column[2].(int64), ShouldEqual, 20020) So(column[3].(int64), ShouldEqual, 980300) So(column[4].(int64), ShouldEqual, 1420070400) - // So(column[5].(float64), ShouldEqual, 20000.15) - // So(column[6].(float64), ShouldEqual, 2.15) - //So(column[7].(float64), ShouldEqual, 12345.12) - So(column[8].(float64), ShouldEqual, 1.1100000143051147) // MSSQL dose not have precision for "real" datatype - // fix me: MSSQL driver puts the decimal inside an array of chars. and the test fails despite the values are correct. - //So(column[9].([]uint8), ShouldEqual, []uint8{'2', '.', '2', '2'}) + So(column[5].(float64), ShouldEqual, 20000.15) + So(column[6].(float64), ShouldEqual, 2.15) + So(column[7].(float64), ShouldEqual, 12345.12) + So(column[8].(float64), ShouldEqual, 1.1100000143051147) + So(column[9].(float64), ShouldEqual, 2.22) So(column[10].(float64), ShouldEqual, 3.33) So(column[11].(string), ShouldEqual, "char10 ")