diff --git a/cid.go b/cid.go index 9f8c87d8..21d6fb80 100644 --- a/cid.go +++ b/cid.go @@ -1,11 +1,7 @@ package pgtype import ( - "fmt" "io" - "strconv" - - "github.com/jackc/pgx/pgio" ) // CID is PostgreSQL's Command Identifier type. @@ -19,123 +15,33 @@ import ( // It is currently implemented as an unsigned four byte integer. // Its definition can be found in src/include/c.h as CommandId // in the PostgreSQL sources. -type CID struct { - Uint uint32 - Status Status -} +type CID pguint32 // ConvertFrom converts from src to dst. Note that as CID is not a general // number type ConvertFrom does not do automatic type conversion as other number // types do. func (dst *CID) ConvertFrom(src interface{}) error { - switch value := src.(type) { - case CID: - *dst = value - case uint32: - *dst = CID{Uint: value, Status: Present} - default: - return fmt.Errorf("cannot convert %v to CID", value) - } - - return nil + return (*pguint32)(dst).ConvertFrom(src) } // AssignTo assigns from src to dst. Note that as CID is not a general number // type AssignTo does not do automatic type conversion as other number types do. func (src *CID) AssignTo(dst interface{}) error { - switch v := dst.(type) { - case *uint32: - if src.Status == Present { - *v = src.Uint - } else { - return fmt.Errorf("cannot assign %v into %T", src, dst) - } - case **uint32: - if src.Status == Present { - n := src.Uint - *v = &n - } else { - *v = nil - } - } - - return nil + return (*pguint32)(src).AssignTo(dst) } func (dst *CID) DecodeText(r io.Reader) error { - size, err := pgio.ReadInt32(r) - if err != nil { - return err - } - - if size == -1 { - *dst = CID{Status: Null} - return nil - } - - buf := make([]byte, int(size)) - _, err = r.Read(buf) - if err != nil { - return err - } - - n, err := strconv.ParseUint(string(buf), 10, 32) - if err != nil { - return err - } - - *dst = CID{Uint: uint32(n), Status: Present} - return nil + return (*pguint32)(dst).DecodeText(r) } func (dst *CID) DecodeBinary(r io.Reader) error { - size, err := pgio.ReadInt32(r) - if err != nil { - return err - } - - if size == -1 { - *dst = CID{Status: Null} - return nil - } - - if size != 4 { - return fmt.Errorf("invalid length for cid: %v", size) - } - - n, err := pgio.ReadUint32(r) - if err != nil { - return err - } - - *dst = CID{Uint: n, Status: Present} - return nil + return (*pguint32)(dst).DecodeBinary(r) } func (src CID) EncodeText(w io.Writer) error { - if done, err := encodeNotPresent(w, src.Status); done { - return err - } - - s := strconv.FormatUint(uint64(src.Uint), 10) - _, err := pgio.WriteInt32(w, int32(len(s))) - if err != nil { - return nil - } - _, err = w.Write([]byte(s)) - return err + return (pguint32)(src).EncodeText(w) } func (src CID) EncodeBinary(w io.Writer) error { - if done, err := encodeNotPresent(w, src.Status); done { - return err - } - - _, err := pgio.WriteInt32(w, 4) - if err != nil { - return err - } - - _, err = pgio.WriteUint32(w, src.Uint) - return err + return (pguint32)(src).EncodeBinary(w) } diff --git a/pguint32.go b/pguint32.go new file mode 100644 index 00000000..66b385fb --- /dev/null +++ b/pguint32.go @@ -0,0 +1,130 @@ +package pgtype + +import ( + "fmt" + "io" + "strconv" + + "github.com/jackc/pgx/pgio" +) + +// pguint32 is the core type that is used to implement PostgreSQL types such as +// CID and XID. +type pguint32 struct { + Uint uint32 + Status Status +} + +// ConvertFrom converts from src to dst. Note that as pguint32 is not a general +// number type ConvertFrom does not do automatic type conversion as other number +// types do. +func (dst *pguint32) ConvertFrom(src interface{}) error { + switch value := src.(type) { + case uint32: + *dst = pguint32{Uint: value, Status: Present} + default: + return fmt.Errorf("cannot convert %v to pguint32", value) + } + + return nil +} + +// AssignTo assigns from src to dst. Note that as pguint32 is not a general number +// type AssignTo does not do automatic type conversion as other number types do. +func (src *pguint32) AssignTo(dst interface{}) error { + switch v := dst.(type) { + case *uint32: + if src.Status == Present { + *v = src.Uint + } else { + return fmt.Errorf("cannot assign %v into %T", src, dst) + } + case **uint32: + if src.Status == Present { + n := src.Uint + *v = &n + } else { + *v = nil + } + } + + return nil +} + +func (dst *pguint32) DecodeText(r io.Reader) error { + size, err := pgio.ReadInt32(r) + if err != nil { + return err + } + + if size == -1 { + *dst = pguint32{Status: Null} + return nil + } + + buf := make([]byte, int(size)) + _, err = r.Read(buf) + if err != nil { + return err + } + + n, err := strconv.ParseUint(string(buf), 10, 32) + if err != nil { + return err + } + + *dst = pguint32{Uint: uint32(n), Status: Present} + return nil +} + +func (dst *pguint32) DecodeBinary(r io.Reader) error { + size, err := pgio.ReadInt32(r) + if err != nil { + return err + } + + if size == -1 { + *dst = pguint32{Status: Null} + return nil + } + + if size != 4 { + return fmt.Errorf("invalid length for cid: %v", size) + } + + n, err := pgio.ReadUint32(r) + if err != nil { + return err + } + + *dst = pguint32{Uint: n, Status: Present} + return nil +} + +func (src pguint32) EncodeText(w io.Writer) error { + if done, err := encodeNotPresent(w, src.Status); done { + return err + } + + s := strconv.FormatUint(uint64(src.Uint), 10) + _, err := pgio.WriteInt32(w, int32(len(s))) + if err != nil { + return nil + } + _, err = w.Write([]byte(s)) + return err +} + +func (src pguint32) EncodeBinary(w io.Writer) error { + if done, err := encodeNotPresent(w, src.Status); done { + return err + } + + _, err := pgio.WriteInt32(w, 4) + if err != nil { + return err + } + + _, err = pgio.WriteUint32(w, src.Uint) + return err +} diff --git a/xid.go b/xid.go index f4d087a5..b311cbfb 100644 --- a/xid.go +++ b/xid.go @@ -18,28 +18,33 @@ import ( // It is currently implemented as an unsigned four byte integer. // Its definition can be found in src/include/postgres_ext.h as TransactionId // in the PostgreSQL sources. -type XID CID +type XID pguint32 +// ConvertFrom converts from src to dst. Note that as XID is not a general +// number type ConvertFrom does not do automatic type conversion as other number +// types do. func (dst *XID) ConvertFrom(src interface{}) error { - return (*CID)(dst).ConvertFrom(src) + return (*pguint32)(dst).ConvertFrom(src) } +// AssignTo assigns from src to dst. Note that as XID is not a general number +// type AssignTo does not do automatic type conversion as other number types do. func (src *XID) AssignTo(dst interface{}) error { - return (*CID)(src).AssignTo(dst) + return (*pguint32)(src).AssignTo(dst) } func (dst *XID) DecodeText(r io.Reader) error { - return (*CID)(dst).DecodeText(r) + return (*pguint32)(dst).DecodeText(r) } func (dst *XID) DecodeBinary(r io.Reader) error { - return (*CID)(dst).DecodeBinary(r) + return (*pguint32)(dst).DecodeBinary(r) } func (src XID) EncodeText(w io.Writer) error { - return (CID)(src).EncodeText(w) + return (pguint32)(src).EncodeText(w) } func (src XID) EncodeBinary(w io.Writer) error { - return (CID)(src).EncodeBinary(w) + return (pguint32)(src).EncodeBinary(w) }