mirror of https://github.com/jackc/pgx.git
parent
11fa083a0d
commit
f42af35884
|
@ -126,6 +126,29 @@ func TestArrayCodecAnySlice(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// https://github.com/jackc/pgx/issues/1442
|
||||
func TestArrayCodecAnyArray(t *testing.T) {
|
||||
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
|
||||
type _point3 [3]float32
|
||||
|
||||
for i, tt := range []struct {
|
||||
expected any
|
||||
}{
|
||||
{_point3{0, 0, 0}},
|
||||
{_point3{1, 2, 3}},
|
||||
} {
|
||||
var actual _point3
|
||||
err := conn.QueryRow(
|
||||
ctx,
|
||||
"select $1::float4[]",
|
||||
tt.expected,
|
||||
).Scan(&actual)
|
||||
assert.NoErrorf(t, err, "%d", i)
|
||||
assert.Equalf(t, tt.expected, actual, "%d", i)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/jackc/pgx/issues/1273#issuecomment-1218262703
|
||||
func TestArrayCodecSliceArgConversion(t *testing.T) {
|
||||
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
|
||||
|
|
|
@ -910,3 +910,43 @@ func (a *anyMultiDimSliceArray) ScanIndexType() any {
|
|||
}
|
||||
return reflect.New(lowestSliceType.Elem()).Interface()
|
||||
}
|
||||
|
||||
type anyArrayArrayReflect struct {
|
||||
array reflect.Value
|
||||
}
|
||||
|
||||
func (a anyArrayArrayReflect) Dimensions() []ArrayDimension {
|
||||
return []ArrayDimension{{Length: int32(a.array.Len()), LowerBound: 1}}
|
||||
}
|
||||
|
||||
func (a anyArrayArrayReflect) Index(i int) any {
|
||||
return a.array.Index(i).Interface()
|
||||
}
|
||||
|
||||
func (a anyArrayArrayReflect) IndexType() any {
|
||||
return reflect.New(a.array.Type().Elem()).Elem().Interface()
|
||||
}
|
||||
|
||||
func (a *anyArrayArrayReflect) SetDimensions(dimensions []ArrayDimension) error {
|
||||
if dimensions == nil {
|
||||
return fmt.Errorf("anyArrayArrayReflect: cannot scan NULL into %v", a.array.Type().String())
|
||||
}
|
||||
|
||||
if len(dimensions) != 1 {
|
||||
return fmt.Errorf("anyArrayArrayReflect: cannot scan multi-dimensional array into %v", a.array.Type().String())
|
||||
}
|
||||
|
||||
if int(dimensions[0].Length) != a.array.Len() {
|
||||
return fmt.Errorf("anyArrayArrayReflect: cannot scan array with length %v into %v", dimensions[0].Length, a.array.Type().String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *anyArrayArrayReflect) ScanIndex(i int) any {
|
||||
return a.array.Index(i).Addr().Interface()
|
||||
}
|
||||
|
||||
func (a *anyArrayArrayReflect) ScanIndexType() any {
|
||||
return reflect.New(a.array.Type().Elem()).Interface()
|
||||
}
|
||||
|
|
|
@ -223,6 +223,7 @@ func NewMap() *Map {
|
|||
TryWrapStructEncodePlan,
|
||||
TryWrapSliceEncodePlan,
|
||||
TryWrapMultiDimSliceEncodePlan,
|
||||
TryWrapArrayEncodePlan,
|
||||
},
|
||||
|
||||
TryWrapScanPlanFuncs: []TryWrapScanPlanFunc{
|
||||
|
@ -232,6 +233,7 @@ func NewMap() *Map {
|
|||
TryWrapStructScanPlan,
|
||||
TryWrapPtrSliceScanPlan,
|
||||
TryWrapPtrMultiDimSliceScanPlan,
|
||||
TryWrapPtrArrayScanPlan,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1139,6 +1141,31 @@ 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]
|
||||
|
@ -1941,6 +1968,35 @@ func (plan *wrapMultiDimSliceEncodePlan) Encode(value any, buf []byte) (newBuf [
|
|||
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 {
|
||||
|
|
Loading…
Reference in New Issue