mirror of https://github.com/jackc/pgx.git
248 lines
6.1 KiB
Go
248 lines
6.1 KiB
Go
package pgtype_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
pgx "github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestCompositeCodecTranscode(t *testing.T) {
|
|
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
|
|
|
|
_, err := conn.Exec(ctx, `drop type if exists ct_test;
|
|
|
|
create type ct_test as (
|
|
a text,
|
|
b int4
|
|
);`)
|
|
require.NoError(t, err)
|
|
defer conn.Exec(ctx, "drop type ct_test")
|
|
|
|
dt, err := conn.LoadType(ctx, "ct_test")
|
|
require.NoError(t, err)
|
|
conn.TypeMap().RegisterType(dt)
|
|
|
|
formats := []struct {
|
|
name string
|
|
code int16
|
|
}{
|
|
{name: "TextFormat", code: pgx.TextFormatCode},
|
|
{name: "BinaryFormat", code: pgx.BinaryFormatCode},
|
|
}
|
|
|
|
for _, format := range formats {
|
|
var a string
|
|
var b int32
|
|
|
|
err := conn.QueryRow(ctx, "select $1::ct_test", pgx.QueryResultFormats{format.code},
|
|
pgtype.CompositeFields{"hi", int32(42)},
|
|
).Scan(
|
|
pgtype.CompositeFields{&a, &b},
|
|
)
|
|
require.NoErrorf(t, err, "%v", format.name)
|
|
require.EqualValuesf(t, "hi", a, "%v", format.name)
|
|
require.EqualValuesf(t, 42, b, "%v", format.name)
|
|
}
|
|
})
|
|
}
|
|
|
|
type point3d struct {
|
|
X, Y, Z float64
|
|
}
|
|
|
|
func (p point3d) IsNull() bool {
|
|
return false
|
|
}
|
|
|
|
func (p point3d) Index(i int) any {
|
|
switch i {
|
|
case 0:
|
|
return p.X
|
|
case 1:
|
|
return p.Y
|
|
case 2:
|
|
return p.Z
|
|
default:
|
|
panic("invalid index")
|
|
}
|
|
}
|
|
|
|
func (p *point3d) ScanNull() error {
|
|
return fmt.Errorf("cannot scan NULL into point3d")
|
|
}
|
|
|
|
func (p *point3d) ScanIndex(i int) any {
|
|
switch i {
|
|
case 0:
|
|
return &p.X
|
|
case 1:
|
|
return &p.Y
|
|
case 2:
|
|
return &p.Z
|
|
default:
|
|
panic("invalid index")
|
|
}
|
|
}
|
|
|
|
func TestCompositeCodecTranscodeStruct(t *testing.T) {
|
|
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
|
|
|
|
_, err := conn.Exec(ctx, `drop type if exists point3d;
|
|
|
|
create type point3d as (
|
|
x float8,
|
|
y float8,
|
|
z float8
|
|
);`)
|
|
require.NoError(t, err)
|
|
defer conn.Exec(ctx, "drop type point3d")
|
|
|
|
dt, err := conn.LoadType(ctx, "point3d")
|
|
require.NoError(t, err)
|
|
conn.TypeMap().RegisterType(dt)
|
|
|
|
formats := []struct {
|
|
name string
|
|
code int16
|
|
}{
|
|
{name: "TextFormat", code: pgx.TextFormatCode},
|
|
{name: "BinaryFormat", code: pgx.BinaryFormatCode},
|
|
}
|
|
|
|
for _, format := range formats {
|
|
input := point3d{X: 1, Y: 2, Z: 3}
|
|
var output point3d
|
|
err := conn.QueryRow(ctx, "select $1::point3d", pgx.QueryResultFormats{format.code}, input).Scan(&output)
|
|
require.NoErrorf(t, err, "%v", format.name)
|
|
require.Equalf(t, input, output, "%v", format.name)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCompositeCodecTranscodeStructWrapper(t *testing.T) {
|
|
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
|
|
|
|
_, err := conn.Exec(ctx, `drop type if exists point3d;
|
|
|
|
create type point3d as (
|
|
x float8,
|
|
y float8,
|
|
z float8
|
|
);`)
|
|
require.NoError(t, err)
|
|
defer conn.Exec(ctx, "drop type point3d")
|
|
|
|
dt, err := conn.LoadType(ctx, "point3d")
|
|
require.NoError(t, err)
|
|
conn.TypeMap().RegisterType(dt)
|
|
|
|
formats := []struct {
|
|
name string
|
|
code int16
|
|
}{
|
|
{name: "TextFormat", code: pgx.TextFormatCode},
|
|
{name: "BinaryFormat", code: pgx.BinaryFormatCode},
|
|
}
|
|
|
|
type anotherPoint struct {
|
|
X, Y, Z float64
|
|
}
|
|
|
|
for _, format := range formats {
|
|
input := anotherPoint{X: 1, Y: 2, Z: 3}
|
|
var output anotherPoint
|
|
err := conn.QueryRow(ctx, "select $1::point3d", pgx.QueryResultFormats{format.code}, input).Scan(&output)
|
|
require.NoErrorf(t, err, "%v", format.name)
|
|
require.Equalf(t, input, output, "%v", format.name)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCompositeCodecDecodeValue(t *testing.T) {
|
|
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
|
|
|
|
_, err := conn.Exec(ctx, `drop type if exists point3d;
|
|
|
|
create type point3d as (
|
|
x float8,
|
|
y float8,
|
|
z float8
|
|
);`)
|
|
require.NoError(t, err)
|
|
defer conn.Exec(ctx, "drop type point3d")
|
|
|
|
dt, err := conn.LoadType(ctx, "point3d")
|
|
require.NoError(t, err)
|
|
conn.TypeMap().RegisterType(dt)
|
|
|
|
formats := []struct {
|
|
name string
|
|
code int16
|
|
}{
|
|
{name: "TextFormat", code: pgx.TextFormatCode},
|
|
{name: "BinaryFormat", code: pgx.BinaryFormatCode},
|
|
}
|
|
|
|
for _, format := range formats {
|
|
rows, err := conn.Query(ctx, "select '(1,2,3)'::point3d", pgx.QueryResultFormats{format.code})
|
|
require.NoErrorf(t, err, "%v", format.name)
|
|
require.True(t, rows.Next())
|
|
values, err := rows.Values()
|
|
require.NoErrorf(t, err, "%v", format.name)
|
|
require.Lenf(t, values, 1, "%v", format.name)
|
|
require.Equalf(t, map[string]any{"x": 1.0, "y": 2.0, "z": 3.0}, values[0], "%v", format.name)
|
|
require.False(t, rows.Next())
|
|
require.NoErrorf(t, rows.Err(), "%v", format.name)
|
|
}
|
|
})
|
|
}
|
|
|
|
// Test for composite type from table instead of create type. Table types have system / hidden columns like tableoid,
|
|
// cmax, xmax, etc. These are not included when sending or receiving composite types.
|
|
//
|
|
// https://github.com/jackc/pgx/issues/1576
|
|
func TestCompositeCodecTranscodeStructWrapperForTable(t *testing.T) {
|
|
skipCockroachDB(t, "Server does not support composite types from table definitions")
|
|
|
|
defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
|
|
|
|
_, err := conn.Exec(ctx, `drop table if exists point3d;
|
|
|
|
create table point3d (
|
|
x float8,
|
|
y float8,
|
|
z float8
|
|
);`)
|
|
require.NoError(t, err)
|
|
defer conn.Exec(ctx, "drop table point3d")
|
|
|
|
dt, err := conn.LoadType(ctx, "point3d")
|
|
require.NoError(t, err)
|
|
conn.TypeMap().RegisterType(dt)
|
|
|
|
formats := []struct {
|
|
name string
|
|
code int16
|
|
}{
|
|
{name: "TextFormat", code: pgx.TextFormatCode},
|
|
{name: "BinaryFormat", code: pgx.BinaryFormatCode},
|
|
}
|
|
|
|
type anotherPoint struct {
|
|
X, Y, Z float64
|
|
}
|
|
|
|
for _, format := range formats {
|
|
input := anotherPoint{X: 1, Y: 2, Z: 3}
|
|
var output anotherPoint
|
|
err := conn.QueryRow(ctx, "select $1::point3d", pgx.QueryResultFormats{format.code}, input).Scan(&output)
|
|
require.NoErrorf(t, err, "%v", format.name)
|
|
require.Equalf(t, input, output, "%v", format.name)
|
|
}
|
|
})
|
|
}
|