GoToSocial/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go

1970 lines
58 KiB
Go

package pgtype
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"net"
"net/netip"
"reflect"
"time"
)
// PostgreSQL oids for common types
const (
BoolOID = 16
ByteaOID = 17
QCharOID = 18
NameOID = 19
Int8OID = 20
Int2OID = 21
Int4OID = 23
TextOID = 25
OIDOID = 26
TIDOID = 27
XIDOID = 28
CIDOID = 29
JSONOID = 114
JSONArrayOID = 199
PointOID = 600
LsegOID = 601
PathOID = 602
BoxOID = 603
PolygonOID = 604
LineOID = 628
LineArrayOID = 629
CIDROID = 650
CIDRArrayOID = 651
Float4OID = 700
Float8OID = 701
CircleOID = 718
CircleArrayOID = 719
UnknownOID = 705
MacaddrOID = 829
InetOID = 869
BoolArrayOID = 1000
QCharArrayOID = 1002
NameArrayOID = 1003
Int2ArrayOID = 1005
Int4ArrayOID = 1007
TextArrayOID = 1009
TIDArrayOID = 1010
ByteaArrayOID = 1001
XIDArrayOID = 1011
CIDArrayOID = 1012
BPCharArrayOID = 1014
VarcharArrayOID = 1015
Int8ArrayOID = 1016
PointArrayOID = 1017
LsegArrayOID = 1018
PathArrayOID = 1019
BoxArrayOID = 1020
Float4ArrayOID = 1021
Float8ArrayOID = 1022
PolygonArrayOID = 1027
OIDArrayOID = 1028
ACLItemOID = 1033
ACLItemArrayOID = 1034
MacaddrArrayOID = 1040
InetArrayOID = 1041
BPCharOID = 1042
VarcharOID = 1043
DateOID = 1082
TimeOID = 1083
TimestampOID = 1114
TimestampArrayOID = 1115
DateArrayOID = 1182
TimeArrayOID = 1183
TimestamptzOID = 1184
TimestamptzArrayOID = 1185
IntervalOID = 1186
IntervalArrayOID = 1187
NumericArrayOID = 1231
TimetzOID = 1266
TimetzArrayOID = 1270
BitOID = 1560
BitArrayOID = 1561
VarbitOID = 1562
VarbitArrayOID = 1563
NumericOID = 1700
RecordOID = 2249
RecordArrayOID = 2287
UUIDOID = 2950
UUIDArrayOID = 2951
JSONBOID = 3802
JSONBArrayOID = 3807
DaterangeOID = 3912
DaterangeArrayOID = 3913
Int4rangeOID = 3904
Int4rangeArrayOID = 3905
NumrangeOID = 3906
NumrangeArrayOID = 3907
TsrangeOID = 3908
TsrangeArrayOID = 3909
TstzrangeOID = 3910
TstzrangeArrayOID = 3911
Int8rangeOID = 3926
Int8rangeArrayOID = 3927
JSONPathOID = 4072
JSONPathArrayOID = 4073
Int4multirangeOID = 4451
NummultirangeOID = 4532
TsmultirangeOID = 4533
TstzmultirangeOID = 4534
DatemultirangeOID = 4535
Int8multirangeOID = 4536
Int4multirangeArrayOID = 6150
NummultirangeArrayOID = 6151
TsmultirangeArrayOID = 6152
TstzmultirangeArrayOID = 6153
DatemultirangeArrayOID = 6155
Int8multirangeArrayOID = 6157
)
type InfinityModifier int8
const (
Infinity InfinityModifier = 1
Finite InfinityModifier = 0
NegativeInfinity InfinityModifier = -Infinity
)
func (im InfinityModifier) String() string {
switch im {
case Finite:
return "finite"
case Infinity:
return "infinity"
case NegativeInfinity:
return "-infinity"
default:
return "invalid"
}
}
// PostgreSQL format codes
const (
TextFormatCode = 0
BinaryFormatCode = 1
)
// A Codec converts between Go and PostgreSQL values. A Codec must not be mutated after it is registered with a Map.
type Codec interface {
// FormatSupported returns true if the format is supported.
FormatSupported(int16) bool
// PreferredFormat returns the preferred format.
PreferredFormat() int16
// PlanEncode returns an EncodePlan for encoding value into PostgreSQL format for oid and format. If no plan can be
// found then nil is returned.
PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan
// PlanScan returns a ScanPlan for scanning a PostgreSQL value into a destination with the same type as target. If
// no plan can be found then nil is returned.
PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan
// DecodeDatabaseSQLValue returns src decoded into a value compatible with the sql.Scanner interface.
DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error)
// DecodeValue returns src decoded into its default format.
DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error)
}
type nullAssignmentError struct {
dst any
}
func (e *nullAssignmentError) Error() string {
return fmt.Sprintf("cannot assign NULL to %T", e.dst)
}
// Type represents a PostgreSQL data type. It must not be mutated after it is registered with a Map.
type Type struct {
Codec Codec
Name string
OID uint32
}
// Map is the mapping between PostgreSQL server types and Go type handling logic. It can encode values for
// transmission to a PostgreSQL server and scan received values.
type Map struct {
oidToType map[uint32]*Type
nameToType map[string]*Type
reflectTypeToName map[reflect.Type]string
oidToFormatCode map[uint32]int16
reflectTypeToType map[reflect.Type]*Type
memoizedScanPlans map[uint32]map[reflect.Type][2]ScanPlan
memoizedEncodePlans map[uint32]map[reflect.Type][2]EncodePlan
// TryWrapEncodePlanFuncs is a slice of functions that will wrap a value that cannot be encoded by the Codec. Every
// time a wrapper is found the PlanEncode method will be recursively called with the new value. This allows several layers of wrappers
// to be built up. There are default functions placed in this slice by NewMap(). In most cases these functions
// should run last. i.e. Additional functions should typically be prepended not appended.
TryWrapEncodePlanFuncs []TryWrapEncodePlanFunc
// TryWrapScanPlanFuncs is a slice of functions that will wrap a target that cannot be scanned into by the Codec. Every
// time a wrapper is found the PlanScan method will be recursively called with the new target. This allows several layers of wrappers
// to be built up. There are default functions placed in this slice by NewMap(). In most cases these functions
// should run last. i.e. Additional functions should typically be prepended not appended.
TryWrapScanPlanFuncs []TryWrapScanPlanFunc
}
func NewMap() *Map {
defaultMapInitOnce.Do(initDefaultMap)
return &Map{
oidToType: make(map[uint32]*Type),
nameToType: make(map[string]*Type),
reflectTypeToName: make(map[reflect.Type]string),
oidToFormatCode: make(map[uint32]int16),
memoizedScanPlans: make(map[uint32]map[reflect.Type][2]ScanPlan),
memoizedEncodePlans: make(map[uint32]map[reflect.Type][2]EncodePlan),
TryWrapEncodePlanFuncs: []TryWrapEncodePlanFunc{
TryWrapDerefPointerEncodePlan,
TryWrapBuiltinTypeEncodePlan,
TryWrapFindUnderlyingTypeEncodePlan,
TryWrapStructEncodePlan,
TryWrapSliceEncodePlan,
TryWrapMultiDimSliceEncodePlan,
TryWrapArrayEncodePlan,
},
TryWrapScanPlanFuncs: []TryWrapScanPlanFunc{
TryPointerPointerScanPlan,
TryWrapBuiltinTypeScanPlan,
TryFindUnderlyingTypeScanPlan,
TryWrapStructScanPlan,
TryWrapPtrSliceScanPlan,
TryWrapPtrMultiDimSliceScanPlan,
TryWrapPtrArrayScanPlan,
},
}
}
// RegisterType registers a data type with the Map. t must not be mutated after it is registered.
func (m *Map) RegisterType(t *Type) {
m.oidToType[t.OID] = t
m.nameToType[t.Name] = t
m.oidToFormatCode[t.OID] = t.Codec.PreferredFormat()
// Invalidated by type registration
m.reflectTypeToType = nil
for k := range m.memoizedScanPlans {
delete(m.memoizedScanPlans, k)
}
for k := range m.memoizedEncodePlans {
delete(m.memoizedEncodePlans, k)
}
}
// RegisterDefaultPgType registers a mapping of a Go type to a PostgreSQL type name. Typically the data type to be
// encoded or decoded is determined by the PostgreSQL OID. But if the OID of a value to be encoded or decoded is
// unknown, this additional mapping will be used by TypeForValue to determine a suitable data type.
func (m *Map) RegisterDefaultPgType(value any, name string) {
m.reflectTypeToName[reflect.TypeOf(value)] = name
// Invalidated by type registration
m.reflectTypeToType = nil
for k := range m.memoizedScanPlans {
delete(m.memoizedScanPlans, k)
}
for k := range m.memoizedEncodePlans {
delete(m.memoizedEncodePlans, k)
}
}
// TypeForOID returns the Type registered for the given OID. The returned Type must not be mutated.
func (m *Map) TypeForOID(oid uint32) (*Type, bool) {
if dt, ok := m.oidToType[oid]; ok {
return dt, true
}
dt, ok := defaultMap.oidToType[oid]
return dt, ok
}
// TypeForName returns the Type registered for the given name. The returned Type must not be mutated.
func (m *Map) TypeForName(name string) (*Type, bool) {
if dt, ok := m.nameToType[name]; ok {
return dt, true
}
dt, ok := defaultMap.nameToType[name]
return dt, ok
}
func (m *Map) buildReflectTypeToType() {
m.reflectTypeToType = make(map[reflect.Type]*Type)
for reflectType, name := range m.reflectTypeToName {
if dt, ok := m.TypeForName(name); ok {
m.reflectTypeToType[reflectType] = dt
}
}
}
// TypeForValue finds a data type suitable for v. Use RegisterType to register types that can encode and decode
// themselves. Use RegisterDefaultPgType to register that can be handled by a registered data type. The returned Type
// must not be mutated.
func (m *Map) TypeForValue(v any) (*Type, bool) {
if m.reflectTypeToType == nil {
m.buildReflectTypeToType()
}
if dt, ok := m.reflectTypeToType[reflect.TypeOf(v)]; ok {
return dt, true
}
dt, ok := defaultMap.reflectTypeToType[reflect.TypeOf(v)]
return dt, ok
}
// FormatCodeForOID returns the preferred format code for type oid. If the type is not registered it returns the text
// format code.
func (m *Map) FormatCodeForOID(oid uint32) int16 {
if fc, ok := m.oidToFormatCode[oid]; ok {
return fc
}
if fc, ok := defaultMap.oidToFormatCode[oid]; ok {
return fc
}
return TextFormatCode
}
// EncodePlan is a precompiled plan to encode a particular type into a particular OID and format.
type EncodePlan interface {
// Encode appends the encoded bytes of value to buf. If value is the SQL value NULL then append nothing and return
// (nil, nil). The caller of Encode is responsible for writing the correct NULL value or the length of the data
// written.
Encode(value any, buf []byte) (newBuf []byte, err error)
}
// ScanPlan is a precompiled plan to scan into a type of destination.
type ScanPlan interface {
// Scan scans src into target. src is only valid during the call to Scan. The ScanPlan must not retain a reference to
// src.
Scan(src []byte, target any) error
}
type scanPlanCodecSQLScanner struct {
c Codec
m *Map
oid uint32
formatCode int16
}
func (plan *scanPlanCodecSQLScanner) Scan(src []byte, dst any) error {
value, err := plan.c.DecodeDatabaseSQLValue(plan.m, plan.oid, plan.formatCode, src)
if err != nil {
return err
}
scanner := dst.(sql.Scanner)
return scanner.Scan(value)
}
type scanPlanSQLScanner struct {
formatCode int16
}
func (plan *scanPlanSQLScanner) Scan(src []byte, dst any) error {
scanner := dst.(sql.Scanner)
if src == nil {
// This is necessary because interface value []byte:nil does not equal nil:nil for the binary format path and the
// text format path would be converted to empty string.
return scanner.Scan(nil)
} else if plan.formatCode == BinaryFormatCode {
return scanner.Scan(src)
} else {
return scanner.Scan(string(src))
}
}
type scanPlanString struct{}
func (scanPlanString) Scan(src []byte, dst any) error {
if src == nil {
return fmt.Errorf("cannot scan NULL into %T", dst)
}
p := (dst).(*string)
*p = string(src)
return nil
}
type scanPlanAnyTextToBytes struct{}
func (scanPlanAnyTextToBytes) Scan(src []byte, dst any) error {
dstBuf := dst.(*[]byte)
if src == nil {
*dstBuf = nil
return nil
}
*dstBuf = make([]byte, len(src))
copy(*dstBuf, src)
return nil
}
type scanPlanFail struct {
m *Map
oid uint32
formatCode int16
}
func (plan *scanPlanFail) Scan(src []byte, dst any) error {
// If src is NULL it might be possible to scan into dst even though it is the types are not compatible. While this
// may seem to be a contrived case it can occur when selecting NULL directly. PostgreSQL assigns it the type of text.
// It would be surprising to the caller to have to cast the NULL (e.g. `select null::int`). So try to figure out a
// compatible data type for dst and scan with that.
//
// See https://github.com/jackc/pgx/issues/1326
if src == nil {
// As a horrible hack try all types to find anything that can scan into dst.
for oid := range plan.m.oidToType {
// using planScan instead of Scan or PlanScan to avoid polluting the planned scan cache.
plan := plan.m.planScan(oid, plan.formatCode, dst)
if _, ok := plan.(*scanPlanFail); !ok {
return plan.Scan(src, dst)
}
}
for oid := range defaultMap.oidToType {
if _, ok := plan.m.oidToType[oid]; !ok {
plan := plan.m.planScan(oid, plan.formatCode, dst)
if _, ok := plan.(*scanPlanFail); !ok {
return plan.Scan(src, dst)
}
}
}
}
var format string
switch plan.formatCode {
case TextFormatCode:
format = "text"
case BinaryFormatCode:
format = "binary"
default:
format = fmt.Sprintf("unknown %d", plan.formatCode)
}
var dataTypeName string
if t, ok := plan.m.TypeForOID(plan.oid); ok {
dataTypeName = t.Name
} else {
dataTypeName = "unknown type"
}
return fmt.Errorf("cannot scan %s (OID %d) in %v format into %T", dataTypeName, plan.oid, format, dst)
}
// TryWrapScanPlanFunc is a function that tries to create a wrapper plan for target. If successful it returns a plan
// that will convert the target passed to Scan and then call the next plan. nextTarget is target as it will be converted
// by plan. It must be used to find another suitable ScanPlan. When it is found SetNext must be called on plan for it
// to be usabled. ok indicates if a suitable wrapper was found.
type TryWrapScanPlanFunc func(target any) (plan WrappedScanPlanNextSetter, nextTarget any, ok bool)
type pointerPointerScanPlan struct {
dstType reflect.Type
next ScanPlan
}
func (plan *pointerPointerScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *pointerPointerScanPlan) Scan(src []byte, dst any) error {
el := reflect.ValueOf(dst).Elem()
if src == nil {
el.Set(reflect.Zero(el.Type()))
return nil
}
el.Set(reflect.New(el.Type().Elem()))
return plan.next.Scan(src, el.Interface())
}
// TryPointerPointerScanPlan handles a pointer to a pointer by setting the target to nil for SQL NULL and allocating and
// scanning for non-NULL.
func TryPointerPointerScanPlan(target any) (plan WrappedScanPlanNextSetter, nextTarget any, ok bool) {
if dstValue := reflect.ValueOf(target); dstValue.Kind() == reflect.Ptr {
elemValue := dstValue.Elem()
if elemValue.Kind() == reflect.Ptr {
plan = &pointerPointerScanPlan{dstType: dstValue.Type()}
return plan, reflect.Zero(elemValue.Type()).Interface(), true
}
}
return nil, nil, false
}
// SkipUnderlyingTypePlanner prevents PlanScan and PlanDecode from trying to use the underlying type.
type SkipUnderlyingTypePlanner interface {
SkipUnderlyingTypePlan()
}
var elemKindToPointerTypes map[reflect.Kind]reflect.Type = map[reflect.Kind]reflect.Type{
reflect.Int: reflect.TypeOf(new(int)),
reflect.Int8: reflect.TypeOf(new(int8)),
reflect.Int16: reflect.TypeOf(new(int16)),
reflect.Int32: reflect.TypeOf(new(int32)),
reflect.Int64: reflect.TypeOf(new(int64)),
reflect.Uint: reflect.TypeOf(new(uint)),
reflect.Uint8: reflect.TypeOf(new(uint8)),
reflect.Uint16: reflect.TypeOf(new(uint16)),
reflect.Uint32: reflect.TypeOf(new(uint32)),
reflect.Uint64: reflect.TypeOf(new(uint64)),
reflect.Float32: reflect.TypeOf(new(float32)),
reflect.Float64: reflect.TypeOf(new(float64)),
reflect.String: reflect.TypeOf(new(string)),
reflect.Bool: reflect.TypeOf(new(bool)),
}
type underlyingTypeScanPlan struct {
dstType reflect.Type
nextDstType reflect.Type
next ScanPlan
}
func (plan *underlyingTypeScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *underlyingTypeScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, reflect.ValueOf(dst).Convert(plan.nextDstType).Interface())
}
// TryFindUnderlyingTypeScanPlan tries to convert to a Go builtin type. e.g. If value was of type MyString and
// MyString was defined as a string then a wrapper plan would be returned that converts MyString to string.
func TryFindUnderlyingTypeScanPlan(dst any) (plan WrappedScanPlanNextSetter, nextDst any, ok bool) {
if _, ok := dst.(SkipUnderlyingTypePlanner); ok {
return nil, nil, false
}
dstValue := reflect.ValueOf(dst)
if dstValue.Kind() == reflect.Ptr {
var elemValue reflect.Value
if dstValue.IsNil() {
elemValue = reflect.New(dstValue.Type().Elem()).Elem()
} else {
elemValue = dstValue.Elem()
}
nextDstType := elemKindToPointerTypes[elemValue.Kind()]
if nextDstType == nil && elemValue.Kind() == reflect.Slice {
if elemValue.Type().Elem().Kind() == reflect.Uint8 {
var v *[]byte
nextDstType = reflect.TypeOf(v)
}
}
if nextDstType != nil && dstValue.Type() != nextDstType && dstValue.CanConvert(nextDstType) {
return &underlyingTypeScanPlan{dstType: dstValue.Type(), nextDstType: nextDstType}, dstValue.Convert(nextDstType).Interface(), true
}
}
return nil, nil, false
}
type WrappedScanPlanNextSetter interface {
SetNext(ScanPlan)
ScanPlan
}
// TryWrapBuiltinTypeScanPlan tries to wrap a builtin type with a wrapper that provides additional methods. e.g. If
// value was of type int32 then a wrapper plan would be returned that converts target to a value that implements
// Int64Scanner.
func TryWrapBuiltinTypeScanPlan(target any) (plan WrappedScanPlanNextSetter, nextDst any, ok bool) {
switch target := target.(type) {
case *int8:
return &wrapInt8ScanPlan{}, (*int8Wrapper)(target), true
case *int16:
return &wrapInt16ScanPlan{}, (*int16Wrapper)(target), true
case *int32:
return &wrapInt32ScanPlan{}, (*int32Wrapper)(target), true
case *int64:
return &wrapInt64ScanPlan{}, (*int64Wrapper)(target), true
case *int:
return &wrapIntScanPlan{}, (*intWrapper)(target), true
case *uint8:
return &wrapUint8ScanPlan{}, (*uint8Wrapper)(target), true
case *uint16:
return &wrapUint16ScanPlan{}, (*uint16Wrapper)(target), true
case *uint32:
return &wrapUint32ScanPlan{}, (*uint32Wrapper)(target), true
case *uint64:
return &wrapUint64ScanPlan{}, (*uint64Wrapper)(target), true
case *uint:
return &wrapUintScanPlan{}, (*uintWrapper)(target), true
case *float32:
return &wrapFloat32ScanPlan{}, (*float32Wrapper)(target), true
case *float64:
return &wrapFloat64ScanPlan{}, (*float64Wrapper)(target), true
case *string:
return &wrapStringScanPlan{}, (*stringWrapper)(target), true
case *time.Time:
return &wrapTimeScanPlan{}, (*timeWrapper)(target), true
case *time.Duration:
return &wrapDurationScanPlan{}, (*durationWrapper)(target), true
case *net.IPNet:
return &wrapNetIPNetScanPlan{}, (*netIPNetWrapper)(target), true
case *net.IP:
return &wrapNetIPScanPlan{}, (*netIPWrapper)(target), true
case *netip.Prefix:
return &wrapNetipPrefixScanPlan{}, (*netipPrefixWrapper)(target), true
case *netip.Addr:
return &wrapNetipAddrScanPlan{}, (*netipAddrWrapper)(target), true
case *map[string]*string:
return &wrapMapStringToPointerStringScanPlan{}, (*mapStringToPointerStringWrapper)(target), true
case *map[string]string:
return &wrapMapStringToStringScanPlan{}, (*mapStringToStringWrapper)(target), true
case *[16]byte:
return &wrapByte16ScanPlan{}, (*byte16Wrapper)(target), true
case *[]byte:
return &wrapByteSliceScanPlan{}, (*byteSliceWrapper)(target), true
}
return nil, nil, false
}
type wrapInt8ScanPlan struct {
next ScanPlan
}
func (plan *wrapInt8ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapInt8ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*int8Wrapper)(dst.(*int8)))
}
type wrapInt16ScanPlan struct {
next ScanPlan
}
func (plan *wrapInt16ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapInt16ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*int16Wrapper)(dst.(*int16)))
}
type wrapInt32ScanPlan struct {
next ScanPlan
}
func (plan *wrapInt32ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapInt32ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*int32Wrapper)(dst.(*int32)))
}
type wrapInt64ScanPlan struct {
next ScanPlan
}
func (plan *wrapInt64ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapInt64ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*int64Wrapper)(dst.(*int64)))
}
type wrapIntScanPlan struct {
next ScanPlan
}
func (plan *wrapIntScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapIntScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*intWrapper)(dst.(*int)))
}
type wrapUint8ScanPlan struct {
next ScanPlan
}
func (plan *wrapUint8ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapUint8ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*uint8Wrapper)(dst.(*uint8)))
}
type wrapUint16ScanPlan struct {
next ScanPlan
}
func (plan *wrapUint16ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapUint16ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*uint16Wrapper)(dst.(*uint16)))
}
type wrapUint32ScanPlan struct {
next ScanPlan
}
func (plan *wrapUint32ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapUint32ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*uint32Wrapper)(dst.(*uint32)))
}
type wrapUint64ScanPlan struct {
next ScanPlan
}
func (plan *wrapUint64ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapUint64ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*uint64Wrapper)(dst.(*uint64)))
}
type wrapUintScanPlan struct {
next ScanPlan
}
func (plan *wrapUintScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapUintScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*uintWrapper)(dst.(*uint)))
}
type wrapFloat32ScanPlan struct {
next ScanPlan
}
func (plan *wrapFloat32ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapFloat32ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*float32Wrapper)(dst.(*float32)))
}
type wrapFloat64ScanPlan struct {
next ScanPlan
}
func (plan *wrapFloat64ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapFloat64ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*float64Wrapper)(dst.(*float64)))
}
type wrapStringScanPlan struct {
next ScanPlan
}
func (plan *wrapStringScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapStringScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*stringWrapper)(dst.(*string)))
}
type wrapTimeScanPlan struct {
next ScanPlan
}
func (plan *wrapTimeScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapTimeScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*timeWrapper)(dst.(*time.Time)))
}
type wrapDurationScanPlan struct {
next ScanPlan
}
func (plan *wrapDurationScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapDurationScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*durationWrapper)(dst.(*time.Duration)))
}
type wrapNetIPNetScanPlan struct {
next ScanPlan
}
func (plan *wrapNetIPNetScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapNetIPNetScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*netIPNetWrapper)(dst.(*net.IPNet)))
}
type wrapNetIPScanPlan struct {
next ScanPlan
}
func (plan *wrapNetIPScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapNetIPScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*netIPWrapper)(dst.(*net.IP)))
}
type wrapNetipPrefixScanPlan struct {
next ScanPlan
}
func (plan *wrapNetipPrefixScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapNetipPrefixScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*netipPrefixWrapper)(dst.(*netip.Prefix)))
}
type wrapNetipAddrScanPlan struct {
next ScanPlan
}
func (plan *wrapNetipAddrScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapNetipAddrScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*netipAddrWrapper)(dst.(*netip.Addr)))
}
type wrapMapStringToPointerStringScanPlan struct {
next ScanPlan
}
func (plan *wrapMapStringToPointerStringScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapMapStringToPointerStringScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*mapStringToPointerStringWrapper)(dst.(*map[string]*string)))
}
type wrapMapStringToStringScanPlan struct {
next ScanPlan
}
func (plan *wrapMapStringToStringScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapMapStringToStringScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*mapStringToStringWrapper)(dst.(*map[string]string)))
}
type wrapByte16ScanPlan struct {
next ScanPlan
}
func (plan *wrapByte16ScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapByte16ScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*byte16Wrapper)(dst.(*[16]byte)))
}
type wrapByteSliceScanPlan struct {
next ScanPlan
}
func (plan *wrapByteSliceScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapByteSliceScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*byteSliceWrapper)(dst.(*[]byte)))
}
type pointerEmptyInterfaceScanPlan struct {
codec Codec
m *Map
oid uint32
formatCode int16
}
func (plan *pointerEmptyInterfaceScanPlan) Scan(src []byte, dst any) error {
value, err := plan.codec.DecodeValue(plan.m, plan.oid, plan.formatCode, src)
if err != nil {
return err
}
ptrAny := dst.(*any)
*ptrAny = value
return nil
}
// TryWrapStructPlan tries to wrap a struct with a wrapper that implements CompositeIndexGetter.
func TryWrapStructScanPlan(target any) (plan WrappedScanPlanNextSetter, nextValue any, ok bool) {
targetValue := reflect.ValueOf(target)
if targetValue.Kind() != reflect.Ptr {
return nil, nil, false
}
var targetElemValue reflect.Value
if targetValue.IsNil() {
targetElemValue = reflect.Zero(targetValue.Type().Elem())
} else {
targetElemValue = targetValue.Elem()
}
targetElemType := targetElemValue.Type()
if targetElemType.Kind() == reflect.Struct {
exportedFields := getExportedFieldValues(targetElemValue)
if len(exportedFields) == 0 {
return nil, nil, false
}
w := ptrStructWrapper{
s: target,
exportedFields: exportedFields,
}
return &wrapAnyPtrStructScanPlan{}, &w, true
}
return nil, nil, false
}
type wrapAnyPtrStructScanPlan struct {
next ScanPlan
}
func (plan *wrapAnyPtrStructScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapAnyPtrStructScanPlan) Scan(src []byte, target any) error {
w := ptrStructWrapper{
s: target,
exportedFields: getExportedFieldValues(reflect.ValueOf(target).Elem()),
}
return plan.next.Scan(src, &w)
}
// TryWrapPtrSliceScanPlan tries to wrap a pointer to a single dimension slice.
func TryWrapPtrSliceScanPlan(target any) (plan WrappedScanPlanNextSetter, nextValue any, ok bool) {
// Avoid using reflect path for common types.
switch target := target.(type) {
case *[]int16:
return &wrapPtrSliceScanPlan[int16]{}, (*FlatArray[int16])(target), true
case *[]int32:
return &wrapPtrSliceScanPlan[int32]{}, (*FlatArray[int32])(target), true
case *[]int64:
return &wrapPtrSliceScanPlan[int64]{}, (*FlatArray[int64])(target), true
case *[]float32:
return &wrapPtrSliceScanPlan[float32]{}, (*FlatArray[float32])(target), true
case *[]float64:
return &wrapPtrSliceScanPlan[float64]{}, (*FlatArray[float64])(target), true
case *[]string:
return &wrapPtrSliceScanPlan[string]{}, (*FlatArray[string])(target), true
case *[]time.Time:
return &wrapPtrSliceScanPlan[time.Time]{}, (*FlatArray[time.Time])(target), true
}
targetType := reflect.TypeOf(target)
if targetType.Kind() != reflect.Ptr {
return nil, nil, false
}
targetElemType := targetType.Elem()
if targetElemType.Kind() == reflect.Slice {
slice := reflect.New(targetElemType).Elem()
return &wrapPtrSliceReflectScanPlan{}, &anySliceArrayReflect{slice: slice}, true
}
return nil, nil, false
}
type wrapPtrSliceScanPlan[T any] struct {
next ScanPlan
}
func (plan *wrapPtrSliceScanPlan[T]) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapPtrSliceScanPlan[T]) Scan(src []byte, target any) error {
return plan.next.Scan(src, (*FlatArray[T])(target.(*[]T)))
}
type wrapPtrSliceReflectScanPlan struct {
next ScanPlan
}
func (plan *wrapPtrSliceReflectScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapPtrSliceReflectScanPlan) Scan(src []byte, target any) error {
return plan.next.Scan(src, &anySliceArrayReflect{slice: reflect.ValueOf(target).Elem()})
}
// TryWrapPtrMultiDimSliceScanPlan tries to wrap a pointer to a multi-dimension slice.
func TryWrapPtrMultiDimSliceScanPlan(target any) (plan WrappedScanPlanNextSetter, nextValue any, ok bool) {
targetValue := reflect.ValueOf(target)
if targetValue.Kind() != reflect.Ptr {
return nil, nil, false
}
targetElemValue := targetValue.Elem()
if targetElemValue.Kind() == reflect.Slice {
elemElemKind := targetElemValue.Type().Elem().Kind()
if elemElemKind == reflect.Slice {
if !isRagged(targetElemValue) {
return &wrapPtrMultiDimSliceScanPlan{}, &anyMultiDimSliceArray{slice: targetValue.Elem()}, true
}
}
}
return nil, nil, false
}
type wrapPtrMultiDimSliceScanPlan struct {
next ScanPlan
}
func (plan *wrapPtrMultiDimSliceScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapPtrMultiDimSliceScanPlan) Scan(src []byte, target any) error {
return plan.next.Scan(src, &anyMultiDimSliceArray{slice: reflect.ValueOf(target).Elem()})
}
// TryWrapPtrArrayScanPlan tries to wrap a pointer to a single dimension array.
func TryWrapPtrArrayScanPlan(target any) (plan WrappedScanPlanNextSetter, nextValue any, ok bool) {
targetValue := reflect.ValueOf(target)
if targetValue.Kind() != reflect.Ptr {
return nil, nil, false
}
targetElemValue := targetValue.Elem()
if targetElemValue.Kind() == reflect.Array {
return &wrapPtrArrayReflectScanPlan{}, &anyArrayArrayReflect{array: targetElemValue}, true
}
return nil, nil, false
}
type wrapPtrArrayReflectScanPlan struct {
next ScanPlan
}
func (plan *wrapPtrArrayReflectScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapPtrArrayReflectScanPlan) Scan(src []byte, target any) error {
return plan.next.Scan(src, &anyArrayArrayReflect{array: reflect.ValueOf(target).Elem()})
}
// PlanScan prepares a plan to scan a value into target.
func (m *Map) PlanScan(oid uint32, formatCode int16, target any) ScanPlan {
oidMemo := m.memoizedScanPlans[oid]
if oidMemo == nil {
oidMemo = make(map[reflect.Type][2]ScanPlan)
m.memoizedScanPlans[oid] = oidMemo
}
targetReflectType := reflect.TypeOf(target)
typeMemo := oidMemo[targetReflectType]
plan := typeMemo[formatCode]
if plan == nil {
plan = m.planScan(oid, formatCode, target)
typeMemo[formatCode] = plan
oidMemo[targetReflectType] = typeMemo
}
return plan
}
func (m *Map) planScan(oid uint32, formatCode int16, target any) ScanPlan {
if target == nil {
return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
}
if _, ok := target.(*UndecodedBytes); ok {
return scanPlanAnyToUndecodedBytes{}
}
switch formatCode {
case BinaryFormatCode:
switch target.(type) {
case *string:
switch oid {
case TextOID, VarcharOID:
return scanPlanString{}
}
}
case TextFormatCode:
switch target.(type) {
case *string:
return scanPlanString{}
case *[]byte:
if oid != ByteaOID {
return scanPlanAnyTextToBytes{}
}
case TextScanner:
return scanPlanTextAnyToTextScanner{}
}
}
var dt *Type
if dataType, ok := m.TypeForOID(oid); ok {
dt = dataType
} else if dataType, ok := m.TypeForValue(target); ok {
dt = dataType
oid = dt.OID // Preserve assumed OID in case we are recursively called below.
}
if dt != nil {
if plan := dt.Codec.PlanScan(m, oid, formatCode, target); plan != nil {
return plan
}
}
// This needs to happen before trying m.TryWrapScanPlanFuncs. Otherwise, a sql.Scanner would not get called if it was
// defined on a type that could be unwrapped such as `type myString string`.
//
// https://github.com/jackc/pgtype/issues/197
if _, ok := target.(sql.Scanner); ok {
if dt == nil {
return &scanPlanSQLScanner{formatCode: formatCode}
} else {
return &scanPlanCodecSQLScanner{c: dt.Codec, m: m, oid: oid, formatCode: formatCode}
}
}
for _, f := range m.TryWrapScanPlanFuncs {
if wrapperPlan, nextDst, ok := f(target); ok {
if nextPlan := m.planScan(oid, formatCode, nextDst); nextPlan != nil {
if _, failed := nextPlan.(*scanPlanFail); !failed {
wrapperPlan.SetNext(nextPlan)
return wrapperPlan
}
}
}
}
if dt != nil {
if _, ok := target.(*any); ok {
return &pointerEmptyInterfaceScanPlan{codec: dt.Codec, m: m, oid: oid, formatCode: formatCode}
}
}
return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
}
func (m *Map) Scan(oid uint32, formatCode int16, src []byte, dst any) error {
if dst == nil {
return nil
}
plan := m.PlanScan(oid, formatCode, dst)
return plan.Scan(src, dst)
}
var ErrScanTargetTypeChanged = errors.New("scan target type changed")
func codecScan(codec Codec, m *Map, oid uint32, format int16, src []byte, dst any) error {
scanPlan := codec.PlanScan(m, oid, format, dst)
if scanPlan == nil {
return fmt.Errorf("PlanScan did not find a plan")
}
return scanPlan.Scan(src, dst)
}
func codecDecodeToTextFormat(codec Codec, m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
if src == nil {
return nil, nil
}
if format == TextFormatCode {
return string(src), nil
} else {
value, err := codec.DecodeValue(m, oid, format, src)
if err != nil {
return nil, err
}
buf, err := m.Encode(oid, TextFormatCode, value, nil)
if err != nil {
return nil, err
}
return string(buf), nil
}
}
// PlanEncode returns an Encode plan for encoding value into PostgreSQL format for oid and format. If no plan can be
// found then nil is returned.
func (m *Map) PlanEncode(oid uint32, format int16, value any) EncodePlan {
oidMemo := m.memoizedEncodePlans[oid]
if oidMemo == nil {
oidMemo = make(map[reflect.Type][2]EncodePlan)
m.memoizedEncodePlans[oid] = oidMemo
}
targetReflectType := reflect.TypeOf(value)
typeMemo := oidMemo[targetReflectType]
plan := typeMemo[format]
if plan == nil {
plan = m.planEncode(oid, format, value)
typeMemo[format] = plan
oidMemo[targetReflectType] = typeMemo
}
return plan
}
func (m *Map) planEncode(oid uint32, format int16, value any) EncodePlan {
if format == TextFormatCode {
switch value.(type) {
case string:
return encodePlanStringToAnyTextFormat{}
case TextValuer:
return encodePlanTextValuerToAnyTextFormat{}
}
}
var dt *Type
if dataType, ok := m.TypeForOID(oid); ok {
dt = dataType
} else {
// If no type for the OID was found, then either it is unknowable (e.g. the simple protocol) or it is an
// unregistered type. In either case try to find the type and OID that matches the value (e.g. a []byte would be
// registered to PostgreSQL bytea).
if dataType, ok := m.TypeForValue(value); ok {
dt = dataType
oid = dt.OID // Preserve assumed OID in case we are recursively called below.
}
}
if dt != nil {
if plan := dt.Codec.PlanEncode(m, oid, format, value); plan != nil {
return plan
}
}
for _, f := range m.TryWrapEncodePlanFuncs {
if wrapperPlan, nextValue, ok := f(value); ok {
if nextPlan := m.PlanEncode(oid, format, nextValue); nextPlan != nil {
wrapperPlan.SetNext(nextPlan)
return wrapperPlan
}
}
}
if _, ok := value.(driver.Valuer); ok {
return &encodePlanDriverValuer{m: m, oid: oid, formatCode: format}
}
return nil
}
type encodePlanStringToAnyTextFormat struct{}
func (encodePlanStringToAnyTextFormat) Encode(value any, buf []byte) (newBuf []byte, err error) {
s := value.(string)
return append(buf, s...), nil
}
type encodePlanTextValuerToAnyTextFormat struct{}
func (encodePlanTextValuerToAnyTextFormat) Encode(value any, buf []byte) (newBuf []byte, err error) {
t, err := value.(TextValuer).TextValue()
if err != nil {
return nil, err
}
if !t.Valid {
return nil, nil
}
return append(buf, t.String...), nil
}
type encodePlanDriverValuer struct {
m *Map
oid uint32
formatCode int16
}
func (plan *encodePlanDriverValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
dv := value.(driver.Valuer)
if dv == nil {
return nil, nil
}
v, err := dv.Value()
if err != nil {
return nil, err
}
if v == nil {
return nil, nil
}
newBuf, err = plan.m.Encode(plan.oid, plan.formatCode, v, buf)
if err == nil {
return newBuf, nil
}
s, ok := v.(string)
if !ok {
return nil, err
}
var scannedValue any
scanErr := plan.m.Scan(plan.oid, TextFormatCode, []byte(s), &scannedValue)
if scanErr != nil {
return nil, err
}
// Prevent infinite loop. We can't encode this. See https://github.com/jackc/pgx/issues/1331.
if reflect.TypeOf(value) == reflect.TypeOf(scannedValue) {
return nil, fmt.Errorf("tried to encode %v via encoding to text and scanning but failed due to receiving same type back", value)
}
var err2 error
newBuf, err2 = plan.m.Encode(plan.oid, BinaryFormatCode, scannedValue, buf)
if err2 != nil {
return nil, err
}
return newBuf, nil
}
// TryWrapEncodePlanFunc is a function that tries to create a wrapper plan for value. If successful it returns a plan
// that will convert the value passed to Encode and then call the next plan. nextValue is value as it will be converted
// by plan. It must be used to find another suitable EncodePlan. When it is found SetNext must be called on plan for it
// to be usabled. ok indicates if a suitable wrapper was found.
type TryWrapEncodePlanFunc func(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool)
type derefPointerEncodePlan struct {
next EncodePlan
}
func (plan *derefPointerEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *derefPointerEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
ptr := reflect.ValueOf(value)
if ptr.IsNil() {
return nil, nil
}
return plan.next.Encode(ptr.Elem().Interface(), buf)
}
// TryWrapDerefPointerEncodePlan tries to dereference a pointer. e.g. If value was of type *string then a wrapper plan
// would be returned that derefences the value.
func TryWrapDerefPointerEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
if _, ok := value.(driver.Valuer); ok {
return nil, nil, false
}
if valueType := reflect.TypeOf(value); valueType != nil && valueType.Kind() == reflect.Ptr {
return &derefPointerEncodePlan{}, reflect.New(valueType.Elem()).Elem().Interface(), true
}
return nil, nil, false
}
var kindToTypes map[reflect.Kind]reflect.Type = map[reflect.Kind]reflect.Type{
reflect.Int: reflect.TypeOf(int(0)),
reflect.Int8: reflect.TypeOf(int8(0)),
reflect.Int16: reflect.TypeOf(int16(0)),
reflect.Int32: reflect.TypeOf(int32(0)),
reflect.Int64: reflect.TypeOf(int64(0)),
reflect.Uint: reflect.TypeOf(uint(0)),
reflect.Uint8: reflect.TypeOf(uint8(0)),
reflect.Uint16: reflect.TypeOf(uint16(0)),
reflect.Uint32: reflect.TypeOf(uint32(0)),
reflect.Uint64: reflect.TypeOf(uint64(0)),
reflect.Float32: reflect.TypeOf(float32(0)),
reflect.Float64: reflect.TypeOf(float64(0)),
reflect.String: reflect.TypeOf(""),
reflect.Bool: reflect.TypeOf(false),
}
var byteSliceType = reflect.TypeOf([]byte{})
type underlyingTypeEncodePlan struct {
nextValueType reflect.Type
next EncodePlan
}
func (plan *underlyingTypeEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *underlyingTypeEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(reflect.ValueOf(value).Convert(plan.nextValueType).Interface(), buf)
}
// TryWrapFindUnderlyingTypeEncodePlan tries to convert to a Go builtin type. e.g. If value was of type MyString and
// MyString was defined as a string then a wrapper plan would be returned that converts MyString to string.
func TryWrapFindUnderlyingTypeEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
if value == nil {
return nil, nil, false
}
if _, ok := value.(driver.Valuer); ok {
return nil, nil, false
}
if _, ok := value.(SkipUnderlyingTypePlanner); ok {
return nil, nil, false
}
refValue := reflect.ValueOf(value)
nextValueType := kindToTypes[refValue.Kind()]
if nextValueType != nil && refValue.Type() != nextValueType {
return &underlyingTypeEncodePlan{nextValueType: nextValueType}, refValue.Convert(nextValueType).Interface(), true
}
// []byte is a special case. It is a slice but we treat it as a scalar type. In the case of a named type like
// json.RawMessage which is defined as []byte the underlying type should be considered as []byte. But any other slice
// does not have a special underlying type.
//
// https://github.com/jackc/pgx/issues/1763
if refValue.Type() != byteSliceType && refValue.Type().AssignableTo(byteSliceType) {
return &underlyingTypeEncodePlan{nextValueType: byteSliceType}, refValue.Convert(byteSliceType).Interface(), true
}
return nil, nil, false
}
type WrappedEncodePlanNextSetter interface {
SetNext(EncodePlan)
EncodePlan
}
// TryWrapBuiltinTypeEncodePlan tries to wrap a builtin type with a wrapper that provides additional methods. e.g. If
// value was of type int32 then a wrapper plan would be returned that converts value to a type that implements
// Int64Valuer.
func TryWrapBuiltinTypeEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
if _, ok := value.(driver.Valuer); ok {
return nil, nil, false
}
switch value := value.(type) {
case int8:
return &wrapInt8EncodePlan{}, int8Wrapper(value), true
case int16:
return &wrapInt16EncodePlan{}, int16Wrapper(value), true
case int32:
return &wrapInt32EncodePlan{}, int32Wrapper(value), true
case int64:
return &wrapInt64EncodePlan{}, int64Wrapper(value), true
case int:
return &wrapIntEncodePlan{}, intWrapper(value), true
case uint8:
return &wrapUint8EncodePlan{}, uint8Wrapper(value), true
case uint16:
return &wrapUint16EncodePlan{}, uint16Wrapper(value), true
case uint32:
return &wrapUint32EncodePlan{}, uint32Wrapper(value), true
case uint64:
return &wrapUint64EncodePlan{}, uint64Wrapper(value), true
case uint:
return &wrapUintEncodePlan{}, uintWrapper(value), true
case float32:
return &wrapFloat32EncodePlan{}, float32Wrapper(value), true
case float64:
return &wrapFloat64EncodePlan{}, float64Wrapper(value), true
case string:
return &wrapStringEncodePlan{}, stringWrapper(value), true
case time.Time:
return &wrapTimeEncodePlan{}, timeWrapper(value), true
case time.Duration:
return &wrapDurationEncodePlan{}, durationWrapper(value), true
case net.IPNet:
return &wrapNetIPNetEncodePlan{}, netIPNetWrapper(value), true
case net.IP:
return &wrapNetIPEncodePlan{}, netIPWrapper(value), true
case netip.Prefix:
return &wrapNetipPrefixEncodePlan{}, netipPrefixWrapper(value), true
case netip.Addr:
return &wrapNetipAddrEncodePlan{}, netipAddrWrapper(value), true
case map[string]*string:
return &wrapMapStringToPointerStringEncodePlan{}, mapStringToPointerStringWrapper(value), true
case map[string]string:
return &wrapMapStringToStringEncodePlan{}, mapStringToStringWrapper(value), true
case [16]byte:
return &wrapByte16EncodePlan{}, byte16Wrapper(value), true
case []byte:
return &wrapByteSliceEncodePlan{}, byteSliceWrapper(value), true
case fmt.Stringer:
return &wrapFmtStringerEncodePlan{}, fmtStringerWrapper{value}, true
}
return nil, nil, false
}
type wrapInt8EncodePlan struct {
next EncodePlan
}
func (plan *wrapInt8EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapInt8EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(int8Wrapper(value.(int8)), buf)
}
type wrapInt16EncodePlan struct {
next EncodePlan
}
func (plan *wrapInt16EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapInt16EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(int16Wrapper(value.(int16)), buf)
}
type wrapInt32EncodePlan struct {
next EncodePlan
}
func (plan *wrapInt32EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapInt32EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(int32Wrapper(value.(int32)), buf)
}
type wrapInt64EncodePlan struct {
next EncodePlan
}
func (plan *wrapInt64EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapInt64EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(int64Wrapper(value.(int64)), buf)
}
type wrapIntEncodePlan struct {
next EncodePlan
}
func (plan *wrapIntEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapIntEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(intWrapper(value.(int)), buf)
}
type wrapUint8EncodePlan struct {
next EncodePlan
}
func (plan *wrapUint8EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapUint8EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(uint8Wrapper(value.(uint8)), buf)
}
type wrapUint16EncodePlan struct {
next EncodePlan
}
func (plan *wrapUint16EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapUint16EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(uint16Wrapper(value.(uint16)), buf)
}
type wrapUint32EncodePlan struct {
next EncodePlan
}
func (plan *wrapUint32EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapUint32EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(uint32Wrapper(value.(uint32)), buf)
}
type wrapUint64EncodePlan struct {
next EncodePlan
}
func (plan *wrapUint64EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapUint64EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(uint64Wrapper(value.(uint64)), buf)
}
type wrapUintEncodePlan struct {
next EncodePlan
}
func (plan *wrapUintEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapUintEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(uintWrapper(value.(uint)), buf)
}
type wrapFloat32EncodePlan struct {
next EncodePlan
}
func (plan *wrapFloat32EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapFloat32EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(float32Wrapper(value.(float32)), buf)
}
type wrapFloat64EncodePlan struct {
next EncodePlan
}
func (plan *wrapFloat64EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapFloat64EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(float64Wrapper(value.(float64)), buf)
}
type wrapStringEncodePlan struct {
next EncodePlan
}
func (plan *wrapStringEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapStringEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(stringWrapper(value.(string)), buf)
}
type wrapTimeEncodePlan struct {
next EncodePlan
}
func (plan *wrapTimeEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapTimeEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(timeWrapper(value.(time.Time)), buf)
}
type wrapDurationEncodePlan struct {
next EncodePlan
}
func (plan *wrapDurationEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapDurationEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(durationWrapper(value.(time.Duration)), buf)
}
type wrapNetIPNetEncodePlan struct {
next EncodePlan
}
func (plan *wrapNetIPNetEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapNetIPNetEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(netIPNetWrapper(value.(net.IPNet)), buf)
}
type wrapNetIPEncodePlan struct {
next EncodePlan
}
func (plan *wrapNetIPEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapNetIPEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(netIPWrapper(value.(net.IP)), buf)
}
type wrapNetipPrefixEncodePlan struct {
next EncodePlan
}
func (plan *wrapNetipPrefixEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapNetipPrefixEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(netipPrefixWrapper(value.(netip.Prefix)), buf)
}
type wrapNetipAddrEncodePlan struct {
next EncodePlan
}
func (plan *wrapNetipAddrEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapNetipAddrEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(netipAddrWrapper(value.(netip.Addr)), buf)
}
type wrapMapStringToPointerStringEncodePlan struct {
next EncodePlan
}
func (plan *wrapMapStringToPointerStringEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapMapStringToPointerStringEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(mapStringToPointerStringWrapper(value.(map[string]*string)), buf)
}
type wrapMapStringToStringEncodePlan struct {
next EncodePlan
}
func (plan *wrapMapStringToStringEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapMapStringToStringEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(mapStringToStringWrapper(value.(map[string]string)), buf)
}
type wrapByte16EncodePlan struct {
next EncodePlan
}
func (plan *wrapByte16EncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapByte16EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(byte16Wrapper(value.([16]byte)), buf)
}
type wrapByteSliceEncodePlan struct {
next EncodePlan
}
func (plan *wrapByteSliceEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapByteSliceEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(byteSliceWrapper(value.([]byte)), buf)
}
type wrapFmtStringerEncodePlan struct {
next EncodePlan
}
func (plan *wrapFmtStringerEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapFmtStringerEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(fmtStringerWrapper{value.(fmt.Stringer)}, buf)
}
// TryWrapStructPlan tries to wrap a struct with a wrapper that implements CompositeIndexGetter.
func TryWrapStructEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
if _, ok := value.(driver.Valuer); ok {
return nil, nil, false
}
if valueType := reflect.TypeOf(value); valueType != nil && valueType.Kind() == reflect.Struct {
exportedFields := getExportedFieldValues(reflect.ValueOf(value))
if len(exportedFields) == 0 {
return nil, nil, false
}
w := structWrapper{
s: value,
exportedFields: exportedFields,
}
return &wrapAnyStructEncodePlan{}, w, true
}
return nil, nil, false
}
type wrapAnyStructEncodePlan struct {
next EncodePlan
}
func (plan *wrapAnyStructEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapAnyStructEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
w := structWrapper{
s: value,
exportedFields: getExportedFieldValues(reflect.ValueOf(value)),
}
return plan.next.Encode(w, buf)
}
func getExportedFieldValues(structValue reflect.Value) []reflect.Value {
structType := structValue.Type()
exportedFields := make([]reflect.Value, 0, structValue.NumField())
for i := 0; i < structType.NumField(); i++ {
sf := structType.Field(i)
if sf.IsExported() {
exportedFields = append(exportedFields, structValue.Field(i))
}
}
return exportedFields
}
func TryWrapSliceEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
if _, ok := value.(driver.Valuer); ok {
return nil, nil, false
}
// Avoid using reflect path for common types.
switch value := value.(type) {
case []int16:
return &wrapSliceEncodePlan[int16]{}, (FlatArray[int16])(value), true
case []int32:
return &wrapSliceEncodePlan[int32]{}, (FlatArray[int32])(value), true
case []int64:
return &wrapSliceEncodePlan[int64]{}, (FlatArray[int64])(value), true
case []float32:
return &wrapSliceEncodePlan[float32]{}, (FlatArray[float32])(value), true
case []float64:
return &wrapSliceEncodePlan[float64]{}, (FlatArray[float64])(value), true
case []string:
return &wrapSliceEncodePlan[string]{}, (FlatArray[string])(value), true
case []time.Time:
return &wrapSliceEncodePlan[time.Time]{}, (FlatArray[time.Time])(value), true
}
if valueType := reflect.TypeOf(value); valueType != nil && valueType.Kind() == reflect.Slice {
w := anySliceArrayReflect{
slice: reflect.ValueOf(value),
}
return &wrapSliceEncodeReflectPlan{}, w, true
}
return nil, nil, false
}
type wrapSliceEncodePlan[T any] struct {
next EncodePlan
}
func (plan *wrapSliceEncodePlan[T]) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapSliceEncodePlan[T]) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode((FlatArray[T])(value.([]T)), buf)
}
type wrapSliceEncodeReflectPlan struct {
next EncodePlan
}
func (plan *wrapSliceEncodeReflectPlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapSliceEncodeReflectPlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
w := anySliceArrayReflect{
slice: reflect.ValueOf(value),
}
return plan.next.Encode(w, buf)
}
func TryWrapMultiDimSliceEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
if _, ok := value.(driver.Valuer); ok {
return nil, nil, false
}
sliceValue := reflect.ValueOf(value)
if sliceValue.Kind() == reflect.Slice {
valueElemType := sliceValue.Type().Elem()
if valueElemType.Kind() == reflect.Slice {
if !isRagged(sliceValue) {
w := anyMultiDimSliceArray{
slice: reflect.ValueOf(value),
}
return &wrapMultiDimSliceEncodePlan{}, &w, true
}
}
}
return nil, nil, false
}
type wrapMultiDimSliceEncodePlan struct {
next EncodePlan
}
func (plan *wrapMultiDimSliceEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapMultiDimSliceEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
w := anyMultiDimSliceArray{
slice: reflect.ValueOf(value),
}
return plan.next.Encode(&w, buf)
}
func TryWrapArrayEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
if _, ok := value.(driver.Valuer); ok {
return nil, nil, false
}
if valueType := reflect.TypeOf(value); valueType != nil && valueType.Kind() == reflect.Array {
w := anyArrayArrayReflect{
array: reflect.ValueOf(value),
}
return &wrapArrayEncodeReflectPlan{}, w, true
}
return nil, nil, false
}
type wrapArrayEncodeReflectPlan struct {
next EncodePlan
}
func (plan *wrapArrayEncodeReflectPlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapArrayEncodeReflectPlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
w := anyArrayArrayReflect{
array: reflect.ValueOf(value),
}
return plan.next.Encode(w, buf)
}
func newEncodeError(value any, m *Map, oid uint32, formatCode int16, err error) error {
var format string
switch formatCode {
case TextFormatCode:
format = "text"
case BinaryFormatCode:
format = "binary"
default:
format = fmt.Sprintf("unknown (%d)", formatCode)
}
var dataTypeName string
if t, ok := m.TypeForOID(oid); ok {
dataTypeName = t.Name
} else {
dataTypeName = "unknown type"
}
return fmt.Errorf("unable to encode %#v into %s format for %s (OID %d): %w", value, format, dataTypeName, oid, err)
}
// Encode appends the encoded bytes of value to buf. If value is the SQL value NULL then append nothing and return
// (nil, nil). The caller of Encode is responsible for writing the correct NULL value or the length of the data
// written.
func (m *Map) Encode(oid uint32, formatCode int16, value any, buf []byte) (newBuf []byte, err error) {
if value == nil {
return nil, nil
}
plan := m.PlanEncode(oid, formatCode, value)
if plan == nil {
return nil, newEncodeError(value, m, oid, formatCode, errors.New("cannot find encode plan"))
}
newBuf, err = plan.Encode(value, buf)
if err != nil {
return nil, newEncodeError(value, m, oid, formatCode, err)
}
return newBuf, nil
}
// SQLScanner returns a database/sql.Scanner for v. This is necessary for types like Array[T] and Range[T] where the
// type needs assistance from Map to implement the sql.Scanner interface. It is not necessary for types like Box that
// implement sql.Scanner directly.
//
// This uses the type of v to look up the PostgreSQL OID that v presumably came from. This means v must be registered
// with m by calling RegisterDefaultPgType.
func (m *Map) SQLScanner(v any) sql.Scanner {
if s, ok := v.(sql.Scanner); ok {
return s
}
return &sqlScannerWrapper{m: m, v: v}
}
type sqlScannerWrapper struct {
m *Map
v any
}
func (w *sqlScannerWrapper) Scan(src any) error {
t, ok := w.m.TypeForValue(w.v)
if !ok {
return fmt.Errorf("cannot convert to sql.Scanner: cannot find registered type for %T", w.v)
}
var bufSrc []byte
if src != nil {
switch src := src.(type) {
case string:
bufSrc = []byte(src)
case []byte:
bufSrc = src
default:
bufSrc = []byte(fmt.Sprint(bufSrc))
}
}
return w.m.Scan(t.OID, TextFormatCode, bufSrc, w.v)
}