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
+22 -42
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,39 +403,17 @@ 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 formatCode {
switch dest.(type) { case BinaryFormatCode:
case *int16: if dest, ok := dest.(BinaryDecoder); ok {
isFastType = true return dest.DecodeBinary(ci, buf)
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 {
case BinaryFormatCode:
if dest, ok := dest.(BinaryDecoder); ok {
return dest.DecodeBinary(ci, buf)
}
case TextFormatCode:
if dest, ok := dest.(TextDecoder); ok {
return dest.DecodeText(ci, buf)
}
default:
return errors.Errorf("unknown format code: %v", formatCode)
} }
case TextFormatCode:
if dest, ok := dest.(TextDecoder); ok {
return dest.DecodeText(ci, buf)
}
default:
return errors.Errorf("unknown format code: %v", formatCode)
} }
if dt, ok := ci.DataTypeForOID(oid); ok { if dt, ok := ci.DataTypeForOID(oid); ok {
@@ -461,17 +438,20 @@ func (ci *ConnInfo) Scan(oid uint32, formatCode int16, buf []byte, dest interfac
} }
} }
if !isFastType { assignToErr := dt.Value.AssignTo(dest)
if scanner, ok := dest.(sql.Scanner); ok { if assignToErr == nil {
sqlSrc, err := DatabaseSQLValue(ci, dt.Value) return nil
if err != nil {
return err
}
return scanner.Scan(sqlSrc)
}
} }
return dt.Value.AssignTo(dest) if scanner, ok := dest.(sql.Scanner); ok {
sqlSrc, err := DatabaseSQLValue(ci, dt.Value)
if err != nil {
return err
}
return scanner.Scan(sqlSrc)
}
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),