select: reduce allocations and improve code structure

This commit is contained in:
Michał Matczuk
2017-08-03 12:02:23 +02:00
parent 456ce5e2f4
commit 3b6b4ff687

View File

@@ -110,8 +110,6 @@ func (iter *Iterx) Select(dest interface{}) error {
} }
func (iter *Iterx) scanAll(dest interface{}, structOnly bool) error { func (iter *Iterx) scanAll(dest interface{}, structOnly bool) error {
var v, vp reflect.Value
value := reflect.ValueOf(dest) value := reflect.ValueOf(dest)
// json.Unmarshal returns errors for these // json.Unmarshal returns errors for these
@@ -121,13 +119,15 @@ func (iter *Iterx) scanAll(dest interface{}, structOnly bool) error {
if value.IsNil() { if value.IsNil() {
return errors.New("nil pointer passed to StructScan destination") return errors.New("nil pointer passed to StructScan destination")
} }
direct := reflect.Indirect(value)
slice, err := baseType(value.Type(), reflect.Slice) slice, err := baseType(value.Type(), reflect.Slice)
if err != nil { if err != nil {
return err return err
} }
// allocate memory for the page data
v := reflect.MakeSlice(slice, 0, iter.Iter.NumRows())
isPtr := slice.Elem().Kind() == reflect.Ptr isPtr := slice.Elem().Kind() == reflect.Ptr
base := reflectx.Deref(slice.Elem()) base := reflectx.Deref(slice.Elem())
scannable := isScannable(base) scannable := isScannable(base)
@@ -141,38 +141,34 @@ func (iter *Iterx) scanAll(dest interface{}, structOnly bool) error {
return fmt.Errorf("non-struct dest type %s with >1 columns (%d)", base.Kind(), len(iter.Columns())) return fmt.Errorf("non-struct dest type %s with >1 columns (%d)", base.Kind(), len(iter.Columns()))
} }
if !scannable { var (
for { vp reflect.Value
// create a new struct type (which returns PtrTo) and indirect it ok bool
vp = reflect.New(base) )
v = reflect.Indirect(vp) for {
// scan into the struct field pointers and append to our results // create a new struct type (which returns PtrTo) and indirect it
if ok := iter.StructScan(vp.Interface()); !ok { vp = reflect.New(base)
break
}
if isPtr { // scan into the struct field pointers
direct.Set(reflect.Append(direct, vp)) if !scannable {
} else { ok = iter.StructScan(vp.Interface())
direct.Set(reflect.Append(direct, v)) } else {
} ok = iter.Scan(vp.Interface())
}
if !ok {
break
} }
} else {
for {
vp = reflect.New(base)
if ok := iter.Scan(vp.Interface()); !ok {
break
}
// append if isPtr {
if isPtr { v = reflect.Append(v, vp)
direct.Set(reflect.Append(direct, vp)) } else {
} else { v = reflect.Append(v, reflect.Indirect(vp))
direct.Set(reflect.Append(direct, reflect.Indirect(vp)))
}
} }
} }
// update dest
reflect.Indirect(value).Set(v)
return iter.err return iter.err
} }