Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
97e2d75f
Commit
97e2d75f
authored
Apr 21, 2017
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mysql: added support for tables in mysql queries
parent
c78c460f
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
193 additions
and
32 deletions
+193
-32
pkg/tsdb/models.go
+12
-1
pkg/tsdb/mysql/mysql.go
+81
-18
public/app/features/panel/metrics_panel_ctrl.ts
+1
-0
public/app/plugins/datasource/mysql/datasource.ts
+19
-4
public/app/plugins/datasource/mysql/module.ts
+1
-1
public/app/plugins/datasource/mysql/partials/query.editor.html
+1
-8
vendor/github.com/go-sql-driver/mysql/row_columntypes.go
+78
-0
No files found.
pkg/tsdb/models.go
View file @
97e2d75f
...
...
@@ -51,14 +51,25 @@ type QueryResult struct {
RefId
string
`json:"refId"`
Meta
*
simplejson
.
Json
`json:"meta,omitempty"`
Series
TimeSeriesSlice
`json:"series"`
Tables
[]
*
Table
`json:"tables"`
}
type
TimeSeries
struct
{
Name
string
`json:"name"`
Points
TimeSeriesPoints
`json:"points"`
Tags
map
[
string
]
string
`json:"tags"`
Tags
map
[
string
]
string
`json:"tags
,omitempty
"`
}
type
Table
struct
{
Columns
[]
TableColumn
`json:"columns"`
Rows
[]
RowValues
`json:"rows"`
}
type
TableColumn
struct
{
Text
string
`json:"text"`
}
type
RowValues
[]
interface
{}
type
TimePoint
[
2
]
null
.
Float
type
TimeSeriesPoints
[]
TimePoint
type
TimeSeriesSlice
[]
*
TimeSeries
...
...
pkg/tsdb/mysql/mysql.go
View file @
97e2d75f
...
...
@@ -7,6 +7,7 @@ import (
"strconv"
"sync"
"github.com/go-sql-driver/mysql"
"github.com/go-xorm/core"
"github.com/go-xorm/xorm"
"github.com/grafana/grafana/pkg/components/null"
...
...
@@ -114,34 +115,97 @@ func (e *MysqlExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, co
format
:=
query
.
Model
.
Get
(
"format"
)
.
MustString
(
"time_series"
)
if
format
==
"time_series"
{
res
,
err
:=
e
.
TransformToTimeSeries
(
query
,
rows
)
switch
format
{
case
"time_series"
:
err
:=
e
.
TransformToTimeSeries
(
query
,
rows
,
queryResult
)
if
err
!=
nil
{
queryResult
.
Error
=
err
continue
}
case
"table"
:
err
:=
e
.
TransformToTable
(
query
,
rows
,
queryResult
)
if
err
!=
nil
{
queryResult
.
Error
=
err
continue
}
}
}
return
result
}
func
(
e
MysqlExecutor
)
TransformToTable
(
query
*
tsdb
.
Query
,
rows
*
core
.
Rows
,
result
*
tsdb
.
QueryResult
)
error
{
columnNames
,
err
:=
rows
.
Columns
()
columnCount
:=
len
(
columnNames
)
if
err
!=
nil
{
return
err
}
queryResult
.
Series
=
res
queryResult
.
Meta
.
Set
(
"rowCount"
,
countPointsInAllSeries
(
res
))
table
:=
&
tsdb
.
Table
{
Columns
:
make
([]
tsdb
.
TableColumn
,
columnCount
),
Rows
:
make
([]
tsdb
.
RowValues
,
0
),
}
for
i
,
name
:=
range
columnNames
{
table
.
Columns
[
i
]
.
Text
=
name
}
return
result
columnTypes
,
err
:=
rows
.
ColumnTypes
()
if
err
!=
nil
{
return
err
}
rowLimit
:=
1000000
rowCount
:=
0
for
;
rows
.
Next
();
rowCount
+=
1
{
if
rowCount
>
rowLimit
{
return
fmt
.
Errorf
(
"MySQL query row limit exceeded, limit %d"
,
rowLimit
)
}
values
,
err
:=
e
.
getTypedRowData
(
columnTypes
,
rows
)
if
err
!=
nil
{
return
err
}
table
.
Rows
=
append
(
table
.
Rows
,
values
)
}
result
.
Tables
=
append
(
result
.
Tables
,
table
)
result
.
Meta
.
Set
(
"rowCount"
,
rowCount
)
return
nil
}
func
countPointsInAllSeries
(
seriesList
tsdb
.
TimeSeriesSlice
)
(
count
int
)
{
for
_
,
series
:=
range
seriesList
{
count
+=
len
(
series
.
Points
)
func
(
e
MysqlExecutor
)
getTypedRowData
(
types
[]
*
sql
.
ColumnType
,
rows
*
core
.
Rows
)
(
tsdb
.
RowValues
,
error
)
{
values
:=
make
([]
interface
{},
len
(
types
))
for
i
,
stype
:=
range
types
{
switch
stype
.
DatabaseTypeName
()
{
case
mysql
.
FieldTypeNameVarString
:
values
[
i
]
=
new
(
string
)
case
mysql
.
FieldTypeNameLongLong
:
values
[
i
]
=
new
(
int64
)
case
mysql
.
FieldTypeNameDouble
:
values
[
i
]
=
new
(
float64
)
default
:
return
nil
,
fmt
.
Errorf
(
"Database type %s not supported"
,
stype
)
}
}
if
err
:=
rows
.
Scan
(
values
...
);
err
!=
nil
{
return
nil
,
err
}
return
count
return
values
,
nil
}
func
(
e
MysqlExecutor
)
TransformToTimeSeries
(
query
*
tsdb
.
Query
,
rows
*
core
.
Rows
)
(
tsdb
.
TimeSeriesSlice
,
error
)
{
func
(
e
MysqlExecutor
)
TransformToTimeSeries
(
query
*
tsdb
.
Query
,
rows
*
core
.
Rows
,
result
*
tsdb
.
QueryResult
)
error
{
pointsBySeries
:=
make
(
map
[
string
]
*
tsdb
.
TimeSeries
)
columnNames
,
err
:=
rows
.
Columns
()
if
err
!=
nil
{
return
nil
,
err
return
err
}
rowData
:=
NewStringStringScan
(
columnNames
)
...
...
@@ -150,13 +214,13 @@ func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows)
for
;
rows
.
Next
();
rowCount
+=
1
{
if
rowCount
>
rowLimit
{
return
nil
,
fmt
.
Errorf
(
"MySQL query row limit exceeded, limit %d"
,
rowLimit
)
return
fmt
.
Errorf
(
"MySQL query row limit exceeded, limit %d"
,
rowLimit
)
}
err
:=
rowData
.
Update
(
rows
.
Rows
)
if
err
!=
nil
{
e
.
log
.
Error
(
"MySQL response parsing"
,
"error"
,
err
)
return
nil
,
fmt
.
Errorf
(
"MySQL response parsing error %v"
,
err
)
return
fmt
.
Errorf
(
"MySQL response parsing error %v"
,
err
)
}
if
rowData
.
metric
==
""
{
...
...
@@ -166,7 +230,7 @@ func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows)
//e.log.Debug("Rows", "metric", rowData.metric, "time", rowData.time, "value", rowData.value)
if
!
rowData
.
time
.
Valid
{
return
nil
,
fmt
.
Errorf
(
"Found row with no time value"
)
return
fmt
.
Errorf
(
"Found row with no time value"
)
}
if
series
,
exist
:=
pointsBySeries
[
rowData
.
metric
];
exist
{
...
...
@@ -178,13 +242,12 @@ func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows)
}
}
seriesList
:=
make
(
tsdb
.
TimeSeriesSlice
,
0
)
for
_
,
value
:=
range
pointsBySeries
{
seriesList
=
append
(
seriesList
,
value
)
result
.
Series
=
append
(
result
.
Series
,
value
)
}
e
.
log
.
Debug
(
"TransformToTimeSeries"
,
"rowCount"
,
rowCount
,
"timeSeriesCount"
,
len
(
seriesList
)
)
return
seriesList
,
nil
result
.
Meta
.
Set
(
"rowCount"
,
rowCount
)
return
nil
}
type
stringStringScan
struct
{
...
...
public/app/features/panel/metrics_panel_ctrl.ts
View file @
97e2d75f
...
...
@@ -31,6 +31,7 @@ class MetricsPanelCtrl extends PanelCtrl {
skipDataOnInit
:
boolean
;
dataStream
:
any
;
dataSubscription
:
any
;
dataList
:
any
;
constructor
(
$scope
,
$injector
)
{
super
(
$scope
,
$injector
);
...
...
public/app/plugins/datasource/mysql/datasource.ts
View file @
97e2d75f
...
...
@@ -38,14 +38,20 @@ export class MysqlDatasource {
to
:
options
.
range
.
to
.
valueOf
().
toString
(),
queries
:
queries
,
}
}).
then
(
res
=>
{
}).
then
(
this
.
processQueryResult
.
bind
(
this
));
}
processQueryResult
(
res
)
{
var
data
=
[];
if
(
!
res
.
data
.
results
)
{
return
{
data
:
data
};
}
_
.
forEach
(
res
.
data
.
results
,
queryRes
=>
{
for
(
let
key
in
res
.
data
.
results
)
{
let
queryRes
=
res
.
data
.
results
[
key
];
if
(
queryRes
.
series
)
{
for
(
let
series
of
queryRes
.
series
)
{
data
.
push
({
target
:
series
.
name
,
...
...
@@ -54,10 +60,19 @@ export class MysqlDatasource {
meta
:
queryRes
.
meta
,
});
}
});
}
if
(
queryRes
.
tables
)
{
for
(
let
table
of
queryRes
.
tables
)
{
table
.
type
=
'table'
;
table
.
refId
=
queryRes
.
refId
;
table
.
meta
=
queryRes
.
meta
;
data
.
push
(
table
);
}
}
}
return
{
data
:
data
};
});
}
}
public/app/plugins/datasource/mysql/module.ts
View file @
97e2d75f
...
...
@@ -27,7 +27,7 @@ class MysqlQueryCtrl extends QueryCtrl {
constructor
(
$scope
,
$injector
)
{
super
(
$scope
,
$injector
);
this
.
target
.
format
=
'time_series'
;
this
.
target
.
format
=
this
.
target
.
format
||
'time_series'
;
this
.
target
.
alias
=
""
;
this
.
formats
=
[
{
text
:
'Time series'
,
value
:
'time_series'
},
...
...
public/app/plugins/datasource/mysql/partials/query.editor.html
View file @
97e2d75f
...
...
@@ -16,14 +16,7 @@
<label
class=
"gf-form-label query-keyword"
>
Name by
</label>
<input
type=
"text"
class=
"gf-form-input"
ng-model=
"ctrl.target.alias"
spellcheck=
'false'
placeholder=
"pattern"
ng-blur=
"ctrl.refresh()"
>
</div>
<div
class=
"gf-form gf-form--grow"
>
<div
class=
"gf-form-label gf-form-label--grow"
></div>
</div>
</div>
<div
class=
"gf-form-inline"
ng-show=
"ctrl.lastQueryMeta"
>
<div
class=
"gf-form"
>
<div
class=
"gf-form"
ng-show=
"ctrl.lastQueryMeta"
>
<label
class=
"gf-form-label query-keyword"
ng-click=
"ctrl.showLastQuerySQL = !ctrl.showLastQuerySQL"
>
Generated SQL
<i
class=
"fa fa-caret-down"
ng-show=
"ctrl.showLastQuerySQL"
></i>
...
...
vendor/github.com/go-sql-driver/mysql/row_columntypes.go
0 → 100644
View file @
97e2d75f
package
mysql
const
(
// In case we get something unexpected
FieldTypeUnknown
=
"UNKNOWN"
// Human-readable names for each distinct type byte
FieldTypeNameDecimal
=
"DECIMAL"
FieldTypeNameTiny
=
"TINY"
FieldTypeNameShort
=
"SHORT"
FieldTypeNameLong
=
"LONG"
FieldTypeNameFloat
=
"FLOAT"
FieldTypeNameDouble
=
"DOUBLE"
FieldTypeNameNULL
=
"NULL"
FieldTypeNameTimestamp
=
"TIMESTAMP"
FieldTypeNameLongLong
=
"LONGLONG"
FieldTypeNameInt24
=
"INT24"
FieldTypeNameDate
=
"DATE"
FieldTypeNameTime
=
"TIME"
FieldTypeNameDateTime
=
"DATETIME"
FieldTypeNameYear
=
"YEAR"
FieldTypeNameNewDate
=
"NEWDATE"
FieldTypeNameVarChar
=
"VARCHAR"
FieldTypeNameBit
=
"BIT"
FieldTypeNameJSON
=
"JSON"
FieldTypeNameNewDecimal
=
"NEWDECIMAL"
FieldTypeNameEnum
=
"ENUM"
FieldTypeNameSet
=
"SET"
FieldTypeNameTinyBLOB
=
"TINYBLOB"
FieldTypeNameMediumBLOB
=
"MEDIUMBLOB"
FieldTypeNameLongBLOB
=
"LONGBLOB"
FieldTypeNameBLOB
=
"BLOB"
FieldTypeNameVarString
=
"VARSTRING"
FieldTypeNameString
=
"STRING"
FieldTypeNameGeometry
=
"GEOMETRY"
)
// mapping from each type identifier to human readable string
var
mysqlTypeMap
=
map
[
byte
]
string
{
fieldTypeDecimal
:
FieldTypeNameDecimal
,
fieldTypeTiny
:
FieldTypeNameTiny
,
fieldTypeShort
:
FieldTypeNameShort
,
fieldTypeLong
:
FieldTypeNameLong
,
fieldTypeFloat
:
FieldTypeNameFloat
,
fieldTypeDouble
:
FieldTypeNameDouble
,
fieldTypeNULL
:
FieldTypeNameNULL
,
fieldTypeTimestamp
:
FieldTypeNameTimestamp
,
fieldTypeLongLong
:
FieldTypeNameLongLong
,
fieldTypeInt24
:
FieldTypeNameInt24
,
fieldTypeDate
:
FieldTypeNameDate
,
fieldTypeTime
:
FieldTypeNameTime
,
fieldTypeDateTime
:
FieldTypeNameDateTime
,
fieldTypeYear
:
FieldTypeNameYear
,
fieldTypeNewDate
:
FieldTypeNameNewDate
,
fieldTypeVarChar
:
FieldTypeNameVarChar
,
fieldTypeBit
:
FieldTypeNameBit
,
fieldTypeJSON
:
FieldTypeNameJSON
,
fieldTypeNewDecimal
:
FieldTypeNameNewDecimal
,
fieldTypeEnum
:
FieldTypeNameEnum
,
fieldTypeSet
:
FieldTypeNameSet
,
fieldTypeTinyBLOB
:
FieldTypeNameTinyBLOB
,
fieldTypeMediumBLOB
:
FieldTypeNameMediumBLOB
,
fieldTypeLongBLOB
:
FieldTypeNameLongBLOB
,
fieldTypeBLOB
:
FieldTypeNameBLOB
,
fieldTypeVarString
:
FieldTypeNameVarString
,
fieldTypeString
:
FieldTypeNameString
,
fieldTypeGeometry
:
FieldTypeNameGeometry
,
}
// Make Rows implement the optional RowsColumnTypeDatabaseTypeName interface.
// See https://github.com/golang/go/commit/2a85578b0ecd424e95b29d810b7a414a299fd6a7
// - (go 1.8 required for this to have any effect)
func
(
rows
*
mysqlRows
)
ColumnTypeDatabaseTypeName
(
index
int
)
string
{
if
typeName
,
ok
:=
mysqlTypeMap
[
rows
.
rs
.
columns
[
index
]
.
fieldType
];
ok
{
return
typeName
}
return
FieldTypeUnknown
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment