CodeSampleX

샘플

github.com/jackc/pgx/v5 v5.10.0: Initialize pgx.ConnConfig via ParseConfig to avoid ConnectConfig panics, understand pgx DSN option extraction and multi-host fallbacks, and handle pgx.ErrNoRows via errors.Is rather than direct sql.ErrNoRows pointer equality

검증된 샘플 — golang github.com/jackc/pgx/v5 v5.10.0: Initialize pgx.ConnConfig via ParseConfig to avoid ConnectConfig panics, understand pgx DSN option…

sha256:99c23efc0d189ad74817464888e317aebe1d850b1a21d9ccc02346cd485f882a

이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다. 통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다. MIT-0

실행 증거

선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.

증거 기준
서명된 컨트랙트 통과
검증 영수증
2
빌드한 서명 키
2
선언된 환경 go linux x64 go go gomod

검증 실행 환경

환경 컨트랙트 단계 실행일
go 1.26 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · golang@1
2026-08-17
go 1.26 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · golang@1
2026-08-18

케이스

HOW
목표
Initialize pgx.ConnConfig via ParseConfig to avoid ConnectConfig panics, understand pgx DSN option extraction and multi-host fallbacks, and handle pgx.ErrNoRows via errors.Is rather than direct sql.ErrNoRows pointer equality
패키지
심벌
  • github.com/jackc/pgx/v5.Conn
  • github.com/jackc/pgx/v5.ConnConfig
  • github.com/jackc/pgx/v5.ConnectConfig
  • github.com/jackc/pgx/v5.ErrNoRows
  • github.com/jackc/pgx/v5.ParseConfig
  • github.com/jackc/pgx/v5.Row
환경
go
생성일
2026-08-17T03:13:21Z

컨트랙트

  1. assert ConnectConfig panics when ConnConfig is manually initialized without ParseConfig
  2. assert ParseConfig extracts statement/description cache capacities and default_query_exec_mode into typed fields and strips them from RuntimeParams
  3. assert ParseConfig sets primary host in Host/Port and secondary hosts in Fallbacks (1 fallback for sslmode=disable, 3 for default prefer)
  4. assert pgx.ErrNoRows != sql.ErrNoRows by direct comparison but matches errors.Is(err, sql.ErrNoRows) and errors.Is(err, pgx.ErrNoRows)
  5. assert Row.Scan returns pgx.ErrNoRows on empty result set and rejects scanning into *pgtype.DriverBytes

파일

  • NOTES.md
  • csx.json
  • go.mod
  • go.sum
  • mock.go
  • sample_test.go

소스 아티팩트 내려받기 (tar.gz)

소스

NOTES.md
# Notes

## CSX Network Search Result
`search_known_solution` returned existing sample `sha256:4eb6eee48a60e79da9dcf4055256991997f094a1da19ee17cfe0697e6d6d7b32` covering NULL struct scanning (`RowToStructByName`/`RowToStructByNameLax`) and `pgxpool.Pool` connection release. We focused on the primary connection lifecycle and error model: manual `ConnConfig` struct instantiation, `ParseConfig` DSN option extraction vs `RuntimeParams`, multi-host fallback generation, and `pgx.ErrNoRows` proxy error unwrapping.

## What a Model Would Have Written Instead
A naive model manually instantiates `&pgx.ConnConfig{Config: pgconn.Config{Host: "example.com"}}` before calling `ConnectConfig`, checks query errors with direct pointer comparison `err == sql.ErrNoRows`, assumes pgx connection options like `default_query_exec_mode` stay in `RuntimeParams`, and expects multi-host DSNs to store both hosts in `Host` or `Fallbacks`.

