Mysql: Returned values are always []byte

Created on 18 Jan 2016  路  10Comments  路  Source: go-sql-driver/mysql

The function below is to map db rows to json, but mysql driver always returns values as []byte

func getJSON(sqlString string) (string, error) {
  rows, err := db.Query(sqlString)
  if err != nil {
      return "", err
  }
  defer rows.Close()
  columns, err := rows.Columns()
  if err != nil {
      return "", err
  }
  count := len(columns)
  tableData := make([]map[string]interface{}, 0)
  values := make([]interface{}, count)
  valuePtrs := make([]interface{}, count)
  for rows.Next() {
      for i := 0; i < count; i++ {
          valuePtrs[i] = &values[i]
      }
      rows.Scan(valuePtrs...)
      entry := make(map[string]interface{})
      for i, col := range columns {
          var v interface{}
          val := values[i]
          b, ok := val.([]byte)
          if ok {
              v = string(b)
          } else {
              v = val
          }
          entry[col] = v
      }
      tableData = append(tableData, entry)
  }
  jsonData, err := json.Marshal(tableData)
  if err != nil {
      return "", err
  }
  fmt.Println(string(jsonData))
  return string(jsonData), nil 
}

Most helpful comment

That's a specialty of MySQL: you have to use prepared statements to get the native types. MySQL has two protocols, one transmits everything as text, the other as the "real" type. And that binary protocol is only used when you use prepared statements. The driver is pretty much powerless to enforce a protocol and the text protocol takes less resources on the server.

This may help you:

stmt, err := db.Prepare(sqlString)
if err != nil { ...... }
defer stmt.Close()
rows, err := stmt.Query()

All 10 comments

What would you expect it to return? Does your code fail? If so, how?

@arnehormann I expect that driver should return integer as int not slice of bytes. Code works fine, but here is the result:

b, ok := val.([]byte)
if ok {
  v = string(b)
} else {
  v = val
}

values are always represented as strings.

That's a specialty of MySQL: you have to use prepared statements to get the native types. MySQL has two protocols, one transmits everything as text, the other as the "real" type. And that binary protocol is only used when you use prepared statements. The driver is pretty much powerless to enforce a protocol and the text protocol takes less resources on the server.

This may help you:

stmt, err := db.Prepare(sqlString)
if err != nil { ...... }
defer stmt.Close()
rows, err := stmt.Query()

Don't scan into interface{} but the type you would expect, the database/sql package converts the returned type for you then.

See also #366

@arnehormann That works! Thanks a lot!

@arnehormann i tried your method, i can get 'int' type ,but i can't get 'float' type, what did i wrong?

and what about boolean types ? any suggestion ?

Does not work yet :(

@arnehormann i tried your method, i can get 'int' type ,but i can't get 'float' type, what did i wrong?

same question

Very low level knowledge is needed to understand what type is used in binary protocol.
You should not expect you can always get type you expect by binary type.

The right approach is:

Don't scan into interface{} but the type you would expect, the database/sql package converts the returned type for you then.

Was this page helpful?
0 / 5 - 0 ratings