Skip to content

LoadTypes always returning empty slice #2254

Description

@kosmoz

Describe the bug
It appears that LoadTypes always returns an empty slice of pgtype.Types, even if err is nil.
Loading the same types individually works.

This leads to some errors when using arrays with enum types.

To Reproduce
Steps to reproduce the behavior:

package main

import (
	"context"
	"fmt"

	"github.com/jackc/pgx/v5"
)

type Color string

type HasColor struct {
	Color  Color   `db:"color"`
	Colors []Color `db:"colors"`
}

func main() {
	Works()
	DoesntWork()
}

func Works() {
	conn := InitConn()
	defer conn.Close(context.Background())
	InitDB(conn)

	for _, s := range []string{"COLOR", "_COLOR"} {
		t, err := conn.LoadType(context.Background(), s)
		if err != nil {
			panic(err)
		} else {
			fmt.Println(t)
		}
		conn.TypeMap().RegisterType(t)
	}

	RunTest(conn)
}

func DoesntWork() {
	conn := InitConn()
	defer conn.Close(context.Background())
	InitDB(conn)

	types, err := conn.LoadTypes(context.Background(), []string{"COLOR", "_COLOR"})
	if err != nil {
		panic(err)
	} else {
		// types is empty!
		fmt.Println(types)
	}

	conn.TypeMap().RegisterTypes(types)

	// Doesn't work:
	//   can't scan into dest[0]: cannot scan unknown type (OID 16389) in text format into *[]main.Color
	RunTest(conn)
}

func InitConn() *pgx.Conn {
	conn, err := pgx.Connect(context.Background(), "postgres://local:local@localhost:5432/local")
	if err != nil {
		panic(err)
	}
	return conn
}

func InitDB(conn *pgx.Conn) {
	_, err := conn.Exec(context.Background(), `
		CREATE TYPE COLOR AS ENUM ('red', 'green', 'blue');
		CREATE TABLE HasColor (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), color COLOR, colors COLOR[]);
		INSERT INTO HasColor (color, colors) VALUES ('red', '{green}')
	`)
	if err != nil {
		fmt.Println(err)
	}
}

func RunTest(conn *pgx.Conn) {
	var result HasColor

	err := conn.QueryRow(context.Background(), "select color from HasColor").Scan(&result.Color)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(result)
	}

	err = conn.QueryRow(context.Background(), "select colors from HasColor").Scan(&result.Colors)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(result)
	}
}

Please run your example with the race detector enabled. For example, go run -race main.go or go test -race.

Expected behavior
LoadTypes should work the same as for ... { LoadType ... }

Actual behavior
Output of above program:

ERROR: type "color" already exists (SQLSTATE 42710)
&{0xc00007a318 COLOR 16386}
&{0xc00007a320 _COLOR 16385}
{red []}
{red [green]}
ERROR: type "color" already exists (SQLSTATE 42710)
[]
{red []}
can't scan into dest[0]: cannot scan unknown type (OID 16385) in text format into *[]main.Color

Note, that the types array is empty and even though the simple enum can be scanned, the enum array gives an error.

Version

  • Go: go version go1.23.6 linux/amd64
  • PostgreSQL: PostgreSQL 17.2 on x86_64-pc-linux-musl, compiled by gcc (Alpine 14.2.0) 14.2.0, 64-bit
  • pgx: github.com/jackc/pgx/v5 v5.7.2

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions