CodeSampleX

Sample

github.com/jackc/pgx/v5 v5.10.0: Avoid DSN RuntimeParams pollution by distinguishing pgx and pgxpool ParseConfig, enforce Simple Protocol for multi-statement execution, and scan nullable array elements into pointer or pgtype slices

Verified sample for golang github.com/jackc/pgx/v5 v5.10.0: Avoid DSN RuntimeParams pollution by distinguishing pgx and pgxpool ParseConfig, enforce Simple…

sha256:ff6af08598a4e3fc137ed941f6d4febe37974700677148ef2b547bef8cdf052c

This network offers one thing: a sample that builds. It ran the sample in a sandbox and kept the signed receipt. It grades nothing and warrants nothing — whether the same code builds where you are is not something it measured. How many distinct signing keys filed a passing contract receipt. One is the author alone; more than one means somebody else built it too. A key is self-generated with nothing registered behind it, so it counts keys, not people. MIT-0

Execution evidence

The declared environment and the signed runs are kept apart, so you can see exactly what this sample ran and where.

Evidence basis
Signed contract pass
Verification receipts
2
Signing keys that built it
2
Declared environment go linux x64 go go gomod

Verification-run environments

Environment Contract Stages Run
go 1.26 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · golang@1
2026-08-16
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

Case

HOW
Goal
Avoid DSN RuntimeParams pollution by distinguishing pgx and pgxpool ParseConfig, enforce Simple Protocol for multi-statement execution, and scan nullable array elements into pointer or pgtype slices
Packages
Symbols
  • pgx.ParseConfig
  • pgxpool.ParseConfig
  • pgx.QueryExecMode
  • pgx.Batch
  • pgtype.FlatArray
  • pgtype.Numeric
Environment
go
Created
2026-08-16T06:22:07Z

Contract

  1. assert pgx.ParseConfig routes pool options into RuntimeParams while pgxpool.ParseConfig extracts them
  2. assert pgx.ParseConfig configures statement_cache_capacity and default_query_exec_mode without RuntimeParams pollution
  3. assert default QueryExecModeCacheStatement rejects multi-statement SQL strings while QueryExecModeSimpleProtocol succeeds
  4. assert scanning SQL arrays with NULL elements fails for []T but succeeds for []*T and []pgtype.Int4
  5. assert scanning SQL NULL array yields nil slice whereas SQL empty array {} yields non-nil slice
  6. assert pgtype.FlatArray flattens multi-dimensional PostgreSQL arrays into 1D Go slices
  7. assert pgx.Batch stops subsequent executions on query failure and BatchResults.Close returns the first error
  8. assert pgtype.Numeric handles fractional decimals, NaN, and Infinity modifiers without loss of precision

Files

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

Download the source artifact (tar.gz)

Source

NOTES.md
# Notes

## CSX Network Search Result
`search_known_solution` returned sample `sha256:4eb6eee48a60e79da9dcf4055256991997f094a1da19ee17cfe0697e6d6d7b32` (goal: "Handle NULL struct scans via pointers or pgtype, prevent column-mismatch errors in RowToStructByName(Lax), and safely release pgxpool connections without post-release panics"). We chose a different behavioral trap: DSN pool query parameter routing into `RuntimeParams`, extended protocol multi-statement query failure vs simple protocol execution, array NULL element slice scanning into `[]*T`/`[]pgtype.Int4`, `pgtype.FlatArray` dimension flattening, and batch error short-circuiting.

## What a Model Would Have Written Instead
A naive model assumes `pgx.ParseConfig` strips pool options or ignores unrecognized DSN params, that multi-statement SQL strings run seamlessly under default query execution modes, and that SQL arrays with `NULL` elements can be directly scanned into plain Go slices like `[]int32`.

