当sql.DB.Exec时,对SQL中的自定义类型感到困惑

时间:2015-05-16 15:12:43

标签: mysql sql types go custom-type

拥有此表结构:

CREATE TABLE `tableName` (
    `Id` int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `Status` enum('pending','rejected','sent','invalid') NOT NULL,
    `Body` varchar(255) NULL
) ENGINE='MyISAM' COLLATE 'utf8_general_ci';

我有这个(不完整)代码正常工作

type StatusEnum string

const (
    STATUS_PENDING  StatusEnum = "pending"
    STATUS_REJECTED StatusEnum = "rejected"
    STATUS_SENT     StatusEnum = "sent"
    STATUS_INVALID  StatusEnum = "invalid"
)

func (s *StatusEnum) Scan(src interface{}) error {
    if src == nil {
        return errors.New("This field cannot be NULL")
    }

    if stringStatus, ok := src.([]byte); ok {
        *s = StatusEnum(string(stringStatus[:]))

        return nil
    }

    return errors.New("Cannot convert enum to string")
}

func (s *StatusEnum) Value() (driver.Value, error) {
    return []byte(*s), nil
}

type EmailQueue struct {
    Id        uint64
    Status    StatusEnum
    Body      sql.NullString
}

func Save (db *sql.DB) error {
    _, err = db.Exec(
        "UPDATE `tableName` SET `Status` = ?, `Body` = ? WHERE `id` = ?",
        &eqi.Status,
        eqi.Body,
        eqi.Id,
    )

    return err
}

所以我的问题是:为什么我需要在&eqi.Status上使用指针引用(db.Exec)?

sql.NullString和我的自定义StatusEnum都没有在github.com/go-sql-driver/mysql中实现,为什么会有区别?

如果我不使用指针引用(eqi.Status),我收到此错误(抛出database/sql/convert.go):

sql: converting Exec argument #0's type: unsupported type emailqueue.StatusEnum, a string

我试图实现其他一些我发现没有运气的接口。

我使用sql.Scannersql.driver.Valuer接口实现了其他自定义类型,但问题是相同的。

我猜测struct并输入继承差异,但我无法得到任何暗示...... :(

请帮助了解发生了什么。谢谢!!! :)

1 个答案:

答案 0 :(得分:4)

您对StatusEnum类型的Valuer interface实施操作*StatusEnum。因此,当您将一个参数作为参数传递给Exec时,它仅作为指针才有意义,因为它只指向StatusEnum实现Value()的指针,需要内联参与。

您没有EmailList类型的定义,因此我可以建议您更改给定的Valuer界面。

func (s StatusEnum) Value() (driver.Value, error) {
    return []byte(s), nil
}

这是标准库implements自定义可空类型。