2
0

Refactor Scan optimization

Instead of hardcoding specific types and skipping type assertions based
on that, only check if a destination is a (sql.Scanner) after a failed
AssignTo.

This is slightly slower in the non-decoder case and *very* slightly
faster in the decoder. However, this approach is cleaner and has the
potential for further optimizations.
This commit is contained in:
Jack Christensen
2020-05-07 19:48:48 -05:00
parent 452511dfc5
commit 4a50a63f12
+6 -26
View File
@@ -3,7 +3,6 @@ package pgtype
import ( import (
"database/sql" "database/sql"
"reflect" "reflect"
"time"
errors "golang.org/x/xerrors" errors "golang.org/x/xerrors"
) )
@@ -404,27 +403,6 @@ func (ci *ConnInfo) DeepCopy() *ConnInfo {
} }
func (ci *ConnInfo) Scan(oid uint32, formatCode int16, buf []byte, dest interface{}) error { func (ci *ConnInfo) Scan(oid uint32, formatCode int16, buf []byte, dest interface{}) error {
isFastType := false
switch dest.(type) {
case *int16:
isFastType = true
case *int32:
isFastType = true
case *int64:
isFastType = true
case *float32:
isFastType = true
case *float64:
isFastType = true
case *string:
isFastType = true
case *time.Time:
isFastType = true
case *[]byte:
isFastType = true
}
if !isFastType {
switch formatCode { switch formatCode {
case BinaryFormatCode: case BinaryFormatCode:
if dest, ok := dest.(BinaryDecoder); ok { if dest, ok := dest.(BinaryDecoder); ok {
@@ -437,7 +415,6 @@ func (ci *ConnInfo) Scan(oid uint32, formatCode int16, buf []byte, dest interfac
default: default:
return errors.Errorf("unknown format code: %v", formatCode) return errors.Errorf("unknown format code: %v", formatCode)
} }
}
if dt, ok := ci.DataTypeForOID(oid); ok { if dt, ok := ci.DataTypeForOID(oid); ok {
switch formatCode { switch formatCode {
@@ -461,7 +438,11 @@ func (ci *ConnInfo) Scan(oid uint32, formatCode int16, buf []byte, dest interfac
} }
} }
if !isFastType { assignToErr := dt.Value.AssignTo(dest)
if assignToErr == nil {
return nil
}
if scanner, ok := dest.(sql.Scanner); ok { if scanner, ok := dest.(sql.Scanner); ok {
sqlSrc, err := DatabaseSQLValue(ci, dt.Value) sqlSrc, err := DatabaseSQLValue(ci, dt.Value)
if err != nil { if err != nil {
@@ -469,9 +450,8 @@ func (ci *ConnInfo) Scan(oid uint32, formatCode int16, buf []byte, dest interfac
} }
return scanner.Scan(sqlSrc) return scanner.Scan(sqlSrc)
} }
}
return dt.Value.AssignTo(dest) return assignToErr
} }
// We might be given a pointer to something that implements the decoder interface(s), // We might be given a pointer to something that implements the decoder interface(s),