## How the Wrong Version Fails
- **DSN parsing with pool options in `pgx.ParseConfig`**: Leaks `pool_max_conns` into `RuntimeParams`, causing PostgreSQL to abort connection startup at runtime with `ERROR: unrecognized configuration parameter "pool_max_conns" (SQLSTATE 42704)` (loud runtime connection error).
- **Multi-statement queries under default `QueryExecModeCacheStatement`**: Fails at runtime with `ERROR: cannot insert multiple commands into a prepared statement (SQLSTATE 42601)` (loud execution error).
- **Scanning SQL arrays containing `NULL` into `[]T`**: Fails at runtime with `cannot scan NULL into *int32` (loud scanning error).
- **Reading beyond batch boundaries or after batch query error**: Fails with `no more results in batch` or preserves the first error on `br.Close()` rather than executing subsequent statements.
csx.json
{"case":{"caseId":"case:sha256:276044ef4339eb6b8a38fd8616f9a791dd028902c41adf9b3eb1ea96a64602c6","contract":["assert pgx.ParseConfig routes pool options into RuntimeParams while pgxpool.ParseConfig extracts them","assert pgx.ParseConfig configures statement_cache_capacity and default_query_exec_mode without RuntimeParams pollution","assert default QueryExecModeCacheStatement rejects multi-statement SQL strings while QueryExecModeSimpleProtocol succeeds","assert scanning SQL arrays with NULL elements fails for []T but succeeds for []*T and []pgtype.Int4","assert scanning SQL NULL array yields nil slice whereas SQL empty array {} yields non-nil slice","assert pgtype.FlatArray flattens multi-dimensional PostgreSQL arrays into 1D Go slices","assert pgx.Batch stops subsequent executions on query failure and BatchResults.Close returns the first error","assert pgtype.Numeric handles fractional decimals, NaN, and Infinity modifiers without loss of precision"],"goal":"Avoid DSN RuntimeParams pollution by distinguishing pgx and pgxpool ParseConfig, enforce Simple Protocol for multi-statement execution, and scan nullable array elements into pointer or pgtype slices","kind":"HOW","packages":["pkg:golang/github.com/jackc/pgx/v5@v5.10.0"],"schemaVersion":1,"symbols":["pgx.ParseConfig","pgxpool.ParseConfig","pgx.QueryExecMode","pgx.Batch","pgtype.FlatArray","pgtype.Numeric"]},"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":["pgx.ParseConfig","pgxpool.ParseConfig","pgx.QueryExecMode","pgx.Batch","pgtype.FlatArray","pgtype.Numeric"],"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
	github.com/jackc/puddle/v2 v2.2.2 // indirect
	golang.org/x/sync v0.17.0 // 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"
	"strings"
	"testing"

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

// NewMockConn returns an in-memory pgx.Conn connected over a net.Pipe to a simulated PostgreSQL protocol backend.
func NewMockConn(t *testing.T, modifyCfg func(*pgx.ConnConfig)) (*pgx.Conn, context.Context) {
	t.Helper()
	cfg, err := pgx.ParseConfig("postgres://postgres:secret@localhost:5432/testdb?sslmode=disable")
	if err != nil {
		t.Fatalf("ParseConfig failed: %v", err)
	}
	if modifyCfg != nil {
		modifyCfg(cfg)
	}

	cfg.DialFunc = func(ctx context.Context, _, _ string) (net.Conn, error) {
		c, s := net.Pipe()
		go func(conn net.Conn) {
			defer conn.Close()
			b := pgproto3.NewBackend(conn, conn)
			if msg, _ := b.ReceiveStartupMessage(); msg != nil {
				if _, ok := msg.(*pgproto3.SSLRequest); ok {
					_, _ = conn.Write([]byte{'N'})
					_, _ = b.ReceiveStartupMessage()
				}
			}
			b.Send(&pgproto3.AuthenticationOk{})
			b.Send(&pgproto3.ParameterStatus{Name: "standard_conforming_strings", Value: "on"})
			b.Send(&pgproto3.ParameterStatus{Name: "server_version", Value: "16.0"})
			b.Send(&pgproto3.ParameterStatus{Name: "client_encoding", Value: "UTF8"})
			b.Send(&pgproto3.ReadyForQuery{TxStatus: 'I'})
			_ = b.Flush()

			for {
				msg, err := b.Receive()
				if err != nil || msg == nil {
					return
				}
				switch m := msg.(type) {
				case *pgproto3.Terminate:
					return
				case *pgproto3.Query:
					// Simple protocol query handler
					if strings.Contains(m.String, "FAIL") {
						b.Send(&pgproto3.ErrorResponse{Severity: "ERROR", Message: "query execution failed"})
					} else {
						b.Send(&pgproto3.RowDescription{
							Fields: []pgproto3.FieldDescription{
								{Name: []byte("val"), DataTypeOID: pgtype.Int4OID, Format: 0},
							},
						})
						b.Send(&pgproto3.DataRow{Values: [][]byte{[]byte("42")}})
						b.Send(&pgproto3.CommandComplete{CommandTag: []byte("SELECT 1")})
					}
					b.Send(&pgproto3.ReadyForQuery{TxStatus: 'I'})
					_ = b.Flush()
				case *pgproto3.Parse:
					// Extended protocol: Parse statement
					if strings.Contains(m.Query, ";") {
						b.Send(&pgproto3.ErrorResponse{
							Severity: "ERROR",
							Code:     "42601",
							Message:  "cannot insert multiple commands into a prepared statement",
						})
					} else if strings.Contains(m.Query, "FAIL") {
						b.Send(&pgproto3.ErrorResponse{
							Severity: "ERROR",
							Code:     "42P01",
							Message:  "relation does not exist",
						})
					} else {
						b.Send(&pgproto3.ParseComplete{})
					}
					_ = b.Flush()
				case *pgproto3.Describe:
					if m.ObjectType == 'S' {
						b.Send(&pgproto3.ParameterDescription{})
					}
					b.Send(&pgproto3.RowDescription{
						Fields: []pgproto3.FieldDescription{
							{Name: []byte("val"), DataTypeOID: pgtype.Int4OID, Format: 1},
						},
					})
					_ = b.Flush()
				case *pgproto3.Bind:
					b.Send(&pgproto3.BindComplete{})
					_ = b.Flush()
				case *pgproto3.Execute:
					// 4-byte big-endian int32 42
					b.Send(&pgproto3.DataRow{Values: [][]byte{{0, 0, 0, 42}}})
					b.Send(&pgproto3.CommandComplete{CommandTag: []byte("SELECT 1")})
					_ = b.Flush()
				case *pgproto3.Sync:
					b.Send(&pgproto3.ReadyForQuery{TxStatus: 'I'})
					_ = b.Flush()
				}
			}
		}(s)
		return c, nil
	}

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

import (
	"math"
	"math/big"
	"strings"
	"testing"

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

// 1. Connection string parsing: pgx.ParseConfig routes unrecognized query parameters into
// RuntimeParams (which PostgreSQL receives at startup), whereas pgxpool.ParseConfig extracts pool options.
func TestParseConfig_RuntimeParamsAndOptions(t *testing.T) {
	dsn := "postgres://user:secret@localhost:5432/testdb?pool_max_conns=20&pool_min_conns=5&statement_cache_capacity=0&default_query_exec_mode=simple_protocol&search_path=custom,public&sslmode=disable"

	// Single connection ParseConfig:
	connCfg, err := pgx.ParseConfig(dsn)
	if err != nil {
		t.Fatalf("pgx.ParseConfig failed: %v", err)
	}

	// Recognized pgx options are handled
	if connCfg.StatementCacheCapacity != 0 {
		t.Fatalf("expected StatementCacheCapacity=0, got %d", connCfg.StatementCacheCapacity)
	}
	if connCfg.DefaultQueryExecMode != pgx.QueryExecModeSimpleProtocol {
		t.Fatalf("expected DefaultQueryExecMode=simple_protocol, got %v", connCfg.DefaultQueryExecMode)
	}

	// Unrecognized pool options leak into RuntimeParams for single connection configs
	if connCfg.RuntimeParams["pool_max_conns"] != "20" || connCfg.RuntimeParams["pool_min_conns"] != "5" {
		t.Fatalf("expected pool options in RuntimeParams, got %v", connCfg.RuntimeParams)
	}
	if connCfg.RuntimeParams["search_path"] != "custom,public" {
		t.Fatalf("expected search_path in RuntimeParams, got %v", connCfg.RuntimeParams)
	}

	// Pool ParseConfig:
	poolCfg, err := pgxpool.ParseConfig(dsn)
	if err != nil {
		t.Fatalf("pgxpool.ParseConfig failed: %v", err)
	}
	if poolCfg.MaxConns != 20 || poolCfg.MinConns != 5 {
		t.Fatalf("expected pool MaxConns=20, MinConns=5, got max=%d, min=%d", poolCfg.MaxConns, poolCfg.MinConns)
	}
	// Pool-specific settings are stripped from the inner ConnConfig RuntimeParams
	if _, exists := poolCfg.ConnConfig.RuntimeParams["pool_max_conns"]; exists {
		t.Fatalf("expected pool_max_conns NOT in pool ConnConfig.RuntimeParams")
	}
	if _, exists := poolCfg.ConnConfig.RuntimeParams["pool_min_conns"]; exists {
		t.Fatalf("expected pool_min_conns NOT in pool ConnConfig.RuntimeParams")
	}
}

// 2. Query execution modes: Default extended protocol rejects multi-statement strings, while simple protocol succeeds.
func TestQueryExecMode_MultiStatement(t *testing.T) {
	// Default QueryExecModeCacheStatement (Extended Protocol)
	connDefault, ctxDefault := NewMockConn(t, nil)
	var valDefault int
	err := connDefault.QueryRow(ctxDefault, "SELECT 1; SELECT 2;").Scan(&valDefault)
	if err == nil || !strings.Contains(err.Error(), "cannot insert multiple commands into a prepared statement") {
		t.Fatalf("expected extended protocol failure on multi-statement query, got: %v", err)
	}

	// QueryExecModeSimpleProtocol (Simple Protocol)
	connSimple, ctxSimple := NewMockConn(t, func(c *pgx.ConnConfig) {
		c.DefaultQueryExecMode = pgx.QueryExecModeSimpleProtocol
	})
	var valSimple int
	err = connSimple.QueryRow(ctxSimple, "SELECT 1; SELECT 2;").Scan(&valSimple)
	if err != nil || valSimple != 42 {
		t.Fatalf("expected simple protocol success, got err=%v, val=%d", err, valSimple)
	}
}

// 3. Array scanning: NULL elements in arrays fail on []T but succeed on []*T and []pgtype.Int4.
// SQL NULL array vs empty array {} are distinctly mapped to nil vs non-nil empty slices.
func TestArrayScanning_NullElementsAndSlices(t *testing.T) {
	tm := pgtype.NewMap()

	// Text format array containing NULL element: "{10,NULL,30}"
	textNullArray := []byte("{10,NULL,30}")

	// Scanning into []int32 fails because int32 cannot represent NULL
	var ints []int32
	err := tm.Scan(pgtype.Int4ArrayOID, pgtype.TextFormatCode, textNullArray, &ints)
	if err == nil || !strings.Contains(err.Error(), "cannot scan NULL into *int32") {
		t.Fatalf("expected error scanning array with NULL element into []int32, got: %v", err)
	}

	// Scanning into []*int32 succeeds and populates nil for NULL elements
	var ptrInts []*int32
	err = tm.Scan(pgtype.Int4ArrayOID, pgtype.TextFormatCode, textNullArray, &ptrInts)
	if err != nil {
		t.Fatalf("expected []*int32 scan to succeed, got: %v", err)
	}
	if len(ptrInts) != 3 || ptrInts[0] == nil || *ptrInts[0] != 10 || ptrInts[1] != nil || ptrInts[2] == nil || *ptrInts[2] != 30 {
		t.Fatalf("unexpected ptrInts: %+v", ptrInts)
	}

	// Scanning into []pgtype.Int4 succeeds with Valid=false for NULL elements
	var pgInts []pgtype.Int4
	err = tm.Scan(pgtype.Int4ArrayOID, pgtype.TextFormatCode, textNullArray, &pgInts)
	if err != nil {
		t.Fatalf("expected []pgtype.Int4 scan to succeed, got: %v", err)
	}
	if len(pgInts) != 3 || !pgInts[0].Valid || pgInts[0].Int32 != 10 || pgInts[1].Valid || !pgInts[2].Valid || pgInts[2].Int32 != 30 {
		t.Fatalf("unexpected pgInts: %+v", pgInts)
	}

	// SQL NULL array (nil raw bytes) yields nil slice
	var sliceNull []string = []string{"initial"}
	err = tm.Scan(pgtype.TextArrayOID, pgtype.TextFormatCode, nil, &sliceNull)
	if err != nil || sliceNull != nil {
		t.Fatalf("expected nil slice for SQL NULL, got err=%v, slice=%v", err, sliceNull)
	}

	// SQL empty array "{}" yields non-nil slice with length 0
	var sliceEmpty []string = []string{"initial"}
	err = tm.Scan(pgtype.TextArrayOID, pgtype.TextFormatCode, []byte("{}"), &sliceEmpty)
	if err != nil || sliceEmpty == nil || len(sliceEmpty) != 0 {
		t.Fatalf("expected empty non-nil slice for {}, got err=%v, slice=%v", err, sliceEmpty)
	}

	// Multi-dimensional array: "{{1,2},{3,4}}" flattened into 1D slice via pgtype.FlatArray
	var flat pgtype.FlatArray[int32]
	err = tm.Scan(pgtype.Int4ArrayOID, pgtype.TextFormatCode, []byte("{{1,2},{3,4}}"), &flat)
	if err != nil {
		t.Fatalf("expected FlatArray scan to succeed, got: %v", err)
	}
	if len(flat) != 4 || flat[0] != 1 || flat[1] != 2 || flat[2] != 3 || flat[3] != 4 {
		t.Fatalf("unexpected flat array contents: %+v", flat)
	}
}

// 4. Batch execution: Failed query halts execution of subsequent queued queries, and Close() returns first error.
func TestBatchExecution_ErrorPropagation(t *testing.T) {
	conn, ctx := NewMockConn(t, nil)

	// Clean batch execution
	batch := &pgx.Batch{}
	batch.Queue("SELECT 1")
	batch.Queue("SELECT 2")

	br := conn.SendBatch(ctx, batch)
	var val1, val2 int
	if err := br.QueryRow().Scan(&val1); err != nil || val1 != 42 {
		t.Fatalf("expected val1=42, got err=%v, val=%d", err, val1)
	}
	if err := br.QueryRow().Scan(&val2); err != nil || val2 != 42 {
		t.Fatalf("expected val2=42, got err=%v, val=%d", err, val2)
	}

	// Reading beyond queued query count returns error
	var val3 int
	err := br.QueryRow().Scan(&val3)
	if err == nil || !strings.Contains(err.Error(), "no more results in batch") {
		t.Fatalf("expected 'no more results in batch' error, got: %v", err)
	}
	if err := br.Close(); err != nil {
		t.Fatalf("expected clean br.Close(), got: %v", err)
	}

	// Batch error propagation: First error halts subsequent queries
	batchFail := &pgx.Batch{}
	batchFail.Queue("SELECT FAIL")
	batchFail.Queue("SELECT 2")

	brFail := conn.SendBatch(ctx, batchFail)
	var fval1, fval2 int
	err1 := brFail.QueryRow().Scan(&fval1)
	if err1 == nil || !strings.Contains(err1.Error(), "relation does not exist") {
		t.Fatalf("expected relation error on first batch query, got: %v", err1)
	}

	err2 := brFail.QueryRow().Scan(&fval2)
	if err2 == nil {
		t.Fatalf("expected error on subsequent query after batch failure, got nil")
	}

	errClose := brFail.Close()
	if errClose == nil || !strings.Contains(errClose.Error(), "relation does not exist") {
		t.Fatalf("expected Close() to return first batch error, got: %v", errClose)
	}
}

// 5. Numeric handling: pgtype.Numeric retains exact fractional decimals, supports NaN, and Infinity modifiers.
func TestNumeric_PrecisionAndSpecialValues(t *testing.T) {
	tm := pgtype.NewMap()

	// Text format numeric "123.45"
	var num pgtype.Numeric
	err := tm.Scan(pgtype.NumericOID, pgtype.TextFormatCode, []byte("123.45"), &num)
	if err != nil {
		t.Fatalf("scan numeric failed: %v", err)
	}
	if !num.Valid || num.Exp != -2 || num.Int.Cmp(big.NewInt(12345)) != 0 {
		t.Fatalf("unexpected numeric representation: %+v", num)
	}

	// Int64Value fails on non-integer numeric (non-zero exponent)
	_, err = num.Int64Value()
	if err == nil {
		t.Fatalf("expected error converting fractional numeric to int64, got nil")
	}

	// Float64Value succeeds
	f, err := num.Float64Value()
	if err != nil || !f.Valid || math.Abs(f.Float64-123.45) > 1e-6 {
		t.Fatalf("expected 123.45 float, got err=%v, val=%v", err, f)
	}

	// Special numeric value: "NaN"
	var numNaN pgtype.Numeric
	err = tm.Scan(pgtype.NumericOID, pgtype.TextFormatCode, []byte("NaN"), &numNaN)
	if err != nil || !numNaN.Valid || !numNaN.NaN {
		t.Fatalf("expected NaN numeric, got err=%v, val=%+v", err, numNaN)
	}
	fNaN, err := numNaN.Float64Value()
	if err != nil || !math.IsNaN(fNaN.Float64) {
		t.Fatalf("expected NaN float, got err=%v, val=%v", err, fNaN)
	}

	// Special numeric value: "Infinity"
	var numInf pgtype.Numeric
	err = tm.Scan(pgtype.NumericOID, pgtype.TextFormatCode, []byte("Infinity"), &numInf)
	if err != nil || !numInf.Valid || numInf.InfinityModifier != pgtype.Infinity {
		t.Fatalf("expected Infinity numeric, got err=%v, val=%+v", err, numInf)
	}
	fInf, err := numInf.Float64Value()
	if err != nil || !math.IsInf(fInf.Float64, 1) {
		t.Fatalf("expected +Inf float, got err=%v, val=%v", err, fInf)
	}
}

Origin Seeder

csx-seed