mirror of https://github.com/jackc/pgx.git
Adds Xid type
parent
7dbfd4bf4b
commit
1061b1f978
|
@ -138,6 +138,12 @@ func (wb *WriteBuf) WriteInt32(n int32) {
|
||||||
wb.buf = append(wb.buf, b...)
|
wb.buf = append(wb.buf, b...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (wb *WriteBuf) WriteUint32(n uint32) {
|
||||||
|
b := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(b, uint32(n))
|
||||||
|
wb.buf = append(wb.buf, b...)
|
||||||
|
}
|
||||||
|
|
||||||
func (wb *WriteBuf) WriteInt64(n int64) {
|
func (wb *WriteBuf) WriteInt64(n int64) {
|
||||||
b := make([]byte, 8)
|
b := make([]byte, 8)
|
||||||
binary.BigEndian.PutUint64(b, uint64(n))
|
binary.BigEndian.PutUint64(b, uint64(n))
|
||||||
|
|
90
values.go
90
values.go
|
@ -22,6 +22,7 @@ const (
|
||||||
Int4Oid = 23
|
Int4Oid = 23
|
||||||
TextOid = 25
|
TextOid = 25
|
||||||
OidOid = 26
|
OidOid = 26
|
||||||
|
XidOid = 28
|
||||||
JsonOid = 114
|
JsonOid = 114
|
||||||
CidrOid = 650
|
CidrOid = 650
|
||||||
CidrArrayOid = 651
|
CidrArrayOid = 651
|
||||||
|
@ -93,6 +94,7 @@ func init() {
|
||||||
"int4": BinaryFormatCode,
|
"int4": BinaryFormatCode,
|
||||||
"int8": BinaryFormatCode,
|
"int8": BinaryFormatCode,
|
||||||
"oid": BinaryFormatCode,
|
"oid": BinaryFormatCode,
|
||||||
|
"xid": BinaryFormatCode,
|
||||||
"record": BinaryFormatCode,
|
"record": BinaryFormatCode,
|
||||||
"text": BinaryFormatCode,
|
"text": BinaryFormatCode,
|
||||||
"timestamp": BinaryFormatCode,
|
"timestamp": BinaryFormatCode,
|
||||||
|
@ -327,6 +329,47 @@ func (n NullInt32) Encode(w *WriteBuf, oid Oid) error {
|
||||||
return encodeInt32(w, oid, n.Int32)
|
return encodeInt32(w, oid, n.Int32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Xid uint32
|
||||||
|
|
||||||
|
// NullXid represents a transaction ID (Xid) that may be null. NullXid implements the
|
||||||
|
// Scanner and Encoder interfaces so it may be used both as an argument to
|
||||||
|
// Query[Row] and a destination for Scan.
|
||||||
|
//
|
||||||
|
// If Valid is false then the value is NULL.
|
||||||
|
type NullXid struct {
|
||||||
|
Xid Xid
|
||||||
|
Valid bool // Valid is true if Int32 is not NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NullXid) Scan(vr *ValueReader) error {
|
||||||
|
if vr.Type().DataType != XidOid {
|
||||||
|
return SerializationError(fmt.Sprintf("NullXid.Scan cannot decode OID %d", vr.Type().DataType))
|
||||||
|
}
|
||||||
|
|
||||||
|
if vr.Len() == -1 {
|
||||||
|
n.Xid, n.Valid = 0, false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
n.Valid = true
|
||||||
|
n.Xid = decodeXid(vr)
|
||||||
|
return vr.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NullXid) FormatCode() int16 { return BinaryFormatCode }
|
||||||
|
|
||||||
|
func (n NullXid) Encode(w *WriteBuf, oid Oid) error {
|
||||||
|
if oid != XidOid {
|
||||||
|
return SerializationError(fmt.Sprintf("NullXid.Encode cannot encode into OID %d", oid))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !n.Valid {
|
||||||
|
w.WriteInt32(-1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return encodeXid(w, oid, n.Xid)
|
||||||
|
}
|
||||||
|
|
||||||
// NullInt64 represents an bigint that may be null. NullInt64 implements the
|
// NullInt64 represents an bigint that may be null. NullInt64 implements the
|
||||||
// Scanner and Encoder interfaces so it may be used both as an argument to
|
// Scanner and Encoder interfaces so it may be used both as an argument to
|
||||||
// Query[Row] and a destination for Scan.
|
// Query[Row] and a destination for Scan.
|
||||||
|
@ -691,6 +734,8 @@ func Encode(wbuf *WriteBuf, oid Oid, arg interface{}) error {
|
||||||
return encodeIPNetSlice(wbuf, oid, arg)
|
return encodeIPNetSlice(wbuf, oid, arg)
|
||||||
case Oid:
|
case Oid:
|
||||||
return encodeOid(wbuf, oid, arg)
|
return encodeOid(wbuf, oid, arg)
|
||||||
|
case Xid:
|
||||||
|
return encodeXid(wbuf, oid, arg)
|
||||||
default:
|
default:
|
||||||
if strippedArg, ok := stripNamedType(&refVal); ok {
|
if strippedArg, ok := stripNamedType(&refVal); ok {
|
||||||
return Encode(wbuf, oid, strippedArg)
|
return Encode(wbuf, oid, strippedArg)
|
||||||
|
@ -815,6 +860,8 @@ func Decode(vr *ValueReader, d interface{}) error {
|
||||||
*v = uint64(n)
|
*v = uint64(n)
|
||||||
case *Oid:
|
case *Oid:
|
||||||
*v = decodeOid(vr)
|
*v = decodeOid(vr)
|
||||||
|
case *Xid:
|
||||||
|
*v = decodeXid(vr)
|
||||||
case *string:
|
case *string:
|
||||||
*v = decodeText(vr)
|
*v = decodeText(vr)
|
||||||
case *float32:
|
case *float32:
|
||||||
|
@ -1339,6 +1386,49 @@ func encodeOid(w *WriteBuf, oid Oid, value Oid) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeXid(vr *ValueReader) Xid {
|
||||||
|
if vr.Len() == -1 {
|
||||||
|
vr.Fatal(ProtocolError("Cannot decode null into Xid"))
|
||||||
|
return Xid(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if vr.Type().DataType != XidOid {
|
||||||
|
vr.Fatal(ProtocolError(fmt.Sprintf("Cannot decode oid %v into pgx.Xid", vr.Type().DataType)))
|
||||||
|
return Xid(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlikely Xid will ever go over the wire as text format, but who knows?
|
||||||
|
switch vr.Type().FormatCode {
|
||||||
|
case TextFormatCode:
|
||||||
|
s := vr.ReadString(vr.Len())
|
||||||
|
n, err := strconv.ParseUint(s, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
vr.Fatal(ProtocolError(fmt.Sprintf("Received invalid Oid: %v", s)))
|
||||||
|
}
|
||||||
|
return Xid(n)
|
||||||
|
case BinaryFormatCode:
|
||||||
|
if vr.Len() != 4 {
|
||||||
|
vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an Oid: %d", vr.Len())))
|
||||||
|
return Xid(0)
|
||||||
|
}
|
||||||
|
return Xid(vr.ReadUint32())
|
||||||
|
default:
|
||||||
|
vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode)))
|
||||||
|
return Xid(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeXid(w *WriteBuf, oid Oid, value Xid) error {
|
||||||
|
if oid != XidOid {
|
||||||
|
return fmt.Errorf("cannot encode Go %s into oid %d", "pgx.Xid", oid)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteInt32(4)
|
||||||
|
w.WriteUint32(uint32(value))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func decodeFloat4(vr *ValueReader) float32 {
|
func decodeFloat4(vr *ValueReader) float32 {
|
||||||
if vr.Len() == -1 {
|
if vr.Len() == -1 {
|
||||||
vr.Fatal(ProtocolError("Cannot decode null into float32"))
|
vr.Fatal(ProtocolError("Cannot decode null into float32"))
|
||||||
|
|
|
@ -594,6 +594,7 @@ func TestNullX(t *testing.T) {
|
||||||
s pgx.NullString
|
s pgx.NullString
|
||||||
i16 pgx.NullInt16
|
i16 pgx.NullInt16
|
||||||
i32 pgx.NullInt32
|
i32 pgx.NullInt32
|
||||||
|
xid pgx.NullXid
|
||||||
i64 pgx.NullInt64
|
i64 pgx.NullInt64
|
||||||
f32 pgx.NullFloat32
|
f32 pgx.NullFloat32
|
||||||
f64 pgx.NullFloat64
|
f64 pgx.NullFloat64
|
||||||
|
@ -615,6 +616,9 @@ func TestNullX(t *testing.T) {
|
||||||
{"select $1::int2", []interface{}{pgx.NullInt16{Int16: 1, Valid: false}}, []interface{}{&actual.i16}, allTypes{i16: pgx.NullInt16{Int16: 0, Valid: false}}},
|
{"select $1::int2", []interface{}{pgx.NullInt16{Int16: 1, Valid: false}}, []interface{}{&actual.i16}, allTypes{i16: pgx.NullInt16{Int16: 0, Valid: false}}},
|
||||||
{"select $1::int4", []interface{}{pgx.NullInt32{Int32: 1, Valid: true}}, []interface{}{&actual.i32}, allTypes{i32: pgx.NullInt32{Int32: 1, Valid: true}}},
|
{"select $1::int4", []interface{}{pgx.NullInt32{Int32: 1, Valid: true}}, []interface{}{&actual.i32}, allTypes{i32: pgx.NullInt32{Int32: 1, Valid: true}}},
|
||||||
{"select $1::int4", []interface{}{pgx.NullInt32{Int32: 1, Valid: false}}, []interface{}{&actual.i32}, allTypes{i32: pgx.NullInt32{Int32: 0, Valid: false}}},
|
{"select $1::int4", []interface{}{pgx.NullInt32{Int32: 1, Valid: false}}, []interface{}{&actual.i32}, allTypes{i32: pgx.NullInt32{Int32: 0, Valid: false}}},
|
||||||
|
{"select $1::xid", []interface{}{pgx.NullXid{Xid: 1, Valid: true}}, []interface{}{&actual.xid}, allTypes{xid: pgx.NullXid{Xid: 1, Valid: true}}},
|
||||||
|
{"select $1::xid", []interface{}{pgx.NullXid{Xid: 1, Valid: false}}, []interface{}{&actual.xid}, allTypes{xid: pgx.NullXid{Xid: 0, Valid: false}}},
|
||||||
|
{"select $1::xid", []interface{}{pgx.NullXid{Xid: 4294967295, Valid: true}}, []interface{}{&actual.xid}, allTypes{xid: pgx.NullXid{Xid: 4294967295, Valid: true}}},
|
||||||
{"select $1::int8", []interface{}{pgx.NullInt64{Int64: 1, Valid: true}}, []interface{}{&actual.i64}, allTypes{i64: pgx.NullInt64{Int64: 1, Valid: true}}},
|
{"select $1::int8", []interface{}{pgx.NullInt64{Int64: 1, Valid: true}}, []interface{}{&actual.i64}, allTypes{i64: pgx.NullInt64{Int64: 1, Valid: true}}},
|
||||||
{"select $1::int8", []interface{}{pgx.NullInt64{Int64: 1, Valid: false}}, []interface{}{&actual.i64}, allTypes{i64: pgx.NullInt64{Int64: 0, Valid: false}}},
|
{"select $1::int8", []interface{}{pgx.NullInt64{Int64: 1, Valid: false}}, []interface{}{&actual.i64}, allTypes{i64: pgx.NullInt64{Int64: 0, Valid: false}}},
|
||||||
{"select $1::float4", []interface{}{pgx.NullFloat32{Float32: 1.23, Valid: true}}, []interface{}{&actual.f32}, allTypes{f32: pgx.NullFloat32{Float32: 1.23, Valid: true}}},
|
{"select $1::float4", []interface{}{pgx.NullFloat32{Float32: 1.23, Valid: true}}, []interface{}{&actual.f32}, allTypes{f32: pgx.NullFloat32{Float32: 1.23, Valid: true}}},
|
||||||
|
|
Loading…
Reference in New Issue