diff --git a/value_reader.go b/value_reader.go index 6e552ea8..a4897543 100644 --- a/value_reader.go +++ b/value_reader.go @@ -60,6 +60,20 @@ func (r *ValueReader) ReadInt16() int16 { return r.mr.readInt16() } +func (r *ValueReader) ReadUint16() uint16 { + if r.err != nil { + return 0 + } + + r.valueBytesRemaining -= 2 + if r.valueBytesRemaining < 0 { + r.Fatal(errors.New("read past end of value")) + return 0 + } + + return r.mr.readUint16() +} + func (r *ValueReader) ReadInt32() int32 { if r.err != nil { return 0 diff --git a/values.go b/values.go index 69fdaae0..ae7b7cf7 100644 --- a/values.go +++ b/values.go @@ -453,7 +453,7 @@ func (n NullCid) Encode(w *WriteBuf, oid Oid) error { // Its conversion functions can be found in src/backend/utils/adt/tid.c // in the PostgreSQL sources. type Tid struct { - BlockNumber uint16 + BlockNumber uint32 OffsetNumber uint16 } @@ -473,7 +473,7 @@ func (n *NullTid) Scan(vr *ValueReader) error { } if vr.Len() == -1 { - n.Tid, n.Valid = 0, false + n.Tid, n.Valid = Tid{BlockNumber: 0, OffsetNumber: 0}, false return nil } n.Valid = true @@ -1639,13 +1639,13 @@ func decodeTid(vr *ValueReader) Tid { if err != nil { vr.Fatal(ProtocolError(fmt.Sprintf("Received invalid offsetNumber part of a Tid: %v", s))) } - return Tid{BlockNumber: blockNumber, OffsetNumber: offsetNumber} + return Tid{BlockNumber: uint32(blockNumber), OffsetNumber: uint16(offsetNumber)} case BinaryFormatCode: - if vr.Len() != 4 { + if vr.Len() != 6 { vr.Fatal(ProtocolError(fmt.Sprintf("Received an invalid size for an Oid: %d", vr.Len()))) return Tid{BlockNumber: 0, OffsetNumber: 0} } - return Tid{BlockNumber: vr.ReadUint16(), OffsetNumber: vr.ReadUint16()} + return Tid{BlockNumber: vr.ReadUint32(), OffsetNumber: vr.ReadUint16()} default: vr.Fatal(ProtocolError(fmt.Sprintf("Unknown field description format code: %v", vr.Type().FormatCode))) return Tid{BlockNumber: 0, OffsetNumber: 0} @@ -1657,9 +1657,9 @@ func encodeTid(w *WriteBuf, oid Oid, value Tid) error { return fmt.Errorf("cannot encode Go %s into oid %d", "pgx.Tid", oid) } - w.WriteInt32(4) - w.WriteUint16(uint16(value.BlockNumber)) - w.WriteUint16(uint16(value.OffsetNumber)) + w.WriteInt32(6) + w.WriteUint32(value.BlockNumber) + w.WriteUint16(value.OffsetNumber) return nil } diff --git a/values_test.go b/values_test.go index 2325b6f1..cea70b9c 100644 --- a/values_test.go +++ b/values_test.go @@ -596,6 +596,7 @@ func TestNullX(t *testing.T) { i32 pgx.NullInt32 xid pgx.NullXid cid pgx.NullCid + tid pgx.NullTid i64 pgx.NullInt64 f32 pgx.NullFloat32 f64 pgx.NullFloat64 @@ -623,6 +624,9 @@ func TestNullX(t *testing.T) { {"select $1::cid", []interface{}{pgx.NullCid{Cid: 1, Valid: true}}, []interface{}{&actual.cid}, allTypes{cid: pgx.NullCid{Cid: 1, Valid: true}}}, {"select $1::cid", []interface{}{pgx.NullCid{Cid: 1, Valid: false}}, []interface{}{&actual.cid}, allTypes{cid: pgx.NullCid{Cid: 0, Valid: false}}}, {"select $1::cid", []interface{}{pgx.NullCid{Cid: 4294967295, Valid: true}}, []interface{}{&actual.cid}, allTypes{cid: pgx.NullCid{Cid: 4294967295, Valid: true}}}, + {"select $1::tid", []interface{}{pgx.NullTid{Tid: pgx.Tid{BlockNumber: 1, OffsetNumber: 1}, Valid: true}}, []interface{}{&actual.tid}, allTypes{tid: pgx.NullTid{Tid: pgx.Tid{BlockNumber: 1, OffsetNumber: 1}, Valid: true}}}, + {"select $1::tid", []interface{}{pgx.NullTid{Tid: pgx.Tid{BlockNumber: 1, OffsetNumber: 1}, Valid: false}}, []interface{}{&actual.tid}, allTypes{tid: pgx.NullTid{Tid: pgx.Tid{BlockNumber: 0, OffsetNumber: 0}, Valid: false}}}, + {"select $1::tid", []interface{}{pgx.NullTid{Tid: pgx.Tid{BlockNumber: 4294967295, OffsetNumber: 65535}, Valid: true}}, []interface{}{&actual.tid}, allTypes{tid: pgx.NullTid{Tid: pgx.Tid{BlockNumber: 4294967295, OffsetNumber: 65535}, 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::float4", []interface{}{pgx.NullFloat32{Float32: 1.23, Valid: true}}, []interface{}{&actual.f32}, allTypes{f32: pgx.NullFloat32{Float32: 1.23, Valid: true}}},