Insert typed []byte with gorm in mysql raises "Error 1241: Operand should contain 1 columns(s)"

Viewed 798

I have a model with typed []byte (password-hash), which I want to save in MySQL:5.7 using gorm:v2.

// this will work
type ModelRaw struct {
    Bytes   []byte
}

type Hash []byte

// this will NOT work
type ModelTyped struct {
    Bytes Hash
}

func main() {
    // Migrate database
    // Both tables will have a column `bytes` of type `longblob default:NULL`
    if err := gormDB.AutoMigrate(&ModelRaw{}, &ModelTyped{}); err != nil {
        panic(err)
    }

    // this works
    mdl1 := &ModelRaw{Bytes: []byte("random-bytes")}
    if err := gormDB.Debug().Create(mdl1).Error; err != nil {
        panic(err)
    }

    // error here
    mdl2 := &ModelTyped{Bytes: Hash("random-bytes")}
    if err := gormDB.Debug().Create(mdl2).Error; err != nil {
        panic(err)
    }
}

The above code results in the following gorm debug output:

2020/11/06 10:31:29 /go/src/app/main.go:47
[7.715ms] [rows:1] INSERT INTO `model_raws` (`bytes`) VALUES ('random-bytes')

2020/11/06 10:31:29 /go/src/app/main.go:53 Error 1241: Operand should contain 1 column(s)
[0.926ms] [rows:0] INSERT INTO `model_typeds` (`bytes`) VALUES ((114,97,110,100,111,109,45,98,121,116,101,115))
panic: Error 1241: Operand should contain 1 column(s)

Repo demonstrating the problem: https://github.com/Iyashi/go-gorm-bytes-test

It worked in gorm:v1 and broke in gorm:v2.

gorm's AutoMigrate() creates mysql table column as longblob NULL.

2 Answers

For this to work, you should just implement a driver.Valuer interface:

func (h Hash) Value() (driver.Value, error) {
  return []byte(h), nil
}

Then your typed data will work with Gorm v2 as expected.

The value being used must be a byte array, not an array of numbers.

One would think that Bytes []byte would be equivalent to type Hash []byte plus Bytes Hash, but apparently not.

Give this a try:

mdl2 := &ModelTyped{Bytes: []byte(Hash("random-bytes"))}

Or maybe

mdl2 := &ModelTyped{Bytes: []byte{Hash("random-bytes")}}

Another possibility is to get rid of struct in the definition of Hash; it seems to be causing an extra level of "structuring" in the effect.

Related