Confuses user types in SQL when sql.DB.Exec

The presence of this table structure:

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'; 

This (not complete) code works fine for me:

 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 } 

So my question is: Why do I need to use a pointer link ( &eqi.Status ) to db.Exec ?

Both sql.NullString and my custom StatusEnum not implemented in github.com/go-sql-driver/mysql , so why the difference?

If I do not use a pointer reference ( eqi.Status ), I get this error (throwing database / sql / convert.go ):

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

I tried to implement some other interfaces that I found with no luck.

I have other custom types implemented with sql.Scanner and sql.driver.Valuer , but the problem is the same.

I assumed about struct and inherit differentiation of inheritance, but I could not understand that ... :(

Please help to understand what is happening. Thank you !!! :)

+6
source share
1 answer

You will implement the Valuer interface for your StatusEnum type as running on *StatusEnum . Therefore, when you pass one of the parameters to Exec, it only makes sense as a pointer, since only pointers to the StatusEnum implement Value() , requiring a built-in binding.

You do not have a definition for the EmailList type, so I can suggest modifying your specified Valuer interface.

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

This standard library implements custom types with a null value.

+4
source

Source: https://habr.com/ru/post/987340/


All Articles