...

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

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

     1  package pgtype_test
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"database/sql/driver"
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"net"
    11  	"os"
    12  	"regexp"
    13  	"strconv"
    14  	"testing"
    15  
    16  	"github.com/jackc/pgx/v5"
    17  	"github.com/jackc/pgx/v5/pgtype"
    18  	"github.com/jackc/pgx/v5/pgxtest"
    19  	_ "github.com/jackc/pgx/v5/stdlib"
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  var defaultConnTestRunner pgxtest.ConnTestRunner
    25  
    26  func init() {
    27  	defaultConnTestRunner = pgxtest.DefaultConnTestRunner()
    28  	defaultConnTestRunner.CreateConfig = func(ctx context.Context, t testing.TB) *pgx.ConnConfig {
    29  		config, err := pgx.ParseConfig(os.Getenv("PGX_TEST_DATABASE"))
    30  		require.NoError(t, err)
    31  		return config
    32  	}
    33  }
    34  
    35  // Test for renamed types
    36  type _string string
    37  type _bool bool
    38  type _uint8 uint8
    39  type _int8 int8
    40  type _int16 int16
    41  type _int16Slice []int16
    42  type _int32Slice []int32
    43  type _int64Slice []int64
    44  type _float32Slice []float32
    45  type _float64Slice []float64
    46  type _byteSlice []byte
    47  
    48  // unregisteredOID represents an actual type that is not registered. Cannot use 0 because that represents that the type
    49  // is not known (e.g. when using the simple protocol).
    50  const unregisteredOID = uint32(1)
    51  
    52  func mustParseInet(t testing.TB, s string) *net.IPNet {
    53  	ip, ipnet, err := net.ParseCIDR(s)
    54  	if err == nil {
    55  		if ipv4 := ip.To4(); ipv4 != nil {
    56  			ipnet.IP = ipv4
    57  		} else {
    58  			ipnet.IP = ip
    59  		}
    60  		return ipnet
    61  	}
    62  
    63  	// May be bare IP address.
    64  	//
    65  	ip = net.ParseIP(s)
    66  	if ip == nil {
    67  		t.Fatal(errors.New("unable to parse inet address"))
    68  	}
    69  	ipnet = &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)}
    70  	if ipv4 := ip.To4(); ipv4 != nil {
    71  		ipnet.IP = ipv4
    72  		ipnet.Mask = net.CIDRMask(32, 32)
    73  	}
    74  	return ipnet
    75  }
    76  
    77  func mustParseMacaddr(t testing.TB, s string) net.HardwareAddr {
    78  	addr, err := net.ParseMAC(s)
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  
    83  	return addr
    84  }
    85  
    86  func skipCockroachDB(t testing.TB, msg string) {
    87  	conn, err := pgx.Connect(context.Background(), os.Getenv("PGX_TEST_DATABASE"))
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	defer conn.Close(context.Background())
    92  
    93  	if conn.PgConn().ParameterStatus("crdb_version") != "" {
    94  		t.Skip(msg)
    95  	}
    96  }
    97  
    98  func skipPostgreSQLVersionLessThan(t testing.TB, minVersion int64) {
    99  	conn, err := pgx.Connect(context.Background(), os.Getenv("PGX_TEST_DATABASE"))
   100  	if err != nil {
   101  		t.Fatal(err)
   102  	}
   103  	defer conn.Close(context.Background())
   104  
   105  	serverVersionStr := conn.PgConn().ParameterStatus("server_version")
   106  	serverVersionStr = regexp.MustCompile(`^[0-9]+`).FindString(serverVersionStr)
   107  	// if not PostgreSQL do nothing
   108  	if serverVersionStr == "" {
   109  		return
   110  	}
   111  
   112  	serverVersion, err := strconv.ParseInt(serverVersionStr, 10, 64)
   113  	require.NoError(t, err)
   114  
   115  	if serverVersion < minVersion {
   116  		t.Skipf("Test requires PostgreSQL v%d+", minVersion)
   117  	}
   118  }
   119  
   120  // sqlScannerFunc lets an arbitrary function be used as a sql.Scanner.
   121  type sqlScannerFunc func(src any) error
   122  
   123  func (f sqlScannerFunc) Scan(src any) error {
   124  	return f(src)
   125  }
   126  
   127  // driverValuerFunc lets an arbitrary function be used as a driver.Valuer.
   128  type driverValuerFunc func() (driver.Value, error)
   129  
   130  func (f driverValuerFunc) Value() (driver.Value, error) {
   131  	return f()
   132  }
   133  
   134  func TestMapScanNilIsNoOp(t *testing.T) {
   135  	m := pgtype.NewMap()
   136  
   137  	err := m.Scan(pgtype.TextOID, pgx.TextFormatCode, []byte("foo"), nil)
   138  	assert.NoError(t, err)
   139  }
   140  
   141  func TestMapScanTextFormatInterfacePtr(t *testing.T) {
   142  	m := pgtype.NewMap()
   143  	var got any
   144  	err := m.Scan(pgtype.TextOID, pgx.TextFormatCode, []byte("foo"), &got)
   145  	require.NoError(t, err)
   146  	assert.Equal(t, "foo", got)
   147  }
   148  
   149  func TestMapScanTextFormatNonByteaIntoByteSlice(t *testing.T) {
   150  	m := pgtype.NewMap()
   151  	var got []byte
   152  	err := m.Scan(pgtype.JSONBOID, pgx.TextFormatCode, []byte("{}"), &got)
   153  	require.NoError(t, err)
   154  	assert.Equal(t, []byte("{}"), got)
   155  }
   156  
   157  func TestMapScanBinaryFormatInterfacePtr(t *testing.T) {
   158  	m := pgtype.NewMap()
   159  	var got any
   160  	err := m.Scan(pgtype.TextOID, pgx.BinaryFormatCode, []byte("foo"), &got)
   161  	require.NoError(t, err)
   162  	assert.Equal(t, "foo", got)
   163  }
   164  
   165  func TestMapScanUnknownOIDToStringsAndBytes(t *testing.T) {
   166  	unknownOID := uint32(999999)
   167  	srcBuf := []byte("foo")
   168  	m := pgtype.NewMap()
   169  
   170  	var s string
   171  	err := m.Scan(unknownOID, pgx.TextFormatCode, srcBuf, &s)
   172  	assert.NoError(t, err)
   173  	assert.Equal(t, "foo", s)
   174  
   175  	var rs _string
   176  	err = m.Scan(unknownOID, pgx.TextFormatCode, srcBuf, &rs)
   177  	assert.NoError(t, err)
   178  	assert.Equal(t, "foo", string(rs))
   179  
   180  	var b []byte
   181  	err = m.Scan(unknownOID, pgx.TextFormatCode, srcBuf, &b)
   182  	assert.NoError(t, err)
   183  	assert.Equal(t, []byte("foo"), b)
   184  
   185  	var rb _byteSlice
   186  	err = m.Scan(unknownOID, pgx.TextFormatCode, srcBuf, &rb)
   187  	assert.NoError(t, err)
   188  	assert.Equal(t, []byte("foo"), []byte(rb))
   189  }
   190  
   191  func TestMapScanPointerToNilStructDoesNotCrash(t *testing.T) {
   192  	m := pgtype.NewMap()
   193  
   194  	type myStruct struct{}
   195  	var p *myStruct
   196  	err := m.Scan(0, pgx.TextFormatCode, []byte("(foo,bar)"), &p)
   197  	require.NotNil(t, err)
   198  }
   199  
   200  func TestMapScanUnknownOIDTextFormat(t *testing.T) {
   201  	m := pgtype.NewMap()
   202  
   203  	var n int32
   204  	err := m.Scan(0, pgx.TextFormatCode, []byte("123"), &n)
   205  	assert.NoError(t, err)
   206  	assert.EqualValues(t, 123, n)
   207  }
   208  
   209  func TestMapScanUnknownOIDIntoSQLScanner(t *testing.T) {
   210  	m := pgtype.NewMap()
   211  
   212  	var s sql.NullString
   213  	err := m.Scan(0, pgx.TextFormatCode, []byte(nil), &s)
   214  	assert.NoError(t, err)
   215  	assert.Equal(t, "", s.String)
   216  	assert.False(t, s.Valid)
   217  }
   218  
   219  type scannerString string
   220  
   221  func (ss *scannerString) Scan(v any) error {
   222  	*ss = scannerString("scanned")
   223  	return nil
   224  }
   225  
   226  // https://github.com/jackc/pgtype/issues/197
   227  func TestMapScanUnregisteredOIDIntoRenamedStringSQLScanner(t *testing.T) {
   228  	m := pgtype.NewMap()
   229  
   230  	var s scannerString
   231  	err := m.Scan(unregisteredOID, pgx.TextFormatCode, []byte(nil), &s)
   232  	assert.NoError(t, err)
   233  	assert.Equal(t, "scanned", string(s))
   234  }
   235  
   236  type pgCustomInt int64
   237  
   238  func (ci *pgCustomInt) Scan(src interface{}) error {
   239  	*ci = pgCustomInt(src.(int64))
   240  	return nil
   241  }
   242  
   243  func TestScanPlanBinaryInt32ScanScanner(t *testing.T) {
   244  	m := pgtype.NewMap()
   245  	src := []byte{0, 42}
   246  	var v pgCustomInt
   247  
   248  	plan := m.PlanScan(pgtype.Int2OID, pgtype.BinaryFormatCode, &v)
   249  	err := plan.Scan(src, &v)
   250  	require.NoError(t, err)
   251  	require.EqualValues(t, 42, v)
   252  
   253  	ptr := new(pgCustomInt)
   254  	plan = m.PlanScan(pgtype.Int2OID, pgtype.BinaryFormatCode, &ptr)
   255  	err = plan.Scan(src, &ptr)
   256  	require.NoError(t, err)
   257  	require.EqualValues(t, 42, *ptr)
   258  
   259  	ptr = new(pgCustomInt)
   260  	err = plan.Scan(nil, &ptr)
   261  	require.NoError(t, err)
   262  	assert.Nil(t, ptr)
   263  
   264  	ptr = nil
   265  	plan = m.PlanScan(pgtype.Int2OID, pgtype.BinaryFormatCode, &ptr)
   266  	err = plan.Scan(src, &ptr)
   267  	require.NoError(t, err)
   268  	require.EqualValues(t, 42, *ptr)
   269  
   270  	ptr = nil
   271  	plan = m.PlanScan(pgtype.Int2OID, pgtype.BinaryFormatCode, &ptr)
   272  	err = plan.Scan(nil, &ptr)
   273  	require.NoError(t, err)
   274  	assert.Nil(t, ptr)
   275  }
   276  
   277  // Test for https://github.com/jackc/pgtype/issues/164
   278  func TestScanPlanInterface(t *testing.T) {
   279  	m := pgtype.NewMap()
   280  	src := []byte{0, 42}
   281  	var v interface{}
   282  	plan := m.PlanScan(pgtype.Int2OID, pgtype.BinaryFormatCode, v)
   283  	err := plan.Scan(src, v)
   284  	assert.Error(t, err)
   285  }
   286  
   287  func TestPointerPointerStructScan(t *testing.T) {
   288  	m := pgtype.NewMap()
   289  	type composite struct {
   290  		ID int
   291  	}
   292  
   293  	int4Type, _ := m.TypeForOID(pgtype.Int4OID)
   294  	pgt := &pgtype.Type{
   295  		Codec: &pgtype.CompositeCodec{
   296  			Fields: []pgtype.CompositeCodecField{
   297  				{
   298  					Name: "id",
   299  					Type: int4Type,
   300  				},
   301  			},
   302  		},
   303  		Name: "composite",
   304  		OID:  215333,
   305  	}
   306  	m.RegisterType(pgt)
   307  
   308  	var c *composite
   309  	plan := m.PlanScan(pgt.OID, pgtype.TextFormatCode, &c)
   310  	err := plan.Scan([]byte("(1)"), &c)
   311  	require.NoError(t, err)
   312  	require.Equal(t, c.ID, 1)
   313  }
   314  
   315  // https://github.com/jackc/pgx/issues/1263
   316  func TestMapScanPtrToPtrToSlice(t *testing.T) {
   317  	m := pgtype.NewMap()
   318  	src := []byte("{foo,bar}")
   319  	var v *[]string
   320  	plan := m.PlanScan(pgtype.TextArrayOID, pgtype.TextFormatCode, &v)
   321  	err := plan.Scan(src, &v)
   322  	require.NoError(t, err)
   323  	require.Equal(t, []string{"foo", "bar"}, *v)
   324  }
   325  
   326  func TestMapScanPtrToPtrToSliceOfStruct(t *testing.T) {
   327  	type Team struct {
   328  		TeamID int
   329  		Name   string
   330  	}
   331  
   332  	// Have to use binary format because text format doesn't include type information.
   333  	m := pgtype.NewMap()
   334  	src := []byte{0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xc9, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x17, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x19, 0x0, 0x0, 0x0, 0x6, 0x74, 0x65, 0x61, 0x6d, 0x20, 0x31, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x17, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x19, 0x0, 0x0, 0x0, 0x6, 0x74, 0x65, 0x61, 0x6d, 0x20, 0x32}
   335  	var v *[]Team
   336  	plan := m.PlanScan(pgtype.RecordArrayOID, pgtype.BinaryFormatCode, &v)
   337  	err := plan.Scan(src, &v)
   338  	require.NoError(t, err)
   339  	require.Equal(t, []Team{{1, "team 1"}, {2, "team 2"}}, *v)
   340  }
   341  
   342  type databaseValuerString string
   343  
   344  func (s databaseValuerString) Value() (driver.Value, error) {
   345  	return fmt.Sprintf("%d", len(s)), nil
   346  }
   347  
   348  // https://github.com/jackc/pgx/issues/1319
   349  func TestMapEncodeTextFormatDatabaseValuerThatIsRenamedSimpleType(t *testing.T) {
   350  	m := pgtype.NewMap()
   351  	src := databaseValuerString("foo")
   352  	buf, err := m.Encode(pgtype.TextOID, pgtype.TextFormatCode, src, nil)
   353  	require.NoError(t, err)
   354  	require.Equal(t, "3", string(buf))
   355  }
   356  
   357  type databaseValuerFmtStringer string
   358  
   359  func (s databaseValuerFmtStringer) Value() (driver.Value, error) {
   360  	return nil, nil
   361  }
   362  
   363  func (s databaseValuerFmtStringer) String() string {
   364  	return "foobar"
   365  }
   366  
   367  // https://github.com/jackc/pgx/issues/1311
   368  func TestMapEncodeTextFormatDatabaseValuerThatIsFmtStringer(t *testing.T) {
   369  	m := pgtype.NewMap()
   370  	src := databaseValuerFmtStringer("")
   371  	buf, err := m.Encode(pgtype.TextOID, pgtype.TextFormatCode, src, nil)
   372  	require.NoError(t, err)
   373  	require.Nil(t, buf)
   374  }
   375  
   376  type databaseValuerStringFormat struct {
   377  	n int32
   378  }
   379  
   380  func (v databaseValuerStringFormat) Value() (driver.Value, error) {
   381  	return fmt.Sprint(v.n), nil
   382  }
   383  
   384  func TestMapEncodeBinaryFormatDatabaseValuerThatReturnsString(t *testing.T) {
   385  	m := pgtype.NewMap()
   386  	src := databaseValuerStringFormat{n: 42}
   387  	buf, err := m.Encode(pgtype.Int4OID, pgtype.BinaryFormatCode, src, nil)
   388  	require.NoError(t, err)
   389  	require.Equal(t, []byte{0, 0, 0, 42}, buf)
   390  }
   391  
   392  // https://github.com/jackc/pgx/issues/1445
   393  func TestMapEncodeDatabaseValuerThatReturnsStringIntoUnregisteredTypeTextFormat(t *testing.T) {
   394  	m := pgtype.NewMap()
   395  	buf, err := m.Encode(unregisteredOID, pgtype.TextFormatCode, driverValuerFunc(func() (driver.Value, error) { return "foo", nil }), nil)
   396  	require.NoError(t, err)
   397  	require.Equal(t, []byte("foo"), buf)
   398  }
   399  
   400  // https://github.com/jackc/pgx/issues/1445
   401  func TestMapEncodeDatabaseValuerThatReturnsByteSliceIntoUnregisteredTypeTextFormat(t *testing.T) {
   402  	m := pgtype.NewMap()
   403  	buf, err := m.Encode(unregisteredOID, pgtype.TextFormatCode, driverValuerFunc(func() (driver.Value, error) { return []byte{0, 1, 2, 3}, nil }), nil)
   404  	require.NoError(t, err)
   405  	require.Equal(t, []byte(`\x00010203`), buf)
   406  }
   407  
   408  func TestMapEncodeStringIntoUnregisteredTypeTextFormat(t *testing.T) {
   409  	m := pgtype.NewMap()
   410  	buf, err := m.Encode(unregisteredOID, pgtype.TextFormatCode, "foo", nil)
   411  	require.NoError(t, err)
   412  	require.Equal(t, []byte("foo"), buf)
   413  }
   414  
   415  func TestMapEncodeByteSliceIntoUnregisteredTypeTextFormat(t *testing.T) {
   416  	m := pgtype.NewMap()
   417  	buf, err := m.Encode(unregisteredOID, pgtype.TextFormatCode, []byte{0, 1, 2, 3}, nil)
   418  	require.NoError(t, err)
   419  	require.Equal(t, []byte(`\x00010203`), buf)
   420  }
   421  
   422  // https://github.com/jackc/pgx/issues/1763
   423  func TestMapEncodeNamedTypeOfByteSliceIntoTextTextFormat(t *testing.T) {
   424  	m := pgtype.NewMap()
   425  	buf, err := m.Encode(pgtype.TextOID, pgtype.TextFormatCode, json.RawMessage(`{"foo": "bar"}`), nil)
   426  	require.NoError(t, err)
   427  	require.Equal(t, []byte(`{"foo": "bar"}`), buf)
   428  }
   429  
   430  // https://github.com/jackc/pgx/issues/1326
   431  func TestMapScanPointerToRenamedType(t *testing.T) {
   432  	srcBuf := []byte("foo")
   433  	m := pgtype.NewMap()
   434  
   435  	var rs *_string
   436  	err := m.Scan(pgtype.TextOID, pgx.TextFormatCode, srcBuf, &rs)
   437  	assert.NoError(t, err)
   438  	require.NotNil(t, rs)
   439  	assert.Equal(t, "foo", string(*rs))
   440  }
   441  
   442  // https://github.com/jackc/pgx/issues/1326
   443  func TestMapScanNullToWrongType(t *testing.T) {
   444  	m := pgtype.NewMap()
   445  
   446  	var n *int32
   447  	err := m.Scan(pgtype.TextOID, pgx.TextFormatCode, nil, &n)
   448  	assert.NoError(t, err)
   449  	assert.Nil(t, n)
   450  
   451  	var pn pgtype.Int4
   452  	err = m.Scan(pgtype.TextOID, pgx.TextFormatCode, nil, &pn)
   453  	assert.NoError(t, err)
   454  	assert.False(t, pn.Valid)
   455  }
   456  
   457  func TestScanToSliceOfRenamedUint8(t *testing.T) {
   458  	m := pgtype.NewMap()
   459  	var ruint8 []_uint8
   460  	err := m.Scan(pgtype.Int2ArrayOID, pgx.TextFormatCode, []byte("{2,4}"), &ruint8)
   461  	assert.NoError(t, err)
   462  	assert.Equal(t, []_uint8{2, 4}, ruint8)
   463  }
   464  
   465  func TestMapScanTextToBool(t *testing.T) {
   466  	tests := []struct {
   467  		name string
   468  		src  []byte
   469  		want bool
   470  	}{
   471  		{"t", []byte("t"), true},
   472  		{"f", []byte("f"), false},
   473  		{"y", []byte("y"), true},
   474  		{"n", []byte("n"), false},
   475  		{"1", []byte("1"), true},
   476  		{"0", []byte("0"), false},
   477  		{"true", []byte("true"), true},
   478  		{"false", []byte("false"), false},
   479  		{"yes", []byte("yes"), true},
   480  		{"no", []byte("no"), false},
   481  		{"on", []byte("on"), true},
   482  		{"off", []byte("off"), false},
   483  	}
   484  
   485  	for _, tt := range tests {
   486  		t.Run(tt.name, func(t *testing.T) {
   487  			m := pgtype.NewMap()
   488  
   489  			var v bool
   490  			err := m.Scan(pgtype.BoolOID, pgx.TextFormatCode, tt.src, &v)
   491  			require.NoError(t, err)
   492  			assert.Equal(t, tt.want, v)
   493  		})
   494  	}
   495  }
   496  
   497  func TestMapScanTextToBoolError(t *testing.T) {
   498  	tests := []struct {
   499  		name string
   500  		src  []byte
   501  		want string
   502  	}{
   503  		{"nil", nil, "cannot scan NULL into *bool"},
   504  		{"empty", []byte{}, "cannot scan empty string into *bool"},
   505  		{"foo", []byte("foo"), "unknown boolean string representation \"foo\""},
   506  	}
   507  
   508  	for _, tt := range tests {
   509  		t.Run(tt.name, func(t *testing.T) {
   510  			m := pgtype.NewMap()
   511  
   512  			var v bool
   513  			err := m.Scan(pgtype.BoolOID, pgx.TextFormatCode, tt.src, &v)
   514  			require.ErrorContains(t, err, tt.want)
   515  		})
   516  	}
   517  }
   518  
   519  type databaseValuerUUID [16]byte
   520  
   521  func (v databaseValuerUUID) Value() (driver.Value, error) {
   522  	return fmt.Sprintf("%x", v), nil
   523  }
   524  
   525  // https://github.com/jackc/pgx/issues/1502
   526  func TestMapEncodePlanCacheUUIDTypeConfusion(t *testing.T) {
   527  	expected := []byte{
   528  		0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0xb, 0x86, 0, 0, 0, 2, 0, 0, 0, 1,
   529  		0, 0, 0, 16,
   530  		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
   531  		0, 0, 0, 16,
   532  		15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
   533  
   534  	m := pgtype.NewMap()
   535  	buf, err := m.Encode(pgtype.UUIDArrayOID, pgtype.BinaryFormatCode,
   536  		[]databaseValuerUUID{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}},
   537  		nil)
   538  	require.NoError(t, err)
   539  	require.Equal(t, expected, buf)
   540  
   541  	// This actually *should* fail. In the actual query path this error is detected and the encoding falls back to the
   542  	// text format. In the bug this test is guarding against regression this would panic.
   543  	_, err = m.Encode(pgtype.UUIDArrayOID, pgtype.BinaryFormatCode,
   544  		[]string{"00010203-0405-0607-0809-0a0b0c0d0e0f", "0f0e0d0c-0b0a-0908-0706-0504-03020100"},
   545  		nil)
   546  	require.Error(t, err)
   547  }
   548  
   549  // https://github.com/jackc/pgx/issues/1763
   550  func TestMapEncodeRawJSONIntoUnknownOID(t *testing.T) {
   551  	m := pgtype.NewMap()
   552  	buf, err := m.Encode(0, pgtype.TextFormatCode, json.RawMessage(`{"foo": "bar"}`), nil)
   553  	require.NoError(t, err)
   554  	require.Equal(t, []byte(`{"foo": "bar"}`), buf)
   555  }
   556  
   557  func BenchmarkMapScanInt4IntoBinaryDecoder(b *testing.B) {
   558  	m := pgtype.NewMap()
   559  	src := []byte{0, 0, 0, 42}
   560  	var v pgtype.Int4
   561  
   562  	for i := 0; i < b.N; i++ {
   563  		v = pgtype.Int4{}
   564  		err := m.Scan(pgtype.Int4OID, pgtype.BinaryFormatCode, src, &v)
   565  		if err != nil {
   566  			b.Fatal(err)
   567  		}
   568  		if v != (pgtype.Int4{Int32: 42, Valid: true}) {
   569  			b.Fatal("scan failed due to bad value")
   570  		}
   571  	}
   572  }
   573  
   574  func BenchmarkMapScanInt4IntoGoInt32(b *testing.B) {
   575  	m := pgtype.NewMap()
   576  	src := []byte{0, 0, 0, 42}
   577  	var v int32
   578  
   579  	for i := 0; i < b.N; i++ {
   580  		v = 0
   581  		err := m.Scan(pgtype.Int4OID, pgtype.BinaryFormatCode, src, &v)
   582  		if err != nil {
   583  			b.Fatal(err)
   584  		}
   585  		if v != 42 {
   586  			b.Fatal("scan failed due to bad value")
   587  		}
   588  	}
   589  }
   590  
   591  func BenchmarkScanPlanScanInt4IntoBinaryDecoder(b *testing.B) {
   592  	m := pgtype.NewMap()
   593  	src := []byte{0, 0, 0, 42}
   594  	var v pgtype.Int4
   595  
   596  	plan := m.PlanScan(pgtype.Int4OID, pgtype.BinaryFormatCode, &v)
   597  
   598  	for i := 0; i < b.N; i++ {
   599  		v = pgtype.Int4{}
   600  		err := plan.Scan(src, &v)
   601  		if err != nil {
   602  			b.Fatal(err)
   603  		}
   604  		if v != (pgtype.Int4{Int32: 42, Valid: true}) {
   605  			b.Fatal("scan failed due to bad value")
   606  		}
   607  	}
   608  }
   609  
   610  func BenchmarkScanPlanScanInt4IntoGoInt32(b *testing.B) {
   611  	m := pgtype.NewMap()
   612  	src := []byte{0, 0, 0, 42}
   613  	var v int32
   614  
   615  	plan := m.PlanScan(pgtype.Int4OID, pgtype.BinaryFormatCode, &v)
   616  
   617  	for i := 0; i < b.N; i++ {
   618  		v = 0
   619  		err := plan.Scan(src, &v)
   620  		if err != nil {
   621  			b.Fatal(err)
   622  		}
   623  		if v != 42 {
   624  			b.Fatal("scan failed due to bad value")
   625  		}
   626  	}
   627  }
   628  
   629  func isExpectedEq(a any) func(any) bool {
   630  	return func(v any) bool {
   631  		return a == v
   632  	}
   633  }
   634  

View as plain text