2015-05-16 8 views
6

diese Tabelle Struktur:Verwirrt über benutzerdefinierte Typen in SQL, wenn sql.DB.Exec

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

Ich habe dies (nicht vollständig) Code fein Arbeits: meine Frage

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 ist: Warum muss ich die Zeigerreferenz (&eqi.Status) auf db.Exec verwenden?

Beide sql.NullString und meine Gewohnheit StatusEnum nicht in github.com/go-sql-driver/mysql implementiert, warum also der Unterschied?

Wenn ich den Zeigerverweis nicht (eqi.Status), erhalte ich diesen Fehler (wirft in database/sql/convert.go):

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

Ich habe versucht, einige andere Schnittstellen zu implementieren ich nicht gefunden habe Glück.

Ich habe andere benutzerdefinierte Typen mit sql.Scanner und sql.driver.Valuer Schnittstellen implementiert, aber das Problem ist das gleiche.

ich raten, über struct und Typ Vererbung Differenzierung, aber ich konnte jeden Hinweis auf, dass nicht bekommen ... :(

Bitte helfen zu verstehen, was vor sich geht. Dank !!! :)

Antwort

4

Sie implementieren die Valuer interface für Ihren StatusEnum Typ als Betrieb an einem *StatusEnum. Wenn Sie also einen als Parameter an Exec übergeben, ist es nur als Zeiger sinnvoll, nur Zeiger auf StatusEnum implementieren Value(), erfordern eine Inline-Referenz.

Sie haben keine Definition für den Typ EmailList, daher kann ich eine Änderung an Ihrer gegebenen Valuer Schnittstelle vorschlagen.

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

Dies ist die Standardbibliothek implements benutzerdefinierte nullfähige Typen.

+0

Entschuldigung, ich habe den Code repariert '' 'EmailList''' mit' '' StatusEnum''' ersetzt. Dies ist jedoch verwirrender, weil dieser Code einfach perfekt funktioniert: '' 'v, err: = eqi.Status.Value() \t v, err = (& eqi.Status) .Wert()' '' –

+0

Für alle, die reinkommen und das Lesen, weil Sie eine Pointer-Methode auf einen Nicht-Pointer-Wert aufrufen können und automatisch die Adresse übernimmt, aber nur, wenn es sich um eine Nicht-Interface-Methode handelt, dh die Variable ist eine Schnittstelle. https://golang.org/ref/spec#Method_values –