Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scan receives unexpected type []uint8 using mysql driver #925

Closed
nkovacs opened this issue Mar 25, 2016 · 3 comments
Closed

Scan receives unexpected type []uint8 using mysql driver #925

nkovacs opened this issue Mar 25, 2016 · 3 comments

Comments

@nkovacs
Copy link
Contributor

nkovacs commented Mar 25, 2016

I've created a custom type that implements sql.Scanner.

The documentation of this interface claims that Scan will receive one of the following types:

  • int64
  • float64
  • bool
  • []byte
  • string
  • time.Time
  • nil - for NULL values

It receives a []uint8 with the value [52 50] instead, which is actually the string "42".
If I use the standard library's Scan function, Foo.Scan receives an int64.

package main

import "fmt"
import _ "github.com/go-sql-driver/mysql"
import "github.com/jinzhu/gorm"

type Foo int

// Scan implements the database/sql.Scanner interface
func (f *Foo) Scan(value interface{}) error {
        switch value := value.(type) {
        case int64:
                *f = Foo(value)
        default:
                return fmt.Errorf("Invalid database type: %T %v", value, value)
        }
        return nil
}

type FooModel struct {
        Foo Foo
}

func main() {
        db, err := gorm.Open("mysql", "user:pass@/testdb")
        if err != nil {
                panic(err)
        }

        db.AutoMigrate(FooModel{})

        db.Create(&FooModel{Foo: Foo(42)})

        var fooModel FooModel
        db.Debug().First(&fooModel)
        fmt.Println(fooModel)

        stmtOut, err := db.DB().Prepare("SELECT foo FROM foo_models LIMIT 1")
        if err != nil {
                panic(err)
        }
        defer stmtOut.Close()

        var foo Foo
        err = stmtOut.QueryRow().Scan(&foo)
        if err != nil {
                panic(err)
        }

        fmt.Println(foo)
}
@jinzhu
Copy link
Member

jinzhu commented Mar 28, 2016

use parseTime=true when connect the database https://github.com/go-sql-driver/mysql#parsetime

@jinzhu jinzhu closed this as completed Mar 28, 2016
@nkovacs
Copy link
Contributor Author

nkovacs commented Mar 28, 2016

This isn't a time value.

@nkovacs
Copy link
Contributor Author

nkovacs commented Mar 28, 2016

Turns out this is a bug in the mysql driver.

The difference is caused by me using a prepared statement, while gorm does not.
Gorm's code runs into mysqlConn.Query: https://github.com/go-sql-driver/mysql/blob/72ea5d0b32a04c67710bf63e97095d82aea5f352/connection.go#L305
That creates a textRows type, which returns strings for everything.
With the prepared statement, it executes mysqlStmt.Query: https://github.com/go-sql-driver/mysql/blob/b4db83c6faa0dc87d33f0bd7cdc81c7078594278/statement.go#L84
That creates a binaryRows type, which correctly returns an int.

So that's why I thought it was a bug in gorm, but I've tried it with db.DB().QueryRow now, it's incorrect.

Edit: bug report is here: go-sql-driver/mysql#441

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants