...

Source file src/github.com/jackc/pgx/v5/pgtype/composite_test.go

Documentation: github.com/jackc/pgx/v5/pgtype

     1  package pgtype_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	pgx "github.com/jackc/pgx/v5"
     9  	"github.com/jackc/pgx/v5/pgtype"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestCompositeCodecTranscode(t *testing.T) {
    14  	skipCockroachDB(t, "Server does not support composite types (see https://github.com/cockroachdb/cockroach/issues/27792)")
    15  
    16  	defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
    17  
    18  		_, err := conn.Exec(ctx, `drop type if exists ct_test;
    19  
    20  create type ct_test as (
    21  	a text,
    22    b int4
    23  );`)
    24  		require.NoError(t, err)
    25  		defer conn.Exec(ctx, "drop type ct_test")
    26  
    27  		dt, err := conn.LoadType(ctx, "ct_test")
    28  		require.NoError(t, err)
    29  		conn.TypeMap().RegisterType(dt)
    30  
    31  		formats := []struct {
    32  			name string
    33  			code int16
    34  		}{
    35  			{name: "TextFormat", code: pgx.TextFormatCode},
    36  			{name: "BinaryFormat", code: pgx.BinaryFormatCode},
    37  		}
    38  
    39  		for _, format := range formats {
    40  			var a string
    41  			var b int32
    42  
    43  			err := conn.QueryRow(ctx, "select $1::ct_test", pgx.QueryResultFormats{format.code},
    44  				pgtype.CompositeFields{"hi", int32(42)},
    45  			).Scan(
    46  				pgtype.CompositeFields{&a, &b},
    47  			)
    48  			require.NoErrorf(t, err, "%v", format.name)
    49  			require.EqualValuesf(t, "hi", a, "%v", format.name)
    50  			require.EqualValuesf(t, 42, b, "%v", format.name)
    51  		}
    52  	})
    53  }
    54  
    55  type point3d struct {
    56  	X, Y, Z float64
    57  }
    58  
    59  func (p point3d) IsNull() bool {
    60  	return false
    61  }
    62  
    63  func (p point3d) Index(i int) any {
    64  	switch i {
    65  	case 0:
    66  		return p.X
    67  	case 1:
    68  		return p.Y
    69  	case 2:
    70  		return p.Z
    71  	default:
    72  		panic("invalid index")
    73  	}
    74  }
    75  
    76  func (p *point3d) ScanNull() error {
    77  	return fmt.Errorf("cannot scan NULL into point3d")
    78  }
    79  
    80  func (p *point3d) ScanIndex(i int) any {
    81  	switch i {
    82  	case 0:
    83  		return &p.X
    84  	case 1:
    85  		return &p.Y
    86  	case 2:
    87  		return &p.Z
    88  	default:
    89  		panic("invalid index")
    90  	}
    91  }
    92  
    93  func TestCompositeCodecTranscodeStruct(t *testing.T) {
    94  	skipCockroachDB(t, "Server does not support composite types (see https://github.com/cockroachdb/cockroach/issues/27792)")
    95  
    96  	defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
    97  
    98  		_, err := conn.Exec(ctx, `drop type if exists point3d;
    99  
   100  create type point3d as (
   101  	x float8,
   102  	y float8,
   103  	z float8
   104  );`)
   105  		require.NoError(t, err)
   106  		defer conn.Exec(ctx, "drop type point3d")
   107  
   108  		dt, err := conn.LoadType(ctx, "point3d")
   109  		require.NoError(t, err)
   110  		conn.TypeMap().RegisterType(dt)
   111  
   112  		formats := []struct {
   113  			name string
   114  			code int16
   115  		}{
   116  			{name: "TextFormat", code: pgx.TextFormatCode},
   117  			{name: "BinaryFormat", code: pgx.BinaryFormatCode},
   118  		}
   119  
   120  		for _, format := range formats {
   121  			input := point3d{X: 1, Y: 2, Z: 3}
   122  			var output point3d
   123  			err := conn.QueryRow(ctx, "select $1::point3d", pgx.QueryResultFormats{format.code}, input).Scan(&output)
   124  			require.NoErrorf(t, err, "%v", format.name)
   125  			require.Equalf(t, input, output, "%v", format.name)
   126  		}
   127  	})
   128  }
   129  
   130  func TestCompositeCodecTranscodeStructWrapper(t *testing.T) {
   131  	skipCockroachDB(t, "Server does not support composite types (see https://github.com/cockroachdb/cockroach/issues/27792)")
   132  
   133  	defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
   134  
   135  		_, err := conn.Exec(ctx, `drop type if exists point3d;
   136  
   137  create type point3d as (
   138  	x float8,
   139  	y float8,
   140  	z float8
   141  );`)
   142  		require.NoError(t, err)
   143  		defer conn.Exec(ctx, "drop type point3d")
   144  
   145  		dt, err := conn.LoadType(ctx, "point3d")
   146  		require.NoError(t, err)
   147  		conn.TypeMap().RegisterType(dt)
   148  
   149  		formats := []struct {
   150  			name string
   151  			code int16
   152  		}{
   153  			{name: "TextFormat", code: pgx.TextFormatCode},
   154  			{name: "BinaryFormat", code: pgx.BinaryFormatCode},
   155  		}
   156  
   157  		type anotherPoint struct {
   158  			X, Y, Z float64
   159  		}
   160  
   161  		for _, format := range formats {
   162  			input := anotherPoint{X: 1, Y: 2, Z: 3}
   163  			var output anotherPoint
   164  			err := conn.QueryRow(ctx, "select $1::point3d", pgx.QueryResultFormats{format.code}, input).Scan(&output)
   165  			require.NoErrorf(t, err, "%v", format.name)
   166  			require.Equalf(t, input, output, "%v", format.name)
   167  		}
   168  	})
   169  }
   170  
   171  func TestCompositeCodecDecodeValue(t *testing.T) {
   172  	skipCockroachDB(t, "Server does not support composite types (see https://github.com/cockroachdb/cockroach/issues/27792)")
   173  
   174  	defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
   175  
   176  		_, err := conn.Exec(ctx, `drop type if exists point3d;
   177  
   178  create type point3d as (
   179  	x float8,
   180  	y float8,
   181  	z float8
   182  );`)
   183  		require.NoError(t, err)
   184  		defer conn.Exec(ctx, "drop type point3d")
   185  
   186  		dt, err := conn.LoadType(ctx, "point3d")
   187  		require.NoError(t, err)
   188  		conn.TypeMap().RegisterType(dt)
   189  
   190  		formats := []struct {
   191  			name string
   192  			code int16
   193  		}{
   194  			{name: "TextFormat", code: pgx.TextFormatCode},
   195  			{name: "BinaryFormat", code: pgx.BinaryFormatCode},
   196  		}
   197  
   198  		for _, format := range formats {
   199  			rows, err := conn.Query(ctx, "select '(1,2,3)'::point3d", pgx.QueryResultFormats{format.code})
   200  			require.NoErrorf(t, err, "%v", format.name)
   201  			require.True(t, rows.Next())
   202  			values, err := rows.Values()
   203  			require.NoErrorf(t, err, "%v", format.name)
   204  			require.Lenf(t, values, 1, "%v", format.name)
   205  			require.Equalf(t, map[string]any{"x": 1.0, "y": 2.0, "z": 3.0}, values[0], "%v", format.name)
   206  			require.False(t, rows.Next())
   207  			require.NoErrorf(t, rows.Err(), "%v", format.name)
   208  		}
   209  	})
   210  }
   211  
   212  // Test for composite type from table instead of create type. Table types have system / hidden columns like tableoid,
   213  // cmax, xmax, etc. These are not included when sending or receiving composite types.
   214  //
   215  // https://github.com/jackc/pgx/issues/1576
   216  func TestCompositeCodecTranscodeStructWrapperForTable(t *testing.T) {
   217  	skipCockroachDB(t, "Server does not support composite types (see https://github.com/cockroachdb/cockroach/issues/27792)")
   218  
   219  	defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
   220  
   221  		_, err := conn.Exec(ctx, `drop table if exists point3d;
   222  
   223  create table point3d (
   224  	x float8,
   225  	y float8,
   226  	z float8
   227  );`)
   228  		require.NoError(t, err)
   229  		defer conn.Exec(ctx, "drop table point3d")
   230  
   231  		dt, err := conn.LoadType(ctx, "point3d")
   232  		require.NoError(t, err)
   233  		conn.TypeMap().RegisterType(dt)
   234  
   235  		formats := []struct {
   236  			name string
   237  			code int16
   238  		}{
   239  			{name: "TextFormat", code: pgx.TextFormatCode},
   240  			{name: "BinaryFormat", code: pgx.BinaryFormatCode},
   241  		}
   242  
   243  		type anotherPoint struct {
   244  			X, Y, Z float64
   245  		}
   246  
   247  		for _, format := range formats {
   248  			input := anotherPoint{X: 1, Y: 2, Z: 3}
   249  			var output anotherPoint
   250  			err := conn.QueryRow(ctx, "select $1::point3d", pgx.QueryResultFormats{format.code}, input).Scan(&output)
   251  			require.NoErrorf(t, err, "%v", format.name)
   252  			require.Equalf(t, input, output, "%v", format.name)
   253  		}
   254  	})
   255  }
   256  

View as plain text