You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jul 12, 2025. It is now read-only.
I have a question about custom types registration. Can you please help me?
I use PostgreSQL with 64-bit XID patch. So this means that the regular pgtype.XID is no longer suitable because it is based on pguint32. I wrote custom pguint64 and XID64 types:
pguint64.go
package types
import (
"database/sql/driver""encoding/binary""errors""fmt""strconv""github.com/jackc/pgio""github.com/jackc/pgtype"
)
// pguint64 is the core type that is used to implement PostgrePro type such as XID.typepguint64struct {
Uintuint64Status pgtype.Status
}
// Set converts from src to dst. Note that as pguint64 is not a general// number type Set does not do automatic type conversion as other number// types do.func (dst*pguint64) Set(srcinterface{}) error {
switchvalue:=src.(type) {
caseint64:
ifvalue<0 {
returnfmt.Errorf("%d is less than minimum value for pguint64", value)
}
*dst=pguint64{Uint: uint64(value), Status: pgtype.Present}
caseuint64:
*dst=pguint64{Uint: value, Status: pgtype.Present}
default:
returnfmt.Errorf("cannot convert %v to pguint64", value)
}
returnnil
}
func (dstpguint64) Get() interface{} {
switchdst.Status {
casepgtype.Present:
returndst.Uintcasepgtype.Null:
returnnildefault:
returndst.Status
}
}
// AssignTo assigns from src to dst. Note that as pguint64 is not a general number// type AssignTo does not do automatic type conversion as other number types do.func (src*pguint64) AssignTo(dstinterface{}) error {
switchv:=dst.(type) {
case*uint64:
ifsrc.Status==pgtype.Present {
*v=src.Uint
} else {
returnfmt.Errorf("cannot assign %v into %T", src, dst)
}
case**uint64:
ifsrc.Status==pgtype.Present {
n:=src.Uint*v=&n
} else {
*v=nil
}
}
returnnil
}
func (dst*pguint64) DecodeText(ci*pgtype.ConnInfo, src []byte) error {
ifsrc==nil {
*dst=pguint64{Status: pgtype.Null}
returnnil
}
n, err:=strconv.ParseUint(string(src), 10, 64)
iferr!=nil {
returnerr
}
*dst=pguint64{Uint: n, Status: pgtype.Present}
returnnil
}
func (dst*pguint64) DecodeBinary(ci*pgtype.ConnInfo, src []byte) error {
ifsrc==nil {
*dst=pguint64{Status: pgtype.Null}
returnnil
}
iflen(src) !=8 {
returnfmt.Errorf("invalid length: %v", len(src))
}
n:=binary.BigEndian.Uint64(src)
*dst=pguint64{Uint: n, Status: pgtype.Present}
returnnil
}
func (srcpguint64) EncodeText(ci*pgtype.ConnInfo, buf []byte) ([]byte, error) {
switchsrc.Status {
casepgtype.Null:
returnnil, nilcasepgtype.Undefined:
returnnil, errors.New("cannot encode status undefined")
}
returnappend(buf, strconv.FormatUint(src.Uint, 10)...), nil
}
func (srcpguint64) EncodeBinary(ci*pgtype.ConnInfo, buf []byte) ([]byte, error) {
switchsrc.Status {
casepgtype.Null:
returnnil, nilcasepgtype.Undefined:
returnnil, errors.New("cannot encode status undefined")
}
returnpgio.AppendUint64(buf, src.Uint), nil
}
// Scan implements the database/sql Scanner interface.func (dst*pguint64) Scan(srcinterface{}) error {
ifsrc==nil {
*dst=pguint64{Status: pgtype.Null}
returnnil
}
switchsrc:=src.(type) {
caseuint64:
*dst=pguint64{Uint: src, Status: pgtype.Present}
returnnilcaseint64:
*dst=pguint64{Uint: uint64(src), Status: pgtype.Present}
returnnilcasestring:
returndst.DecodeText(nil, []byte(src))
case []byte:
srcCopy:=make([]byte, len(src))
copy(srcCopy, src)
returndst.DecodeText(nil, srcCopy)
}
returnfmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.func (srcpguint64) Value() (driver.Value, error) {
switchsrc.Status {
casepgtype.Present:
returnsrc.Uint, nilcasepgtype.Null:
returnnil, nildefault:
returnnil, errors.New("cannot encode status undefined")
}
}
xid64.go
package types
import (
"database/sql/driver""github.com/jackc/pgtype"
)
// XID is PostgresPro's Transaction ID type.//// In later versions of PostgresPro, it is the type used for the backend_xid// and backend_xmin columns of the pg_stat_activity system view.//// Also, when one does//// select xmin, xmax, * from some_table;//// it is the data type of the xmin and xmax hidden system columns.//// It is currently implemented as an unsigned eight byte integer.typeXID64pguint64// Set converts from src to dst. Note that as XID64 is not a general// number type Set does not do automatic type conversion as other number// types do.func (dst*XID64) Set(srcinterface{}) error {
return (*pguint64)(dst).Set(src)
}
func (dstXID64) Get() interface{} {
return (pguint64)(dst).Get()
}
// AssignTo assigns from src to dst. Note that as XID64 is not a general number// type AssignTo does not do automatic type conversion as other number types do.func (src*XID64) AssignTo(dstinterface{}) error {
return (*pguint64)(src).AssignTo(dst)
}
func (dst*XID64) DecodeText(ci*pgtype.ConnInfo, src []byte) error {
return (*pguint64)(dst).DecodeText(ci, src)
}
func (dst*XID64) DecodeBinary(ci*pgtype.ConnInfo, src []byte) error {
return (*pguint64)(dst).DecodeBinary(ci, src)
}
func (srcXID64) EncodeText(ci*pgtype.ConnInfo, buf []byte) ([]byte, error) {
return (pguint64)(src).EncodeText(ci, buf)
}
func (srcXID64) EncodeBinary(ci*pgtype.ConnInfo, buf []byte) ([]byte, error) {
return (pguint64)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.func (dst*XID64) Scan(srcinterface{}) error {
return (*pguint64)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.func (srcXID64) Value() (driver.Value, error) {
return (pguint64)(src).Value()
}
I can easily register this new XID64 type with pgx and replace the regular one:
But for me it is crucial to use sqlx instead of pgx. Is there any possibility to register type with sqlx?
To avoid misunderstandings, I will indicate the key point of importance of sqlx for me: I need to scan an unspecified number of fields into struct in different cases, so I need sqlx methods which contain destination as interface{}. pgx does not have such functionality.
pgx v5 can be used with scany which has methods for scanning into struct. But with pgtype v5 I cannot scan nullable fields with complex types like inet, xid, etc. and cannot differentiate that a field is NULL or just undefined (like Status in pgtype v4). Or am I wrong about this?
I have a question about custom types registration. Can you please help me?
I use PostgreSQL with 64-bit XID patch. So this means that the regular pgtype.XID is no longer suitable because it is based on pguint32. I wrote custom pguint64 and XID64 types:
pguint64.go
xid64.go
I can easily register this new XID64 type with pgx and replace the regular one:
But for me it is crucial to use sqlx instead of pgx. Is there any possibility to register type with sqlx?
To avoid misunderstandings, I will indicate the key point of importance of sqlx for me: I need to scan an unspecified number of fields into struct in different cases, so I need sqlx methods which contain destination as interface{}. pgx does not have such functionality.
pgx v5 can be used with scany which has methods for scanning into struct. But with pgtype v5 I cannot scan nullable fields with complex types like inet, xid, etc. and cannot differentiate that a field is NULL or just undefined (like Status in pgtype v4). Or am I wrong about this?