mssql: fix precision for the time column in table/annotation query mode

Use the ConvertSqlTimeColumnToEpochMs function to convert any native
datetime data type or epoch time (millisecond precision).
Additional tests and update of existing due to timezone issues
running MSSQL on UTC and dev environment on non-utc.
Update stored procedures test to handle more parameters.
Update test dashboard.
pull/11348/head
Marcus Efraimsson 8 years ago
parent b0076d4f65
commit b69ebee066
  1. 380
      docker/blocks/mssql_tests/dashboard.json
  2. 13
      pkg/tsdb/mssql/mssql.go
  3. 279
      pkg/tsdb/mssql/mssql_test.go
  4. 2
      public/app/plugins/datasource/mssql/partials/annotations.editor.html
  5. 2
      public/app/plugins/datasource/mssql/response_parser.ts

@ -53,7 +53,7 @@
"iconColor": "#6ed0e0", "iconColor": "#6ed0e0",
"limit": 100, "limit": 100,
"name": "Deploys", "name": "Deploys",
"rawQuery": "SELECT\n time_sec as time,\n description as [text],\n tags\n FROM [event]\n WHERE $__unixEpochFilter(time_sec) AND tags='deploy'\n ORDER BY 1 ASC\n ", "rawQuery": "SELECT\n $__time(time_sec),\n description as [text],\n tags\n FROM [event]\n WHERE $__unixEpochFilter(time_sec) AND tags='deploy'\n ORDER BY 1 ASC\n ",
"showIn": 0, "showIn": 0,
"tags": [], "tags": [],
"type": "tags" "type": "tags"
@ -65,7 +65,7 @@
"iconColor": "rgba(255, 96, 96, 1)", "iconColor": "rgba(255, 96, 96, 1)",
"limit": 100, "limit": 100,
"name": "Tickets", "name": "Tickets",
"rawQuery": "SELECT\n time_sec as time,\n description as [text],\n tags\n FROM [event]\n WHERE $__unixEpochFilter(time_sec) AND tags='ticket'\n ORDER BY 1 ASC\n ", "rawQuery": "SELECT\n $__time(time_sec),\n description as [text],\n tags\n FROM [event]\n WHERE $__unixEpochFilter(time_sec) AND tags='ticket'\n ORDER BY 1 ASC\n ",
"showIn": 0, "showIn": 0,
"tags": [], "tags": [],
"type": "tags" "type": "tags"
@ -76,8 +76,20 @@
"hide": false, "hide": false,
"iconColor": "#7eb26d", "iconColor": "#7eb26d",
"limit": 100, "limit": 100,
"name": "Metric Values", "name": "Metric Values timeEpoch macro",
"rawQuery": "SELECT \n time, \n measurement as text, \n '' as tags\nFROM\n metric_values \nORDER BY 1", "rawQuery": "SELECT \n $__timeEpoch(time), \n measurement as text, \n '' as tags\nFROM\n metric_values \nWHERE\n $__timeFilter(time)\nORDER BY 1",
"showIn": 0,
"tags": [],
"type": "tags"
},
{
"datasource": "${DS_MSSQL_TEST}",
"enable": false,
"hide": false,
"iconColor": "#1f78c1",
"limit": 100,
"name": "Metric Values native time",
"rawQuery": "SELECT \n time, \n measurement as text, \n '' as tags\nFROM\n metric_values \nWHERE\n $__timeFilter(time)\nORDER BY 1",
"showIn": 0, "showIn": 0,
"tags": [], "tags": [],
"type": "tags" "type": "tags"
@ -88,7 +100,7 @@
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
"iteration": 1521481503341, "iteration": 1521715844826,
"links": [], "links": [],
"panels": [ "panels": [
{ {
@ -138,6 +150,222 @@
"transform": "table", "transform": "table",
"type": "table" "type": "table"
}, },
{
"columns": [],
"datasource": "${DS_MSSQL_TEST}",
"fontSize": "100%",
"gridPos": {
"h": 3,
"w": 6,
"x": 0,
"y": 4
},
"id": 32,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"alias": "Time",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "time",
"type": "date"
},
{
"alias": "",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "short"
}
],
"targets": [
{
"alias": "",
"format": "table",
"rawSql": "SELECT cast(null as bigint) as time",
"refId": "A",
"target": ""
}
],
"title": "cast(null as bigint) as time",
"transform": "table",
"type": "table"
},
{
"columns": [],
"datasource": "${DS_MSSQL_TEST}",
"fontSize": "100%",
"gridPos": {
"h": 3,
"w": 6,
"x": 6,
"y": 4
},
"id": 33,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"alias": "Time",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "time",
"type": "date"
},
{
"alias": "",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "short"
}
],
"targets": [
{
"alias": "",
"format": "table",
"rawSql": "SELECT cast(null as datetime) as time",
"refId": "A",
"target": ""
}
],
"title": "cast(null as datetime) as time",
"transform": "table",
"type": "table"
},
{
"columns": [],
"datasource": "${DS_MSSQL_TEST}",
"fontSize": "100%",
"gridPos": {
"h": 3,
"w": 6,
"x": 12,
"y": 4
},
"id": 34,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"alias": "Time",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "time",
"type": "date"
},
{
"alias": "",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "short"
}
],
"targets": [
{
"alias": "",
"format": "table",
"rawSql": "SELECT GETDATE() as time",
"refId": "A",
"target": ""
}
],
"title": "GETDATE() as time",
"transform": "table",
"type": "table"
},
{
"columns": [],
"datasource": "${DS_MSSQL_TEST}",
"fontSize": "100%",
"gridPos": {
"h": 3,
"w": 6,
"x": 18,
"y": 4
},
"id": 35,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"alias": "Time",
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "time",
"type": "date"
},
{
"alias": "",
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "short"
}
],
"targets": [
{
"alias": "",
"format": "table",
"rawSql": "SELECT GETUTCDATE() as time",
"refId": "A",
"target": ""
}
],
"title": "GETUTCDATE() as time",
"transform": "table",
"type": "table"
},
{ {
"aliasColors": {}, "aliasColors": {},
"bars": false, "bars": false,
@ -149,7 +377,7 @@
"h": 9, "h": 9,
"w": 8, "w": 8,
"x": 0, "x": 0,
"y": 4 "y": 7
}, },
"id": 7, "id": 7,
"legend": { "legend": {
@ -228,7 +456,7 @@
"h": 9, "h": 9,
"w": 8, "w": 8,
"x": 8, "x": 8,
"y": 4 "y": 7
}, },
"id": 9, "id": 9,
"legend": { "legend": {
@ -307,7 +535,7 @@
"h": 9, "h": 9,
"w": 8, "w": 8,
"x": 16, "x": 16,
"y": 4 "y": 7
}, },
"id": 10, "id": 10,
"legend": { "legend": {
@ -386,7 +614,7 @@
"h": 9, "h": 9,
"w": 8, "w": 8,
"x": 0, "x": 0,
"y": 13 "y": 16
}, },
"id": 16, "id": 16,
"legend": { "legend": {
@ -465,7 +693,7 @@
"h": 9, "h": 9,
"w": 8, "w": 8,
"x": 8, "x": 8,
"y": 13 "y": 16
}, },
"id": 12, "id": 12,
"legend": { "legend": {
@ -544,7 +772,7 @@
"h": 9, "h": 9,
"w": 8, "w": 8,
"x": 16, "x": 16,
"y": 13 "y": 16
}, },
"id": 13, "id": 13,
"legend": { "legend": {
@ -623,7 +851,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 22 "y": 25
}, },
"id": 27, "id": 27,
"legend": { "legend": {
@ -655,13 +883,13 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT \n $__timeGroup(time, '$summarize') as time, \n measurement + ' - value one' as metric, \n avg(valueOne) as valueOne\nFROM\n metric_values \nWHERE\n $__timeFilter(time)\nGROUP BY \n $__timeGroup(time, '$summarize'), \n measurement \nORDER BY 1", "rawSql": "SELECT \n $__timeGroup(time, '$summarize') as time, \n measurement + ' - value one' as metric, \n avg(valueOne) as valueOne\nFROM\n metric_values \nWHERE\n $__timeFilter(time) AND\n ($metric = 'ALL' OR measurement = $metric)\nGROUP BY \n $__timeGroup(time, '$summarize'), \n measurement \nORDER BY 1",
"refId": "A" "refId": "A"
}, },
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT \n $__timeGroup(time, '$summarize') as time, \n measurement + ' - value two' as metric, \n avg(valueTwo) as valueTwo \nFROM\n metric_values \nGROUP BY \n $__timeGroup(time, '$summarize'), \n measurement \nORDER BY 1", "rawSql": "SELECT \n $__timeGroup(time, '$summarize') as time, \n measurement + ' - value two' as metric, \n avg(valueTwo) as valueTwo \nFROM\n metric_values\nWHERE\n $__timeFilter(time) AND\n ($metric = 'ALL' OR measurement = $metric)\nGROUP BY \n $__timeGroup(time, '$summarize'), \n measurement \nORDER BY 1",
"refId": "B" "refId": "B"
} }
], ],
@ -712,7 +940,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 22 "y": 25
}, },
"id": 5, "id": 5,
"legend": { "legend": {
@ -734,7 +962,19 @@
"pointradius": 3, "pointradius": 3,
"points": false, "points": false,
"renderer": "flot", "renderer": "flot",
"seriesOverrides": [], "seriesOverrides": [
{
"alias": "MovingAverageValueOne",
"dashes": true,
"lines": false
},
{
"alias": "MovingAverageValueTwo",
"dashes": true,
"lines": false,
"yaxis": 1
}
],
"spaceLength": 10, "spaceLength": 10,
"stack": false, "stack": false,
"steppedLine": false, "steppedLine": false,
@ -742,8 +982,14 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT \n $__timeGroup(time, '$summarize') as time, \n avg(valueOne) as valueOne, \n avg(valueTwo) as valueTwo \nFROM\n metric_values \nGROUP BY \n $__timeGroup(time, '$summarize')\nORDER BY 1", "rawSql": "SELECT \n $__timeGroup(time, '$summarize') as time, \n avg(valueOne) as valueOne, \n avg(valueTwo) as valueTwo \nFROM\n metric_values \nWHERE \n $__timeFilter(time) AND \n ($metric = 'ALL' OR measurement = $metric)\nGROUP BY \n $__timeGroup(time, '$summarize')\nORDER BY 1",
"refId": "A" "refId": "A"
},
{
"alias": "",
"format": "time_series",
"rawSql": "SELECT \n time,\n avg(valueOne) OVER (ORDER BY time ROWS BETWEEN 6 PRECEDING AND 6 FOLLOWING) as MovingAverageValueOne,\n avg(valueTwo) OVER (ORDER BY time ROWS BETWEEN 6 PRECEDING AND 6 FOLLOWING) as MovingAverageValueTwo\nFROM\n metric_values \nWHERE \n $__timeFilter(time) AND \n ($metric = 'ALL' OR measurement = $metric)\nORDER BY 1",
"refId": "B"
} }
], ],
"thresholds": [], "thresholds": [],
@ -793,7 +1039,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 30 "y": 33
}, },
"id": 4, "id": 4,
"legend": { "legend": {
@ -825,13 +1071,13 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values WHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
}, },
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values WHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "B" "refId": "B"
} }
], ],
@ -882,7 +1128,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 30 "y": 33
}, },
"id": 28, "id": 28,
"legend": { "legend": {
@ -963,7 +1209,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 38 "y": 41
}, },
"id": 19, "id": 19,
"legend": { "legend": {
@ -995,13 +1241,13 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values WHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
}, },
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values WHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "B" "refId": "B"
} }
], ],
@ -1052,7 +1298,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 38 "y": 41
}, },
"id": 18, "id": 18,
"legend": { "legend": {
@ -1082,7 +1328,7 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values\nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
} }
], ],
@ -1133,7 +1379,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 46 "y": 49
}, },
"id": 17, "id": 17,
"legend": { "legend": {
@ -1165,13 +1411,13 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values WHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
}, },
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values WHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "B" "refId": "B"
} }
], ],
@ -1222,7 +1468,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 46 "y": 49
}, },
"id": 20, "id": 20,
"legend": { "legend": {
@ -1252,7 +1498,7 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values\nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
} }
], ],
@ -1303,7 +1549,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 54 "y": 57
}, },
"id": 29, "id": 29,
"legend": { "legend": {
@ -1335,7 +1581,7 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "DECLARE \n @from int = $__unixEpochFrom(),\n @to int = $__unixEpochTo()\n \nEXEC dbo.sp_test_epoch @from, @to", "rawSql": "DECLARE\n @from int = $__unixEpochFrom(), \n @to int = $__unixEpochTo(), \n @interval nvarchar(50) = '$summarize', \n @metric nvarchar(200) = $metric\n \nEXEC dbo.sp_test_epoch @from, @to, @interval, @metric",
"refId": "A" "refId": "A"
} }
], ],
@ -1386,7 +1632,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 54 "y": 57
}, },
"id": 30, "id": 30,
"legend": { "legend": {
@ -1418,7 +1664,7 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "DECLARE \n @from datetime = $__timeFrom(),\n @to datetime = $__timeTo()\n \nEXEC dbo.sp_test_datetime @from, @to", "rawSql": "DECLARE\n @from datetime = $__timeFrom(), \n @to datetime = $__timeTo(), \n @interval nvarchar(50) = '$summarize', \n @metric nvarchar(200) = $metric\n \nEXEC dbo.sp_test_datetime @from, @to, @interval, @metric",
"refId": "A" "refId": "A"
} }
], ],
@ -1469,7 +1715,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 62 "y": 65
}, },
"id": 14, "id": 14,
"legend": { "legend": {
@ -1499,13 +1745,13 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values \nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
}, },
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values \nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "B" "refId": "B"
} }
], ],
@ -1559,7 +1805,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 62 "y": 65
}, },
"id": 15, "id": 15,
"legend": { "legend": {
@ -1589,7 +1835,7 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values\nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
} }
], ],
@ -1642,7 +1888,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 70 "y": 73
}, },
"id": 25, "id": 25,
"legend": { "legend": {
@ -1672,13 +1918,13 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values \nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
}, },
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values \nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "B" "refId": "B"
} }
], ],
@ -1732,7 +1978,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 70 "y": 73
}, },
"id": 22, "id": 22,
"legend": { "legend": {
@ -1762,7 +2008,7 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values\nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
} }
], ],
@ -1815,7 +2061,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 78 "y": 81
}, },
"id": 21, "id": 21,
"legend": { "legend": {
@ -1845,13 +2091,13 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values \nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
}, },
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values \nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "B" "refId": "B"
} }
], ],
@ -1905,7 +2151,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 78 "y": 81
}, },
"id": 26, "id": 26,
"legend": { "legend": {
@ -1935,7 +2181,7 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values \nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
} }
], ],
@ -1988,7 +2234,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 86 "y": 89
}, },
"id": 23, "id": 23,
"legend": { "legend": {
@ -2018,13 +2264,13 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value one' as metric, valueOne FROM metric_values\nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
}, },
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), measurement + ' - value two' as metric, valueTwo FROM metric_values \nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "B" "refId": "B"
} }
], ],
@ -2078,7 +2324,7 @@
"h": 8, "h": 8,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 86 "y": 89
}, },
"id": 24, "id": 24,
"legend": { "legend": {
@ -2108,7 +2354,7 @@
{ {
"alias": "", "alias": "",
"format": "time_series", "format": "time_series",
"rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values ORDER BY 1", "rawSql": "SELECT $__timeEpoch(time), valueOne, valueTwo FROM metric_values \nWHERE $__timeFilter(time) AND ($metric = 'ALL' OR measurement = $metric) ORDER BY 1",
"refId": "A" "refId": "A"
} }
], ],
@ -2157,6 +2403,26 @@
"tags": [], "tags": [],
"templating": { "templating": {
"list": [ "list": [
{
"allValue": "'ALL'",
"current": {},
"datasource": "${DS_MSSQL_TEST}",
"hide": 0,
"includeAll": true,
"label": "Metric",
"multi": false,
"name": "metric",
"options": [],
"query": "SELECT DISTINCT measurement FROM metric_values",
"refresh": 1,
"regex": "",
"sort": 0,
"tagValuesQuery": "",
"tags": [],
"tagsQuery": "",
"type": "query",
"useTags": false
},
{ {
"auto": false, "auto": false,
"auto_count": 30, "auto_count": 30,
@ -2208,7 +2474,7 @@
}, },
"time": { "time": {
"from": "2018-03-15T12:30:00.000Z", "from": "2018-03-15T12:30:00.000Z",
"to": "2018-03-15T13:55:00.000Z" "to": "2018-03-15T13:55:01.000Z"
}, },
"timepicker": { "timepicker": {
"refresh_intervals": [ "refresh_intervals": [
@ -2238,5 +2504,5 @@
"timezone": "", "timezone": "",
"title": "Microsoft SQL Server Data Source Test", "title": "Microsoft SQL Server Data Source Test",
"uid": "GlAqcPgmz", "uid": "GlAqcPgmz",
"version": 37 "version": 57
} }

@ -119,15 +119,10 @@ func (e MssqlQueryEndpoint) transformToTable(query *tsdb.Query, rows *core.Rows,
return err return err
} }
// convert column named time to unix timestamp to make // converts column named time to unix timestamp in milliseconds
// native datetime mssql types work in annotation queries // to make native mssql datetime types and epoch dates work in
if timeIndex != -1 { // annotation and table queries.
switch value := values[timeIndex].(type) { tsdb.ConvertSqlTimeColumnToEpochMs(values, timeIndex)
case time.Time:
values[timeIndex] = (float64(value.Unix()) * 1000) + float64(value.Nanosecond()/1e6) // in case someone is trying to map times beyond 2262 :D
}
}
table.Rows = append(table.Rows, values) table.Rows = append(table.Rows, values)
} }

@ -19,6 +19,8 @@ import (
// and set up a MSSQL db named grafanatest and a user/password grafana/Password! // and set up a MSSQL db named grafanatest and a user/password grafana/Password!
// Use the docker/blocks/mssql_tests/docker-compose.yaml to spin up a // Use the docker/blocks/mssql_tests/docker-compose.yaml to spin up a
// preconfigured MSSQL server suitable for running these tests. // preconfigured MSSQL server suitable for running these tests.
// Thers's also a dashboard.json in same directory that you can import to Grafana
// once you've created a datasource for the test server/database.
// If needed, change the variable below to the IP address of the database. // If needed, change the variable below to the IP address of the database.
var serverIP string = "localhost" var serverIP string = "localhost"
@ -37,7 +39,7 @@ func TestMSSQL(t *testing.T) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()
fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC) fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC).In(time.Local)
Convey("Given a table with different native data types", func() { Convey("Given a table with different native data types", func() {
sql := ` sql := `
@ -186,14 +188,8 @@ func TestMSSQL(t *testing.T) {
}) })
} }
dtFormat := "2006-01-02 15:04:05.999999999"
for _, s := range series { for _, s := range series {
sql = fmt.Sprintf(` _, err = sess.Insert(s)
INSERT INTO metric (time, value)
VALUES(CAST('%s' AS DATETIME), %d)
`, s.Time.Format(dtFormat), s.Value)
_, err = sess.Exec(sql)
So(err, ShouldBeNil) So(err, ShouldBeNil)
} }
@ -315,42 +311,34 @@ func TestMSSQL(t *testing.T) {
}) })
Convey("Given a table with metrics having multiple values and measurements", func() { Convey("Given a table with metrics having multiple values and measurements", func() {
sql := ` type metric_values struct {
IF OBJECT_ID('dbo.[metric_values]', 'U') IS NOT NULL
DROP TABLE dbo.[metric_values]
CREATE TABLE [metric_values] (
time datetime,
measurement nvarchar(100),
valueOne int,
valueTwo int,
)
`
_, err := sess.Exec(sql)
So(err, ShouldBeNil)
type metricValues struct {
Time time.Time Time time.Time
Measurement string Measurement string
ValueOne int64 ValueOne int64 `xorm:"integer 'valueOne'"`
ValueTwo int64 ValueTwo int64 `xorm:"integer 'valueTwo'"`
} }
if exist, err := sess.IsTableExist(metric_values{}); err != nil || exist {
So(err, ShouldBeNil)
sess.DropTable(metric_values{})
}
err := sess.CreateTable(metric_values{})
So(err, ShouldBeNil)
rand.Seed(time.Now().Unix()) rand.Seed(time.Now().Unix())
rnd := func(min, max int64) int64 { rnd := func(min, max int64) int64 {
return rand.Int63n(max-min) + min return rand.Int63n(max-min) + min
} }
series := []*metricValues{} series := []*metric_values{}
for _, t := range genTimeRangeByInterval(fromStart.Add(-30*time.Minute), 90*time.Minute, 5*time.Minute) { for _, t := range genTimeRangeByInterval(fromStart.Add(-30*time.Minute), 90*time.Minute, 5*time.Minute) {
series = append(series, &metricValues{ series = append(series, &metric_values{
Time: t, Time: t,
Measurement: "Metric A", Measurement: "Metric A",
ValueOne: rnd(0, 100), ValueOne: rnd(0, 100),
ValueTwo: rnd(0, 100), ValueTwo: rnd(0, 100),
}) })
series = append(series, &metricValues{ series = append(series, &metric_values{
Time: t, Time: t,
Measurement: "Metric B", Measurement: "Metric B",
ValueOne: rnd(0, 100), ValueOne: rnd(0, 100),
@ -358,14 +346,8 @@ func TestMSSQL(t *testing.T) {
}) })
} }
dtFormat := "2006-01-02 15:04:05"
for _, s := range series { for _, s := range series {
sql = fmt.Sprintf(` _, err = sess.Insert(s)
INSERT metric_values (time, measurement, valueOne, valueTwo)
VALUES(CAST('%s' AS DATETIME), '%s', %d, %d)
`, s.Time.Format(dtFormat), s.Measurement, s.ValueOne, s.ValueTwo)
_, err = sess.Exec(sql)
So(err, ShouldBeNil) So(err, ShouldBeNil)
} }
@ -383,8 +365,8 @@ func TestMSSQL(t *testing.T) {
} }
resp, err := endpoint.Query(nil, nil, query) resp, err := endpoint.Query(nil, nil, query)
queryResult := resp.Results["A"]
So(err, ShouldBeNil) So(err, ShouldBeNil)
queryResult := resp.Results["A"]
So(queryResult.Error, ShouldBeNil) So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Series), ShouldEqual, 2) So(len(queryResult.Series), ShouldEqual, 2)
@ -406,8 +388,8 @@ func TestMSSQL(t *testing.T) {
} }
resp, err := endpoint.Query(nil, nil, query) resp, err := endpoint.Query(nil, nil, query)
queryResult := resp.Results["A"]
So(err, ShouldBeNil) So(err, ShouldBeNil)
queryResult := resp.Results["A"]
So(queryResult.Error, ShouldBeNil) So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Series), ShouldEqual, 2) So(len(queryResult.Series), ShouldEqual, 2)
@ -427,31 +409,41 @@ func TestMSSQL(t *testing.T) {
sql = ` sql = `
CREATE PROCEDURE sp_test_epoch( CREATE PROCEDURE sp_test_epoch(
@from int, @from int,
@to int @to int,
@interval nvarchar(50) = '5m',
@metric nvarchar(200) = 'ALL'
) AS ) AS
BEGIN BEGIN
DECLARE @dInterval int
SELECT @dInterval = 300
IF @interval = '10m'
SELECT @dInterval = 600
SELECT SELECT
cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int) as time, CAST(ROUND(DATEDIFF(second, '1970-01-01', time)/CAST(@dInterval as float), 0) as bigint)*@dInterval as time,
measurement + ' - value one' as metric, measurement + ' - value one' as metric,
avg(valueOne) as value avg(valueOne) as value
FROM FROM
metric_values metric_values
WHERE WHERE
time >= DATEADD(s, @from, '1970-01-01') AND time <= DATEADD(s, @to, '1970-01-01') time BETWEEN DATEADD(s, @from, '1970-01-01') AND DATEADD(s, @to, '1970-01-01') AND
(@metric = 'ALL' OR measurement = @metric)
GROUP BY GROUP BY
cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int), CAST(ROUND(DATEDIFF(second, '1970-01-01', time)/CAST(@dInterval as float), 0) as bigint)*@dInterval,
measurement measurement
UNION ALL UNION ALL
SELECT SELECT
cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int) as time, CAST(ROUND(DATEDIFF(second, '1970-01-01', time)/CAST(@dInterval as float), 0) as bigint)*@dInterval as time,
measurement + ' - value two' as metric, measurement + ' - value two' as metric,
avg(valueTwo) as value avg(valueTwo) as value
FROM FROM
metric_values metric_values
WHERE WHERE
time >= DATEADD(s, @from, '1970-01-01') AND time <= DATEADD(s, @to, '1970-01-01') time BETWEEN DATEADD(s, @from, '1970-01-01') AND DATEADD(s, @to, '1970-01-01') AND
(@metric = 'ALL' OR measurement = @metric)
GROUP BY GROUP BY
cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int), CAST(ROUND(DATEDIFF(second, '1970-01-01', time)/CAST(@dInterval as float), 0) as bigint)*@dInterval,
measurement measurement
ORDER BY 1 ORDER BY 1
END END
@ -484,6 +476,7 @@ func TestMSSQL(t *testing.T) {
resp, err := endpoint.Query(nil, nil, query) resp, err := endpoint.Query(nil, nil, query)
queryResult := resp.Results["A"] queryResult := resp.Results["A"]
So(err, ShouldBeNil) So(err, ShouldBeNil)
fmt.Println("query", "sql", queryResult.Meta)
So(queryResult.Error, ShouldBeNil) So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Series), ShouldEqual, 4) So(len(queryResult.Series), ShouldEqual, 4)
@ -506,31 +499,41 @@ func TestMSSQL(t *testing.T) {
sql = ` sql = `
CREATE PROCEDURE sp_test_datetime( CREATE PROCEDURE sp_test_datetime(
@from datetime, @from datetime,
@to datetime @to datetime,
@interval nvarchar(50) = '5m',
@metric nvarchar(200) = 'ALL'
) AS ) AS
BEGIN BEGIN
DECLARE @dInterval int
SELECT @dInterval = 300
IF @interval = '10m'
SELECT @dInterval = 600
SELECT SELECT
cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int) as time, CAST(ROUND(DATEDIFF(second, '1970-01-01', time)/CAST(@dInterval as float), 0) as bigint)*@dInterval as time,
measurement + ' - value one' as metric, measurement + ' - value one' as metric,
avg(valueOne) as value avg(valueOne) as value
FROM FROM
metric_values metric_values
WHERE WHERE
time >= @from AND time <= @to time BETWEEN @from AND @to AND
(@metric = 'ALL' OR measurement = @metric)
GROUP BY GROUP BY
cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int), CAST(ROUND(DATEDIFF(second, '1970-01-01', time)/CAST(@dInterval as float), 0) as bigint)*@dInterval,
measurement measurement
UNION ALL UNION ALL
SELECT SELECT
cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int) as time, CAST(ROUND(DATEDIFF(second, '1970-01-01', time)/CAST(@dInterval as float), 0) as bigint)*@dInterval as time,
measurement + ' - value two' as metric, measurement + ' - value two' as metric,
avg(valueTwo) as value avg(valueTwo) as value
FROM FROM
metric_values metric_values
WHERE WHERE
time >= @from AND time <= @to time BETWEEN @from AND @to AND
(@metric = 'ALL' OR measurement = @metric)
GROUP BY GROUP BY
cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int), CAST(ROUND(DATEDIFF(second, '1970-01-01', time)/CAST(@dInterval as float), 0) as bigint)*@dInterval,
measurement measurement
ORDER BY 1 ORDER BY 1
END END
@ -580,7 +583,7 @@ func TestMSSQL(t *testing.T) {
DROP TABLE dbo.[event] DROP TABLE dbo.[event]
CREATE TABLE [event] ( CREATE TABLE [event] (
time_sec bigint, time_sec int,
description nvarchar(100), description nvarchar(100),
tags nvarchar(100), tags nvarchar(100),
) )
@ -666,30 +669,180 @@ func TestMSSQL(t *testing.T) {
}) })
Convey("When doing an annotation query with a time column in datetime format", func() { Convey("When doing an annotation query with a time column in datetime format", func() {
dt := time.Date(2018, 3, 14, 21, 20, 6, 527e6, time.UTC)
dtFormat := "2006-01-02 15:04:05.999999999"
query := &tsdb.TsdbQuery{ query := &tsdb.TsdbQuery{
Queries: []*tsdb.Query{ Queries: []*tsdb.Query{
{ {
Model: simplejson.NewFromAny(map[string]interface{}{ Model: simplejson.NewFromAny(map[string]interface{}{
"rawSql": "SELECT DATEADD(s, time_sec, {d '1970-01-01'}) AS time, description as [text], tags FROM [event] WHERE $__unixEpochFilter(time_sec) AND tags='ticket' ORDER BY 1 ASC", "rawSql": fmt.Sprintf(`SELECT
CAST('%s' AS DATETIME) as time,
'message' as text,
'tag1,tag2' as tags
`, dt.Format(dtFormat)),
"format": "table", "format": "table",
}), }),
RefId: "Tickets", RefId: "A",
}, },
}, },
TimeRange: &tsdb.TimeRange{ }
From: fmt.Sprintf("%v", fromStart.Add(-20*time.Minute).Unix()*1000),
To: fmt.Sprintf("%v", fromStart.Add(40*time.Minute).Unix()*1000), resp, err := endpoint.Query(nil, nil, query)
So(err, ShouldBeNil)
queryResult := resp.Results["A"]
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Tables[0].Rows), ShouldEqual, 1)
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0].(float64), ShouldEqual, float64(dt.Unix()*1000))
})
Convey("When doing an annotation query with a time column in epoch second format should return ms", func() {
dt := time.Date(2018, 3, 14, 21, 20, 6, 527e6, time.UTC)
query := &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"rawSql": fmt.Sprintf(`SELECT
%d as time,
'message' as text,
'tag1,tag2' as tags
`, dt.Unix()),
"format": "table",
}),
RefId: "A",
},
}, },
} }
resp, err := endpoint.Query(nil, nil, query) resp, err := endpoint.Query(nil, nil, query)
queryResult := resp.Results["Tickets"]
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(queryResult.Tables[0].Rows), ShouldEqual, 3) queryResult := resp.Results["A"]
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Tables[0].Rows), ShouldEqual, 1)
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0].(int64), ShouldEqual, int64(dt.Unix()*1000))
})
Convey("When doing an annotation query with a time column in epoch second format (int) should return ms", func() {
dt := time.Date(2018, 3, 14, 21, 20, 6, 527e6, time.UTC)
query := &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"rawSql": fmt.Sprintf(`SELECT
cast(%d as int) as time,
'message' as text,
'tag1,tag2' as tags
`, dt.Unix()),
"format": "table",
}),
RefId: "A",
},
},
}
resp, err := endpoint.Query(nil, nil, query)
So(err, ShouldBeNil)
queryResult := resp.Results["A"]
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Tables[0].Rows), ShouldEqual, 1)
columns := queryResult.Tables[0].Rows[0] columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds //Should be in milliseconds
So(columns[0].(float64), ShouldBeGreaterThan, 1000000000000) So(columns[0].(int64), ShouldEqual, int64(dt.Unix()*1000))
})
Convey("When doing an annotation query with a time column in epoch millisecond format should return ms", func() {
dt := time.Date(2018, 3, 14, 21, 20, 6, 527e6, time.UTC)
query := &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"rawSql": fmt.Sprintf(`SELECT
%d as time,
'message' as text,
'tag1,tag2' as tags
`, dt.Unix()*1000),
"format": "table",
}),
RefId: "A",
},
},
}
resp, err := endpoint.Query(nil, nil, query)
So(err, ShouldBeNil)
queryResult := resp.Results["A"]
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Tables[0].Rows), ShouldEqual, 1)
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0].(float64), ShouldEqual, float64(dt.Unix()*1000))
})
Convey("When doing an annotation query with a time column holding a bigint null value should return nil", func() {
query := &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"rawSql": `SELECT
cast(null as bigint) as time,
'message' as text,
'tag1,tag2' as tags
`,
"format": "table",
}),
RefId: "A",
},
},
}
resp, err := endpoint.Query(nil, nil, query)
So(err, ShouldBeNil)
queryResult := resp.Results["A"]
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Tables[0].Rows), ShouldEqual, 1)
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0], ShouldBeNil)
})
Convey("When doing an annotation query with a time column holding a datetime null value should return nil", func() {
query := &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"rawSql": `SELECT
cast(null as datetime) as time,
'message' as text,
'tag1,tag2' as tags
`,
"format": "table",
}),
RefId: "A",
},
},
}
resp, err := endpoint.Query(nil, nil, query)
So(err, ShouldBeNil)
queryResult := resp.Results["A"]
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Tables[0].Rows), ShouldEqual, 1)
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0], ShouldBeNil)
}) })
}) })
}) })
@ -697,6 +850,8 @@ func TestMSSQL(t *testing.T) {
func InitMSSQLTestDB(t *testing.T) *xorm.Engine { func InitMSSQLTestDB(t *testing.T) *xorm.Engine {
x, err := xorm.NewEngine(sqlutil.TestDB_Mssql.DriverName, strings.Replace(sqlutil.TestDB_Mssql.ConnStr, "localhost", serverIP, 1)) x, err := xorm.NewEngine(sqlutil.TestDB_Mssql.DriverName, strings.Replace(sqlutil.TestDB_Mssql.ConnStr, "localhost", serverIP, 1))
x.DatabaseTZ = time.UTC
x.TZLocation = time.UTC
// x.ShowSQL() // x.ShowSQL()
@ -704,8 +859,6 @@ func InitMSSQLTestDB(t *testing.T) *xorm.Engine {
t.Fatalf("Failed to init mssql db %v", err) t.Fatalf("Failed to init mssql db %v", err)
} }
sqlutil.CleanDB(x)
return x return x
} }

