jackc / pgx

PostgreSQL driver and toolkit for Go
MIT License
9.86k stars 803 forks source link

panic on scanning to slice of custom types #2033

Open mr-tron opened 1 month ago

mr-tron commented 1 month ago

Describe the bug Library panics on scanning to []CustomType

To Reproduce

package main

import (
    "context"

    "github.com/jackc/pgx/v4/pgxpool"
)

type Int64 int64
func main() {
    conn,err := pgxpool.Connect(context.Background(), "postgres://user:qwert1@localhost/tests?port=5432&application_name=subbotin_pidor")
    if err !=nil {
        panic(err)
    }
    _, err = conn.Exec(context.Background(), "CREATE TABLE IF NOT EXISTS test (id serial PRIMARY KEY, ids bigint[])")
    if err != nil {
        panic(err)
    }
    _, err = conn.Exec(context.Background(), "INSERT INTO test (ids) VALUES ($1)", []Int64{1,2,3})
    if err != nil {
        panic(err)
    }
    var ids []Int64
    err = conn.QueryRow(context.Background(), "SELECT ids FROM test WHERE id = 1").Scan(&ids)
    if err != nil {
        panic(err)
    }
    print(ids)
}

Expected behavior Printing 1, 2, 3

Actual behavior

panic: reflect.Value.Convert: value of type *[]main.Int64 cannot be converted to type *[]int64

goroutine 1 [running]:
reflect.Value.Convert({0x727320?, 0xc0002020a8?, 0x3?}, {0x81cde8, 0x7276e0})
        /home/user/sdk/go1.22.0/src/reflect/value.go:3368 +0x12c
github.com/jackc/pgtype.toInterface({0x727320?, 0xc0002020a8?, 0x6?}, {0x81cde8?, 0x7276e0?})
        /home/user/go/pkg/mod/github.com/jackc/pgtype@v1.12.0/convert.go:397 +0x46
github.com/jackc/pgtype.GetAssignToDstType({0x727320?, 0xc0002020a8?})
        /home/user/go/pkg/mod/github.com/jackc/pgtype@v1.12.0/convert.go:431 +0x2a6
github.com/jackc/pgtype.(*Int8Array).AssignTo(0xc000072e80, {0x727320, 0xc0002020a8})
        /home/user/go/pkg/mod/github.com/jackc/pgtype@v1.12.0/int8_array.go:613 +0x885
github.com/jackc/pgtype.(*scanPlanDataTypeAssignTo).Scan(0xc00007e5a0, 0xc00010abd0, 0x3f8, 0x1, {0xc0001b2336, 0x38, 0x38}, {0x727320, 0xc0002020a8})
        /home/user/go/pkg/mod/github.com/jackc/pgtype@v1.12.0/pgtype.go:590 +0x130
github.com/jackc/pgx/v4.(*connRows).Scan(0xc00021a000, {0xc000210020?, 0x1, 0xc000210020?})
        /home/user/go/pkg/mod/github.com/jackc/pgx/v4@v4.17.2/rows.go:225 +0x3fd
github.com/jackc/pgx/v4.(*connRow).Scan(0xc00021a000, {0xc000210020, 0x1, 0x1})
        /home/user/go/pkg/mod/github.com/jackc/pgx/v4@v4.17.2/rows.go:88 +0x8e
github.com/jackc/pgx/v4/pgxpool.(*poolRow).Scan(0xc0000e69e0, {0xc000210020?, 0xa87f40?, 0x796afb?})
        /home/user/go/pkg/mod/github.com/jackc/pgx/v4@v4.17.2/pgxpool/rows.go:100 +0x31
main.main()

Version

mr-tron commented 1 month ago

There is a workarround:

type Int64s []Int64

func (ids *Int64s) Scan(src interface{}) error {
    var dest pgtype.Int8Array
    err := dest.Scan(src)
    *ids = make(Int64s, len(dest.Elements))
    for i := range dest.Elements {
        (*ids)[i] = Int64(dest.Elements[i].Int)
    }
    return err
}

but I don't sure what library should panic in any cases

jackc commented 1 month ago

It works on v5.