2
0

Refactor lowlevel record field iteration

This commit is contained in:
Maxim Ivanov
2020-04-11 10:38:23 +01:00
parent 98c9ec4f7b
commit 087df120bb
+63 -26
View File
@@ -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}