Refactor lowlevel record field iteration
This commit is contained in:
@@ -78,57 +78,94 @@ func (src *Record) AssignTo(dst interface{}) error {
|
|||||||
return errors.Errorf("cannot decode %#v into %T", src, dst)
|
return errors.Errorf("cannot decode %#v into %T", src, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fieldIter struct {
|
||||||
|
rp int
|
||||||
|
fieldCount int
|
||||||
|
src []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFieldIterator(src []byte) (fieldIter, error) {
|
||||||
|
rp := 0
|
||||||
|
if len(src[rp:]) < 4 {
|
||||||
|
return fieldIter{}, errors.Errorf("Record incomplete %v", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldCount := int(int32(binary.BigEndian.Uint32(src[rp:])))
|
||||||
|
rp += 4
|
||||||
|
|
||||||
|
return fieldIter{
|
||||||
|
rp: rp,
|
||||||
|
fieldCount: fieldCount,
|
||||||
|
src: src,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *fieldIter) 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
|
||||||
|
}
|
||||||
|
|
||||||
func (dst *Record) DecodeBinary(ci *ConnInfo, src []byte) error {
|
func (dst *Record) DecodeBinary(ci *ConnInfo, src []byte) error {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
*dst = Record{Status: Null}
|
*dst = Record{Status: Null}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rp := 0
|
fieldIter, err := newFieldIterator(src)
|
||||||
|
if err != nil {
|
||||||
if len(src[rp:]) < 4 {
|
return err
|
||||||
return errors.Errorf("Record incomplete %v", src)
|
|
||||||
}
|
}
|
||||||
fieldCount := int(int32(binary.BigEndian.Uint32(src[rp:])))
|
|
||||||
rp += 4
|
|
||||||
|
|
||||||
fields := make([]Value, fieldCount)
|
fields := make([]Value, fieldIter.fieldCount)
|
||||||
|
fieldOID, fieldBytes, eof, err := fieldIter.next()
|
||||||
|
|
||||||
for i := 0; i < fieldCount; i++ {
|
for i := 0; !eof; i++ {
|
||||||
if len(src[rp:]) < 8 {
|
if err != nil {
|
||||||
return errors.Errorf("Record incomplete %v", src)
|
return err
|
||||||
}
|
}
|
||||||
fieldOID := binary.BigEndian.Uint32(src[rp:])
|
|
||||||
rp += 4
|
|
||||||
|
|
||||||
fieldLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
|
|
||||||
rp += 4
|
|
||||||
|
|
||||||
var binaryDecoder BinaryDecoder
|
var binaryDecoder BinaryDecoder
|
||||||
|
|
||||||
if dt, ok := ci.DataTypeForOID(fieldOID); ok {
|
if dt, ok := ci.DataTypeForOID(fieldOID); ok {
|
||||||
binaryDecoder, _ = dt.Value.(BinaryDecoder)
|
binaryDecoder, _ = dt.Value.(BinaryDecoder)
|
||||||
}
|
} else {
|
||||||
if binaryDecoder == nil {
|
|
||||||
return errors.Errorf("unknown oid while decoding record: %v", fieldOID)
|
return errors.Errorf("unknown oid while decoding record: %v", fieldOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
var fieldBytes []byte
|
if binaryDecoder == nil {
|
||||||
if fieldLen >= 0 {
|
return errors.Errorf("no binary decoder registered for: %v", fieldOID)
|
||||||
if len(src[rp:]) < fieldLen {
|
|
||||||
return errors.Errorf("Record incomplete %v", src)
|
|
||||||
}
|
|
||||||
fieldBytes = src[rp : rp+fieldLen]
|
|
||||||
rp += fieldLen
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplicate struct to scan into
|
// Duplicate struct to scan into
|
||||||
binaryDecoder = reflect.New(reflect.ValueOf(binaryDecoder).Elem().Type()).Interface().(BinaryDecoder)
|
binaryDecoder = reflect.New(reflect.ValueOf(binaryDecoder).Elem().Type()).Interface().(BinaryDecoder)
|
||||||
|
|
||||||
if err := binaryDecoder.DecodeBinary(ci, fieldBytes); err != nil {
|
if err := binaryDecoder.DecodeBinary(ci, fieldBytes); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fields[i] = binaryDecoder.(Value)
|
fields[i] = binaryDecoder.(Value)
|
||||||
|
fieldOID, fieldBytes, eof, err = fieldIter.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst = Record{Fields: fields, Status: Present}
|
*dst = Record{Fields: fields, Status: Present}
|
||||||
|
|||||||
Reference in New Issue
Block a user