From ff9bc5d68dd597c3f4259eadd759cfb2817ca43b Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Thu, 7 May 2020 10:15:23 -0500 Subject: [PATCH] Merge binary package into pgtype package --- binary/record.go | 78 ----------------------------------------- composite.go | 76 +++++++++++++++++++++++++++++++++++++-- composite_bench_test.go | 11 +++--- convert.go | 9 +++-- record.go | 4 +-- 5 files changed, 84 insertions(+), 94 deletions(-) delete mode 100644 binary/record.go diff --git a/binary/record.go b/binary/record.go deleted file mode 100644 index 72b688a8..00000000 --- a/binary/record.go +++ /dev/null @@ -1,78 +0,0 @@ -package binary - -import ( - "encoding/binary" - - "github.com/jackc/pgio" - errors "golang.org/x/xerrors" -) - -type RecordFieldIter struct { - rp int - src []byte -} - -// NewRecordFieldIterator creates iterator over binary representation -// of record, aka ROW(), aka Composite -func NewRecordFieldIterator(src []byte) (RecordFieldIter, int, error) { - rp := 0 - if len(src[rp:]) < 4 { - return RecordFieldIter{}, 0, errors.Errorf("Record incomplete %v", src) - } - - fieldCount := int(int32(binary.BigEndian.Uint32(src[rp:]))) - rp += 4 - - return RecordFieldIter{ - rp: rp, - src: src, - }, fieldCount, nil -} - -// Next returns next field decoded from record. eof is returned if no -// more fields left to decode. -func (fi *RecordFieldIter) Next() (fieldOID uint32, buf []byte, eof bool, err error) { - if fi.rp == len(fi.src) { - eof = true - return - } - - if len(fi.src[fi.rp:]) < 8 { - err = errors.Errorf("Record incomplete %v", fi.src) - return - } - fieldOID = binary.BigEndian.Uint32(fi.src[fi.rp:]) - fi.rp += 4 - - fieldLen := int(int32(binary.BigEndian.Uint32(fi.src[fi.rp:]))) - fi.rp += 4 - - if fieldLen >= 0 { - if len(fi.src[fi.rp:]) < fieldLen { - err = errors.Errorf("Record incomplete rp=%d src=%v", fi.rp, fi.src) - return - } - buf = fi.src[fi.rp : fi.rp+fieldLen] - fi.rp += fieldLen - } - - return -} - -// RecordStart adds record header to the buf -func RecordStart(buf []byte, fieldCount int) []byte { - return pgio.AppendUint32(buf, uint32(fieldCount)) -} - -// RecordAdd adds record field to the buf -func RecordAdd(buf []byte, oid uint32, fieldBytes []byte) []byte { - buf = pgio.AppendUint32(buf, oid) - buf = pgio.AppendUint32(buf, uint32(len(fieldBytes))) - buf = append(buf, fieldBytes...) - return buf -} - -// RecordAddNull adds null value as a field to the buf -func RecordAddNull(buf []byte, oid uint32) []byte { - return pgio.AppendInt32(buf, int32(-1)) -} diff --git a/composite.go b/composite.go index 61034262..6ffe9acf 100644 --- a/composite.go +++ b/composite.go @@ -1,7 +1,9 @@ package pgtype import ( - "github.com/jackc/pgtype/binary" + "encoding/binary" + + "github.com/jackc/pgio" errors "golang.org/x/xerrors" ) @@ -82,7 +84,7 @@ func (dst *Composite) DecodeBinary(ci *ConnInfo, buf []byte) (err error) { return nil } - fieldIter, fieldCount, err := binary.NewRecordFieldIterator(buf) + fieldIter, fieldCount, err := NewRecordFieldIterator(buf) if err != nil { return err } else if len(dst.fields) != fieldCount { @@ -151,3 +153,73 @@ func (dst *Composite) SetFields(values ...interface{}) error { dst.Status = Present return nil } + +type RecordFieldIter struct { + rp int + src []byte +} + +// NewRecordFieldIterator creates iterator over binary representation +// of record, aka ROW(), aka Composite +func NewRecordFieldIterator(src []byte) (RecordFieldIter, int, error) { + rp := 0 + if len(src[rp:]) < 4 { + return RecordFieldIter{}, 0, errors.Errorf("Record incomplete %v", src) + } + + fieldCount := int(int32(binary.BigEndian.Uint32(src[rp:]))) + rp += 4 + + return RecordFieldIter{ + rp: rp, + src: src, + }, fieldCount, nil +} + +// Next returns next field decoded from record. eof is returned if no +// more fields left to decode. +func (fi *RecordFieldIter) Next() (fieldOID uint32, buf []byte, eof bool, err error) { + if fi.rp == len(fi.src) { + eof = true + return + } + + if len(fi.src[fi.rp:]) < 8 { + err = errors.Errorf("Record incomplete %v", fi.src) + return + } + fieldOID = binary.BigEndian.Uint32(fi.src[fi.rp:]) + fi.rp += 4 + + fieldLen := int(int32(binary.BigEndian.Uint32(fi.src[fi.rp:]))) + fi.rp += 4 + + if fieldLen >= 0 { + if len(fi.src[fi.rp:]) < fieldLen { + err = errors.Errorf("Record incomplete rp=%d src=%v", fi.rp, fi.src) + return + } + buf = fi.src[fi.rp : fi.rp+fieldLen] + fi.rp += fieldLen + } + + return +} + +// RecordStart adds record header to the buf +func RecordStart(buf []byte, fieldCount int) []byte { + return pgio.AppendUint32(buf, uint32(fieldCount)) +} + +// RecordAdd adds record field to the buf +func RecordAdd(buf []byte, oid uint32, fieldBytes []byte) []byte { + buf = pgio.AppendUint32(buf, oid) + buf = pgio.AppendUint32(buf, uint32(len(fieldBytes))) + buf = append(buf, fieldBytes...) + return buf +} + +// RecordAddNull adds null value as a field to the buf +func RecordAddNull(buf []byte, oid uint32) []byte { + return pgio.AppendInt32(buf, int32(-1)) +} diff --git a/composite_bench_test.go b/composite_bench_test.go index 429ce9b3..fd31e8ea 100644 --- a/composite_bench_test.go +++ b/composite_bench_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/jackc/pgtype" - "github.com/jackc/pgtype/binary" errors "golang.org/x/xerrors" ) @@ -19,14 +18,14 @@ func (src MyCompositeRaw) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) (newBuf fieldBytes := make([]byte, 0, 64) fieldBytes, _ = a.EncodeBinary(ci, fieldBytes[:0]) - newBuf = binary.RecordStart(buf, 2) - newBuf = binary.RecordAdd(newBuf, pgtype.Int4OID, fieldBytes) + newBuf = pgtype.RecordStart(buf, 2) + newBuf = pgtype.RecordAdd(newBuf, pgtype.Int4OID, fieldBytes) if src.B != nil { fieldBytes, _ = pgtype.Text{*src.B, pgtype.Present}.EncodeBinary(ci, fieldBytes[:0]) - newBuf = binary.RecordAdd(newBuf, pgtype.TextOID, fieldBytes) + newBuf = pgtype.RecordAdd(newBuf, pgtype.TextOID, fieldBytes) } else { - newBuf = binary.RecordAddNull(newBuf, pgtype.TextOID) + newBuf = pgtype.RecordAddNull(newBuf, pgtype.TextOID) } return } @@ -35,7 +34,7 @@ func (dst *MyCompositeRaw) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error { a := pgtype.Int4{} b := pgtype.Text{} - fieldIter, fieldCount, err := binary.NewRecordFieldIterator(src) + fieldIter, fieldCount, err := pgtype.NewRecordFieldIterator(src) if err != nil { return err } diff --git a/convert.go b/convert.go index 115f33a3..91a32a60 100644 --- a/convert.go +++ b/convert.go @@ -5,7 +5,6 @@ import ( "reflect" "time" - "github.com/jackc/pgtype/binary" errors "golang.org/x/xerrors" ) @@ -443,7 +442,7 @@ func GetAssignToDstType(dst interface{}) (interface{}, bool) { // // ScanRowValue takes ownership of src, caller MUST not use it after call func ScanRowValue(ci *ConnInfo, src []byte, dst ...interface{}) error { - fieldIter, fieldCount, err := binary.NewRecordFieldIterator(src) + fieldIter, fieldCount, err := NewRecordFieldIterator(src) if err != nil { return err } @@ -472,7 +471,7 @@ func ScanRowValue(ci *ConnInfo, src []byte, dst ...interface{}) error { func EncodeRow(ci *ConnInfo, buf []byte, fields ...Value) (newBuf []byte, err error) { fieldBytes := make([]byte, 0, 128) - newBuf = binary.RecordStart(buf, len(fields)) + newBuf = RecordStart(buf, len(fields)) for _, f := range fields { dt, ok := ci.DataTypeForValue(f) if !ok { @@ -487,9 +486,9 @@ func EncodeRow(ci *ConnInfo, buf []byte, fields ...Value) (newBuf []byte, err er if err != nil { return nil, err } - newBuf = binary.RecordAdd(newBuf, dt.OID, fieldBytes) + newBuf = RecordAdd(newBuf, dt.OID, fieldBytes) } else { - newBuf = binary.RecordAddNull(newBuf, dt.OID) + newBuf = RecordAddNull(newBuf, dt.OID) } } diff --git a/record.go b/record.go index 4e39f92a..b0c47185 100644 --- a/record.go +++ b/record.go @@ -3,8 +3,6 @@ package pgtype import ( "reflect" - "github.com/jackc/pgtype/binary" - errors "golang.org/x/xerrors" ) @@ -104,7 +102,7 @@ func (dst *Record) DecodeBinary(ci *ConnInfo, src []byte) error { return nil } - fieldIter, fieldCount, err := binary.NewRecordFieldIterator(src) + fieldIter, fieldCount, err := NewRecordFieldIterator(src) if err != nil { return err }