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:
@@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user