@ -20,7 +20,7 @@
<pre class="gf-form-pre alert alert-info"><h6>Annotation Query Format</h6> <pre class="gf-form-pre alert alert-info"><h6>Annotation Query Format</h6>
An annotation is an event that is overlayed on top of graphs. The query can have up to three columns per row, the <b>time</b> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned. An annotation is an event that is overlayed on top of graphs. The query can have up to three columns per row, the <b>time</b> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
- column with alias: <b>time</b> for the annotation event time (in UTC). Use unix timestamp in seconds or any native date data type. - column with alias: <b>time</b> for the annotation event time. Use epoch time or any native date data type.
- column with alias: <b>text</b> for the annotation text. - column with alias: <b>text</b> for the annotation text.
- column with alias: <b>tags</b> for annotation tags. This is a comma separated string of tags e.g. 'tag1,tag2'. - column with alias: <b>tags</b> for annotation tags. This is a comma separated string of tags e.g. 'tag1,tag2'.

@ -128,7 +128,7 @@ export default class ResponseParser {
const row = table.rows[i]; const row = table.rows[i];
list.push({ list.push({
annotation: options.annotation, annotation: options.annotation,
time: row[timeColumnIndex], time: Math.floor(row[timeColumnIndex]),
text: row[textColumnIndex], text: row[textColumnIndex],
tags: row[tagsColumnIndex] ? row[tagsColumnIndex].trim().split(/\s*,\s*/) : [], tags: row[tagsColumnIndex] ? row[tagsColumnIndex].trim().split(/\s*,\s*/) : [],
}); });

Loading…
Cancel
Save