From 4a50a63f121988af42b813db7c637bd397f2d8ae Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Thu, 7 May 2020 19:48:48 -0500 Subject: [PATCH] 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. --- pgtype.go | 64 +++++++++++++++++++------------------------------------ 1 file changed, 22 insertions(+), 42 deletions(-) diff --git a/pgtype.go b/pgtype.go index eead52af..71babbc8 100644 --- a/pgtype.go +++ b/pgtype.go @@ -3,7 +3,6 @@ package pgtype import ( "database/sql" "reflect" - "time" 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 { - 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 { - 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) + 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) } 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 { - if scanner, ok := dest.(sql.Scanner); ok { - sqlSrc, err := DatabaseSQLValue(ci, dt.Value) - if err != nil { - return err - } - return scanner.Scan(sqlSrc) - } + assignToErr := dt.Value.AssignTo(dest) + if assignToErr == nil { + return nil } - 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),