## How the Wrong Version Fails
- **Manual ConnConfig**: Fails loudly at runtime with `panic: config must be created by ParseConfig` inside `ConnectConfig`.
- **sql.ErrNoRows direct comparison**: Fails silently with a green build where `err == sql.ErrNoRows` evaluates to `false` because `pgx.ErrNoRows` is a wrapped proxy error, skipping error branches.
- **pgx DSN options**: Silently misconfigures session settings if assumed to be in `RuntimeParams`, or returns loud `*pgconn.ParseConfigError` on invalid query exec modes.
- **Multi-host parsing**: Silently mishandles host topology by assuming all hosts reside in `Fallbacks` or `Host`.
csx.json
{"case":{"caseId":"case:sha256:049a727163b7714415bfaedee222c1925903ce4dd9bad366ff986c44e77d8e9a","contract":["assert ConnectConfig panics when ConnConfig is manually initialized without ParseConfig","assert ParseConfig extracts statement/description cache capacities and default_query_exec_mode into typed fields and strips them from RuntimeParams","assert ParseConfig sets primary host in Host/Port and secondary hosts in Fallbacks (1 fallback for sslmode=disable, 3 for default prefer)","assert pgx.ErrNoRows != sql.ErrNoRows by direct comparison but matches errors.Is(err, sql.ErrNoRows) and errors.Is(err, pgx.ErrNoRows)","assert Row.Scan returns pgx.ErrNoRows on empty result set and rejects scanning into *pgtype.DriverBytes"],"goal":"Initialize pgx.ConnConfig via ParseConfig to avoid ConnectConfig panics, understand pgx DSN option extraction and multi-host fallbacks, and handle pgx.ErrNoRows via errors.Is rather than direct sql.ErrNoRows pointer equality","kind":"HOW","packages":["pkg:golang/github.com/jackc/pgx/v5@v5.10.0"],"schemaVersion":1,"symbols":["github.com/jackc/pgx/v5.Conn","github.com/jackc/pgx/v5.ConnConfig","github.com/jackc/pgx/v5.ConnectConfig","github.com/jackc/pgx/v5.ErrNoRows","github.com/jackc/pgx/v5.ParseConfig","github.com/jackc/pgx/v5.Row"]},"contractCommand":["go","test","./..."],"environment":{"arch":"x64","ecosystem":"golang","executionContext":"go","language":"go","os":"linux","packageManager":"gomod","runtime":"go","schemaVersion":1},"license":"MIT-0","packages":["pkg:golang/github.com/jackc/pgx/v5@v5.10.0"],"schemaVersion":1,"symbols":["github.com/jackc/pgx/v5.Conn","github.com/jackc/pgx/v5.ConnConfig","github.com/jackc/pgx/v5.ConnectConfig","github.com/jackc/pgx/v5.ErrNoRows","github.com/jackc/pgx/v5.ParseConfig","github.com/jackc/pgx/v5.Row"],"verifierAdapter":"golang@1"}
go.mod
module sample

go 1.26.5

require github.com/jackc/pgx/v5 v5.10.0

require (
	github.com/jackc/pgpassfile v1.0.0 // indirect
	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
	golang.org/x/text v0.29.0 // indirect
)
go.sum
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=
github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mock.go
package sample

