ConnInfo Scan optimizes common native types
This comes at a small expense to scanning into a type that implements TextDecoder or BinaryDecoder but I think it is a good trade. Before: BenchmarkConnInfoScanInt4IntoBinaryDecoder-16 88181061 12.4 ns/op 0 B/op 0 allocs/op BenchmarkConnInfoScanInt4IntoGoInt32-16 30402768 36.8 ns/op 0 B/op 0 allocs/op After: BenchmarkConnInfoScanInt4IntoBinaryDecoder-16 79859755 14.6 ns/op 0 B/op 0 allocs/op BenchmarkConnInfoScanInt4IntoGoInt32-16 38969991 30.0 ns/op 0 B/op 0 allocs/op
This commit is contained in:
@@ -3,6 +3,7 @@ package pgtype
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
errors "golang.org/x/xerrors"
|
errors "golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
@@ -337,17 +338,39 @@ 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 {
|
||||||
switch formatCode {
|
isFastType := false
|
||||||
case BinaryFormatCode:
|
switch dest.(type) {
|
||||||
if dest, ok := dest.(BinaryDecoder); ok {
|
case *int16:
|
||||||
return dest.DecodeBinary(ci, buf)
|
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)
|
||||||
}
|
}
|
||||||
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 {
|
||||||
@@ -371,17 +394,21 @@ func (ci *ConnInfo) Scan(oid uint32, formatCode int16, buf []byte, dest interfac
|
|||||||
} else {
|
} else {
|
||||||
return errors.Errorf("%T is not a pgtype.BinaryDecoder", value)
|
return errors.Errorf("%T is not a pgtype.BinaryDecoder", value)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return errors.Errorf("unknown format code: %v", formatCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if scanner, ok := dest.(sql.Scanner); ok {
|
if !isFastType {
|
||||||
sqlSrc, err := DatabaseSQLValue(ci, value)
|
if scanner, ok := dest.(sql.Scanner); ok {
|
||||||
if err != nil {
|
sqlSrc, err := DatabaseSQLValue(ci, value)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return scanner.Scan(sqlSrc)
|
||||||
}
|
}
|
||||||
return scanner.Scan(sqlSrc)
|
|
||||||
} else {
|
|
||||||
return value.AssignTo(dest)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return value.AssignTo(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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