Skip to content

Commit

Permalink
Improve CopyFrom auto-conversion of text-ish values
Browse files Browse the repository at this point in the history
CopyFrom requires that all values are encoded in the binary format. It
already tried to parse strings to values that can then be encoded into
the binary format. But it didn't handle types that can be encoded as
text and then parsed and converted to binary. It now does.
  • Loading branch information
jackc committed Feb 3, 2024
1 parent 7b5fcac commit 34da2fe
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
34 changes: 34 additions & 0 deletions copy_from_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,40 @@ func TestConnCopyFromAutomaticStringConversion(t *testing.T) {
ensureConnValid(t, conn)
}

// https://github.com/jackc/pgx/discussions/1891
func TestConnCopyFromAutomaticStringConversionArray(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()

conn := mustConnectString(t, os.Getenv("PGX_TEST_DATABASE"))
defer closeConn(t, conn)

mustExec(t, conn, `create temporary table foo(
a numeric[]
)`)

inputRows := [][]interface{}{
{[]string{"42"}},
{[]string{"7"}},
{[]string{"8", "9"}},
{[][]string{{"10", "11"}, {"12", "13"}}},
}

copyCount, err := conn.CopyFrom(ctx, pgx.Identifier{"foo"}, []string{"a"}, pgx.CopyFromRows(inputRows))
require.NoError(t, err)
require.EqualValues(t, len(inputRows), copyCount)

// Test reads as int64 and flattened array for simplicity.
rows, _ := conn.Query(ctx, "select * from foo")
nums, err := pgx.CollectRows(rows, pgx.RowTo[[]int64])
require.NoError(t, err)
require.Equal(t, [][]int64{{42}, {7}, {8, 9}, {10, 11, 12, 13}}, nums)

ensureConnValid(t, conn)
}

func TestCopyFromFunc(t *testing.T) {
t.Parallel()

Expand Down
6 changes: 5 additions & 1 deletion values.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ func encodeCopyValue(m *pgtype.Map, buf []byte, oid uint32, arg any) ([]byte, er
func tryScanStringCopyValueThenEncode(m *pgtype.Map, buf []byte, oid uint32, arg any) ([]byte, error) {
s, ok := arg.(string)
if !ok {
return nil, errors.New("not a string")
textBuf, err := m.Encode(oid, TextFormatCode, arg, nil)
if err != nil {
return nil, errors.New("not a string and cannot be encoded as text")
}
s = string(textBuf)
}

var v any
Expand Down

0 comments on commit 34da2fe

Please sign in to comment.