Golang: Database: database/sql: uint64 Support

28th December 2021 at 3:35pm

database/sql

database/sql 标准本身 不支持 uint64。rsc 的看法([1], [2])是:

  • 有部分数据库不支持 uint64(比如 SQLite)
  • database/sql 的 Value 体系中,使用一个 int64 类型来表达所有的数据库整型值;这样使得 Driver 的实现简单,只需要处理一个 int 类型(而不需要对 int8,int16 等一起处理)
  • 如果 MySQL 的 driver 需要支持 uint64,它仍然可以自行支持,不需要改动 database/sql 的代码

有 proposal 期望 Go 2 的 ColumnType 中可以 加入 signedness 信息,但是被拒绝了。

MySQL Driver

go-sql-driver/mysql 在 2015 年已经 实现了对 uint64 的支持。你可以:

  • 把 DB 的值 Scan 到一个 uint64 对象中
  • 写 DB 时(Exec)使用 uint64 对象作为写入参数

GORM

GORM(v1.22.4)也实现了对 BIGINT UNSIGNED 列的(非完美)支持(当然是在 go-sql-driver/mysql 的基础上)。GORM 可以把数据保存到:

  • 某个 struct value 中:此时只要 BIGINT UNSIGNED 列对应的 field 是 uint64 类型,可以正常读进去
  • 某个 map[string]interface{};如果:
    • 当该列是可以为 null 且值大于 int64 范围时,GORM 会报错;这个问题可以用我维护的 fork 解决
    • 否则能正确地读到 uint64

老版本问题

老版本(v1.21.15)GORM 的支持更差些。比如 db.ScanRows() 处理不了大于 int64 范围的整数:

converting driver.Value type []uint8 ("9223372036854775809") to a int64: value out of range

但是 db.Find() 却可以。后面作者 fix 了这个问题。