pgx icon indicating copy to clipboard operation
pgx copied to clipboard

CopyFrom with null schema gives zero-length delimited identifier error

Open joescharf opened this issue 1 year ago • 2 comments

Describe the bug Turns out it's a minor thing but tripped me up for a bit. If you send a null schema into pgx.Identifier like so:

copyCount, err := dstConn.CopyFrom(ctx, pgx.Identifier{"", "dstTable"}, columnNames, pgx.CopyFromRows(filteredRows[0:1]))

then Identifier.Sanitize() will return "\"\".\"dst_table\""

and you'll end up with the error: "zero-length delimited identifier at or near \"\"\"\""

Identifier.Sanitize() should probably check for parts[0] == ""

Maybe it should also ensure len(parts) <= 2

To Reproduce Runnable example:

package main

import (
	"context"
	"log"
	"os"

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

// Sample code to demonstrate the bug
//
// Returns:
// (base) ➜  copyfrombug gor .
// 2024/01/11 12:00:29 copyCount 1
// 2024/01/11 12:00:29 copyfrom errstatement description failed: ERROR: zero-length delimited identifier at or near """" (SQLSTATE 42601)
// exit status 1

func main() {
	conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close(context.Background())

	_, err = conn.Exec(context.Background(), "DROP TABLE IF EXISTS copyfrombug")
	if err != nil {
		log.Fatal("drop table", err)
	}
	_, err = conn.Exec(context.Background(), "CREATE TABLE copyfrombug(id serial primary key, name text)")
	if err != nil {
		log.Fatal(err)
	}

	// WORKS
	inputRows := [][]any{
		{int16(1), "abc"},
	}
	// IDENT IS JUST THE TABLE NAME
	ident := pgx.Identifier{"copyfrombug"}
	copyCount, err := conn.CopyFrom(context.Background(), ident, []string{"id", "name"}, pgx.CopyFromRows(inputRows))
	if err != nil {
		log.Fatal("copyfrom err", err)
	}
	log.Println("copyCount", copyCount)

	// DOES NOT WORK
	inputRows = [][]any{
		{int16(2), "def"},
	}
	// IDENT IS THE SCHEMA(null) AND TABLE NAME
	// statement description failed: ERROR: zero-length delimited identifier at or near """" (SQLSTATE 42601)
	ident = pgx.Identifier{"", "copyfrombug"}
	copyCount, err = conn.CopyFrom(context.Background(), ident, []string{"id", "name"}, pgx.CopyFromRows(inputRows))
	if err != nil {
		log.Fatal("copyfrom err", err)
	}
	log.Println("copyCount", copyCount)
}

Version go 1.21.6 pgx 5.4.3

Additional Thanks for the great library!

joescharf avatar Jan 11 '24 19:01 joescharf

Identifier.Sanitize() should probably check for parts[0] == ""

Maybe it should also ensure len(parts) <= 2

Sanitize doesn't return an error so there is really nothing that can be done about length. As far as checking for "", again there is no error return. I suppose "" could be filtered out. Not sure if that would just be hiding an application bug though.

jackc avatar Jan 13 '24 15:01 jackc

Maybe just a note in the docs could suffice.

joescharf avatar Jan 14 '24 17:01 joescharf