import (
	"context"
	"net"
	"testing"

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

// newMockConn creates an in-memory *pgx.Conn backed by net.Pipe.
// The mock PostgreSQL backend answers startup and simulates empty result sets or specific queries.
func newMockConn(t *testing.T, modifyConfig func(*pgx.ConnConfig)) (*pgx.Conn, context.Context) {
	t.Helper()

	cfg, err := pgx.ParseConfig("postgres://example.user:secret@127.0.0.1:5432/testdb?sslmode=disable")
	if err != nil {
		t.Fatalf("pgx.ParseConfig failed: %v", err)
	}

	if modifyConfig != nil {
		modifyConfig(cfg)
	}

	cfg.DialFunc = func(ctx context.Context, _, _ string) (net.Conn, error) {
		client, server := net.Pipe()
		go func(conn net.Conn) {
			defer conn.Close()
			b := pgproto3.NewBackend(conn, conn)

			// 1. Startup handshake
			msg, err := b.ReceiveStartupMessage()
			if err != nil || msg == nil {
				return
			}
			if _, ok := msg.(*pgproto3.SSLRequest); ok {
				_, _ = conn.Write([]byte{'N'}) // Reject SSL
				msg, err = b.ReceiveStartupMessage()
				if err != nil || msg == nil {
					return
				}
			}

			b.Send(&pgproto3.AuthenticationOk{})
			b.Send(&pgproto3.ReadyForQuery{TxStatus: 'I'})
			if err := b.Flush(); err != nil {
				return
			}

			// 2. Query message loop
			for {
				req, err := b.Receive()
				if err != nil || req == nil {
					return
				}
				switch msg := req.(type) {
				case *pgproto3.Terminate:
					return
				case *pgproto3.Query:
					// Simple protocol query returning 0 rows (CommandComplete)
					b.Send(&pgproto3.RowDescription{
						Fields: []pgproto3.FieldDescription{
							{Name: []byte("val"), DataTypeOID: 25, DataTypeSize: -1, TypeModifier: -1, Format: 0},
						},
					})
					b.Send(&pgproto3.CommandComplete{CommandTag: []byte("SELECT 0")})
					b.Send(&pgproto3.ReadyForQuery{TxStatus: 'I'})
					_ = b.Flush()
				case *pgproto3.Parse:
					b.Send(&pgproto3.ParseComplete{})
					_ = b.Flush()
				case *pgproto3.Describe:
					if msg.ObjectType == 'S' {
						b.Send(&pgproto3.ParameterDescription{ParameterOIDs: []uint32{23}})
					}
					b.Send(&pgproto3.RowDescription{
						Fields: []pgproto3.FieldDescription{
							{Name: []byte("val"), DataTypeOID: 25, DataTypeSize: -1, TypeModifier: -1, Format: 0},
						},
					})
					_ = b.Flush()
				case *pgproto3.Bind:
					b.Send(&pgproto3.BindComplete{})
					_ = b.Flush()
				case *pgproto3.Execute:
					// Return 0 rows, then complete
					b.Send(&pgproto3.CommandComplete{CommandTag: []byte("SELECT 0")})
					_ = b.Flush()
				case *pgproto3.Sync:
					b.Send(&pgproto3.ReadyForQuery{TxStatus: 'I'})
					_ = b.Flush()
				}
			}
		}(server)
		return client, nil
	}

	ctx := context.Background()
	conn, err := pgx.ConnectConfig(ctx, cfg)
	if err != nil {
		t.Fatalf("pgx.ConnectConfig failed: %v", err)
	}
	t.Cleanup(func() {
		_ = conn.Close(ctx)
	})

	return conn, ctx
}
sample_test.go
package sample

import (
	"context"
	"database/sql"
	"errors"
	"net"
	"strings"
	"testing"

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

func TestConnConfig_ManualInitPanics(t *testing.T) {
	// A naive model often constructs &pgx.ConnConfig manually.
	// In pgx v5, ConnectConfig explicitly checks an internal createdByParseConfig flag and PANICS.
	manualCfg := &pgx.ConnConfig{
		Config: pgconn.Config{
			Host: "192.0.2.1",
			Port: 5432,
		},
	}

	panicked := false
	func() {
		defer func() {
			if r := recover(); r != nil {
				panicked = true
				msg, ok := r.(string)
				if !ok || msg != "config must be created by ParseConfig" {
					t.Fatalf("unexpected panic message: %v", r)
				}
			}
		}()
		_, _ = pgx.ConnectConfig(context.Background(), manualCfg)
	}()

	if !panicked {
		t.Fatalf("expected pgx.ConnectConfig with manually initialized ConnConfig to panic")
	}

	// Parsing via ParseConfig (even with empty string for defaults) sets the internal flag.
	parsedCfg, err := pgx.ParseConfig("")
	if err != nil {
		t.Fatalf("ParseConfig(\"\") failed: %v", err)
	}

	// Copying the config preserves the validation flag.
	copiedCfg := parsedCfg.Copy()
	copiedCfg.Host = "192.0.2.1"
	copiedCfg.Port = 5432

	// Setting a dummy DialFunc prevents real network dial during ConnectConfig verification.
	dialCalled := false
	copiedCfg.DialFunc = func(ctx context.Context, network, addr string) (netConn net.Conn, err error) {
		dialCalled = true
		return nil, errors.New("abort dial after validation")
	}

	_, err = pgx.ConnectConfig(context.Background(), copiedCfg)
	if err == nil || !strings.Contains(err.Error(), "abort dial after validation") {
		t.Fatalf("expected dial abort error, got: %v", err)
	}
	if !dialCalled {
		t.Fatalf("expected DialFunc to be reached without panic")
	}
}

func TestParseConfig_PgxOptionsVsRuntimeParams(t *testing.T) {
	dsn := "postgres://example.com/mydb?default_query_exec_mode=simple_protocol&statement_cache_capacity=128&description_cache_capacity=64&search_path=myschema&application_name=myapp"
	cfg, err := pgx.ParseConfig(dsn)
	if err != nil {
		t.Fatalf("ParseConfig failed: %v", err)
	}

	// pgx-specific options are extracted into typed struct fields
	if cfg.DefaultQueryExecMode != pgx.QueryExecModeSimpleProtocol {
		t.Fatalf("expected DefaultQueryExecMode SimpleProtocol, got: %v", cfg.DefaultQueryExecMode)
	}
	if cfg.StatementCacheCapacity != 128 {
		t.Fatalf("expected StatementCacheCapacity 128, got: %d", cfg.StatementCacheCapacity)
	}
	if cfg.DescriptionCacheCapacity != 64 {
		t.Fatalf("expected DescriptionCacheCapacity 64, got: %d", cfg.DescriptionCacheCapacity)
	}

	// pgx-specific options are stripped from RuntimeParams so they are not sent as PostgreSQL session settings
	if _, exists := cfg.RuntimeParams["default_query_exec_mode"]; exists {
		t.Fatalf("expected default_query_exec_mode to be stripped from RuntimeParams")
	}
	if _, exists := cfg.RuntimeParams["statement_cache_capacity"]; exists {
		t.Fatalf("expected statement_cache_capacity to be stripped from RuntimeParams")
	}
	if _, exists := cfg.RuntimeParams["description_cache_capacity"]; exists {
		t.Fatalf("expected description_cache_capacity to be stripped from RuntimeParams")
	}

	// Standard PostgreSQL parameters remain in RuntimeParams
	if cfg.RuntimeParams["search_path"] != "myschema" {
		t.Fatalf("expected search_path in RuntimeParams, got: %q", cfg.RuntimeParams["search_path"])
	}
	if cfg.RuntimeParams["application_name"] != "myapp" {
		t.Fatalf("expected application_name in RuntimeParams, got: %q", cfg.RuntimeParams["application_name"])
	}

	// Invalid default_query_exec_mode produces a ParseConfigError
	_, err = pgx.ParseConfig("postgres://example.com/mydb?default_query_exec_mode=invalid_mode")
	if err == nil {
		t.Fatalf("expected error for invalid default_query_exec_mode")
	}
	var parseErr *pgconn.ParseConfigError
	if !errors.As(err, &parseErr) {
		t.Fatalf("expected error to be *pgconn.ParseConfigError, got: %T (%v)", err, err)
	}
}

func TestParseConfig_MultiHostFallbacks(t *testing.T) {
	// 1. With sslmode=disable, secondary hosts create 1 fallback entry
	dsnDisable := "postgres://example.user:secret@host1.example.com:5432,host2.example.com:5433/mydb?sslmode=disable"
	cfgDisable, err := pgx.ParseConfig(dsnDisable)
	if err != nil {
		t.Fatalf("ParseConfig multi-host failed: %v", err)
	}

	// Primary host is set directly in Host and Port
	if cfgDisable.Host != "host1.example.com" || cfgDisable.Port != 5432 {
		t.Fatalf("expected primary host1.example.com:5432, got %s:%d", cfgDisable.Host, cfgDisable.Port)
	}

	// Secondary host is stored in Fallbacks slice
	if len(cfgDisable.Fallbacks) != 1 {
		t.Fatalf("expected exactly 1 fallback host with sslmode=disable, got: %d", len(cfgDisable.Fallbacks))
	}
	if cfgDisable.Fallbacks[0].Host != "host2.example.com" || cfgDisable.Fallbacks[0].Port != 5433 {
		t.Fatalf("expected fallback host2.example.com:5433, got %s:%d", cfgDisable.Fallbacks[0].Host, cfgDisable.Fallbacks[0].Port)
	}

	// 2. With default sslmode=prefer, pgconn generates TLS and non-TLS fallback combinations (total 3 fallbacks for 2 hosts)
	dsnPrefer := "postgres://example.user:secret@host1.example.com:5432,host2.example.com:5433/mydb"
	cfgPrefer, err := pgx.ParseConfig(dsnPrefer)
	if err != nil {
		t.Fatalf("ParseConfig default prefer failed: %v", err)
	}
	if len(cfgPrefer.Fallbacks) != 3 {
		t.Fatalf("expected 3 fallbacks with default sslmode=prefer, got: %d", len(cfgPrefer.Fallbacks))
	}
}

func TestErrNoRows_ProxyErrorBehavior(t *testing.T) {
	// 1. Direct pointer equality with sql.ErrNoRows fails because pgx.ErrNoRows is a proxy error struct
	if pgx.ErrNoRows == sql.ErrNoRows {
		t.Fatalf("expected pgx.ErrNoRows != sql.ErrNoRows by direct comparison")
	}

	// 2. errors.Is matches both pgx.ErrNoRows and sql.ErrNoRows via Unwrap()
	if !errors.Is(pgx.ErrNoRows, sql.ErrNoRows) {
		t.Fatalf("expected errors.Is(pgx.ErrNoRows, sql.ErrNoRows) to be true")
	}
	if !errors.Is(pgx.ErrNoRows, pgx.ErrNoRows) {
		t.Fatalf("expected errors.Is(pgx.ErrNoRows, pgx.ErrNoRows) to be true")
	}

	// 3. Error messages differ: pgx strips the "sql: " prefix
	if pgx.ErrNoRows.Error() != "no rows in result set" {
		t.Fatalf("expected %q, got %q", "no rows in result set", pgx.ErrNoRows.Error())
	}
	if sql.ErrNoRows.Error() != "sql: no rows in result set" {
		t.Fatalf("expected %q, got %q", "sql: no rows in result set", sql.ErrNoRows.Error())
	}
}

func TestRow_ScanErrNoRowsAndDriverBytes(t *testing.T) {
	conn, ctx := newMockConn(t, nil)

	// 1. Query returning 0 rows yields pgx.ErrNoRows from Row.Scan
	row := conn.QueryRow(ctx, "SELECT val FROM items WHERE id = $1", 123)
	var val string
	err := row.Scan(&val)
	if err == nil {
		t.Fatalf("expected error from empty result set scan, got nil")
	}

	// Direct equality with pgx.ErrNoRows matches
	if err != pgx.ErrNoRows {
		t.Fatalf("expected err == pgx.ErrNoRows, got %v", err)
	}

	// Direct equality with sql.ErrNoRows FAILS (the common bug in naive code)
	if err == sql.ErrNoRows {
		t.Fatalf("expected err != sql.ErrNoRows by direct pointer comparison")
	}

	// errors.Is matches sql.ErrNoRows
	if !errors.Is(err, sql.ErrNoRows) {
		t.Fatalf("expected errors.Is(err, sql.ErrNoRows) to be true")
	}

	// 2. Attempting to scan into *pgtype.DriverBytes from QueryRow is explicitly forbidden
	driverRow := conn.QueryRow(ctx, "SELECT val FROM items WHERE id = $1", 123)
	var driverBytes pgtype.DriverBytes
	driverErr := driverRow.Scan(&driverBytes)
	if driverErr == nil || !strings.Contains(driverErr.Error(), "cannot scan into *pgtype.DriverBytes from QueryRow") {
		t.Fatalf("expected cannot scan into *pgtype.DriverBytes error, got: %v", driverErr)
	}
}

오리진 시더

csx-seed