mysql.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package mysql
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. "github.com/go-sql-driver/mysql"
  8. "github.com/go-xorm/core"
  9. "github.com/grafana/grafana/pkg/log"
  10. "github.com/grafana/grafana/pkg/models"
  11. "github.com/grafana/grafana/pkg/tsdb"
  12. )
  13. func init() {
  14. tsdb.RegisterTsdbQueryEndpoint("mysql", newMysqlQueryEndpoint)
  15. }
  16. func newMysqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
  17. logger := log.New("tsdb.mysql")
  18. cnnstr := fmt.Sprintf("%s:%s@%s(%s)/%s?collation=utf8mb4_unicode_ci&parseTime=true&loc=UTC&allowNativePasswords=true",
  19. datasource.User,
  20. datasource.Password,
  21. "tcp",
  22. datasource.Url,
  23. datasource.Database,
  24. )
  25. logger.Debug("getEngine", "connection", cnnstr)
  26. config := tsdb.SqlQueryEndpointConfiguration{
  27. DriverName: "mysql",
  28. ConnectionString: cnnstr,
  29. Datasource: datasource,
  30. TimeColumnNames: []string{"time", "time_sec"},
  31. MetricColumnTypes: []string{"CHAR", "VARCHAR", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"},
  32. }
  33. rowTransformer := mysqlRowTransformer{
  34. log: logger,
  35. }
  36. return tsdb.NewSqlQueryEndpoint(&config, &rowTransformer, newMysqlMacroEngine(), logger)
  37. }
  38. type mysqlRowTransformer struct {
  39. log log.Logger
  40. }
  41. func (t *mysqlRowTransformer) Transform(columnTypes []*sql.ColumnType, rows *core.Rows) (tsdb.RowValues, error) {
  42. values := make([]interface{}, len(columnTypes))
  43. for i := range values {
  44. scanType := columnTypes[i].ScanType()
  45. values[i] = reflect.New(scanType).Interface()
  46. if columnTypes[i].DatabaseTypeName() == "BIT" {
  47. values[i] = new([]byte)
  48. }
  49. }
  50. if err := rows.Scan(values...); err != nil {
  51. return nil, err
  52. }
  53. for i := 0; i < len(columnTypes); i++ {
  54. typeName := reflect.ValueOf(values[i]).Type().String()
  55. switch typeName {
  56. case "*sql.RawBytes":
  57. values[i] = string(*values[i].(*sql.RawBytes))
  58. case "*mysql.NullTime":
  59. sqlTime := (*values[i].(*mysql.NullTime))
  60. if sqlTime.Valid {
  61. values[i] = sqlTime.Time
  62. } else {
  63. values[i] = nil
  64. }
  65. case "*sql.NullInt64":
  66. nullInt64 := (*values[i].(*sql.NullInt64))
  67. if nullInt64.Valid {
  68. values[i] = nullInt64.Int64
  69. } else {
  70. values[i] = nil
  71. }
  72. case "*sql.NullFloat64":
  73. nullFloat64 := (*values[i].(*sql.NullFloat64))
  74. if nullFloat64.Valid {
  75. values[i] = nullFloat64.Float64
  76. } else {
  77. values[i] = nil
  78. }
  79. }
  80. if columnTypes[i].DatabaseTypeName() == "DECIMAL" {
  81. f, err := strconv.ParseFloat(values[i].(string), 64)
  82. if err == nil {
  83. values[i] = f
  84. } else {
  85. values[i] = nil
  86. }
  87. }
  88. }
  89. return values, nil
  90. }