Merge pull request #7 from scylladb/mmt/select

select: reduce allocations and improve code structure
This commit is contained in:
Michał Matczuk
2017-08-03 13:30:28 +02:00
committed by GitHub

View File

@@ -62,15 +62,15 @@ func (iter *Iterx) Get(dest interface{}) error {
} }
func (iter *Iterx) scanAny(dest interface{}, structOnly bool) error { func (iter *Iterx) scanAny(dest interface{}, structOnly bool) error {
v := reflect.ValueOf(dest) value := reflect.ValueOf(dest)
if v.Kind() != reflect.Ptr { if value.Kind() != reflect.Ptr {
return errors.New("must pass a pointer, not a value, to StructScan destination") return errors.New("must pass a pointer, not a value, to StructScan destination")
} }
if v.IsNil() { if value.IsNil() {
return errors.New("nil pointer passed to StructScan destination") return errors.New("nil pointer passed to StructScan destination")
} }
base := reflectx.Deref(v.Type()) base := reflectx.Deref(value.Type())
scannable := isScannable(base) scannable := isScannable(base)
if structOnly && scannable { if structOnly && scannable {
@@ -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,37 +141,33 @@ 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 (
vp reflect.Value
ok bool
)
for { for {
// create a new struct type (which returns PtrTo) and indirect it // create a new struct type (which returns PtrTo) and indirect it
vp = reflect.New(base) vp = reflect.New(base)
v = reflect.Indirect(vp)
// scan into the struct field pointers and append to our results // scan into the struct field pointers
if ok := iter.StructScan(vp.Interface()); !ok { if !scannable {
ok = iter.StructScan(vp.Interface())
} else {
ok = iter.Scan(vp.Interface())
}
if !ok {
break break
} }
if isPtr { if isPtr {
direct.Set(reflect.Append(direct, vp)) v = reflect.Append(v, vp)
} else { } else {
direct.Set(reflect.Append(direct, v)) v = reflect.Append(v, reflect.Indirect(vp))
} }
} }
} else {
for {
vp = reflect.New(base)
if ok := iter.Scan(vp.Interface()); !ok {
break
}
// append // update dest
if isPtr { reflect.Indirect(value).Set(v)
direct.Set(reflect.Append(direct, vp))
} else {
direct.Set(reflect.Append(direct, reflect.Indirect(vp)))
}
}
}
return iter.err return iter.err
} }