Help us shape the future of Go! Take the 2026 Go Developer Survey

pgexec

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2026 License: MIT Imports: 10 Imported by: 1

Documentation

Overview

Package pgexec is the transport-neutral execution layer shared by pdbq and pdbr: pool setup, per-request transactions with RLS role switching and claims via set_config (SET LOCAL only, so pooled connections never leak identity), serialization-failure retries, identifier quoting, and PostgreSQL error classification with the dev/prod/strict message policy.

Index

Constants

View Source
const DefaultClaimsPrefix = "pdbq.claims"

DefaultClaimsPrefix is the set_config namespace used when Identity.ClaimsPrefix is empty (kept as pdbq's so existing RLS policies work with either product).

Variables

This section is empty.

Functions

func ApplyIdentity

func ApplyIdentity(ctx context.Context, tx Querier, id Identity) error

ApplyIdentity switches role and exposes claims inside an open transaction. It uses SET LOCAL exclusively (never SET) so pooled connections cannot leak request identity across requests once the connection is reused.

func Connect

func Connect(ctx context.Context, cfg PoolConfig) (*pgxpool.Pool, error)

Connect opens a pool. StatementTimeout > 0 is applied as the connection's statement_timeout runtime parameter (milliseconds).

func IsSerializationFailure

func IsSerializationFailure(err error) bool

IsSerializationFailure reports whether err carries SQLSTATE 40001 (serialization_failure) or 40P01 (deadlock_detected), anywhere in its wrap chain.

func ParseIsolation

func ParseIsolation(s string) pgx.TxIsoLevel

ParseIsolation maps the config spelling ("read_committed", "repeatable_read", "serializable") to pgx's level; anything else is ReadCommitted.

func QuoteIdent

func QuoteIdent(s string) string

QuoteIdent double-quotes an SQL identifier, doubling embedded quotes.

func RunTx

func RunTx(ctx context.Context, db TxBeginner, opts TxOptions, id Identity, fn func(q Querier) error) error

RunTx begins a transaction with opts.Isolation, applies the identity (RLS true), calls fn, and commits unless fn returned an error (rollback). The error from fn is returned as-is (unwrapped) so callers can inspect their own error types; begin/RLS/commit errors are returned raw too. On a serialization failure or deadlock — anywhere in the attempt — the whole thing re-runs up to opts.MaxRetries times, so fn may run more than once and must not have side effects outside the transaction.

func SanitizeMessage

func SanitizeMessage(pgErr *pgconn.PgError, strict bool) string

SanitizeMessage keeps actionable constraint-class errors and hides the rest behind a generic message. strict hides those too: PG constraint messages embed constraint/table/column names, which strict mode treats as sensitive.

func ValidClaimKey

func ValidClaimKey(s string) bool

ValidClaimKey reports whether s is a safe claim key for set_config (same alphabet as ValidRole).

func ValidRole

func ValidRole(s string) bool

ValidRole reports whether s is a safe role name: [A-Za-z0-9_]+.

Types

type Class

type Class int

Class is the transport-neutral error category. Products map it to an HTTP status (pdbr) or a GraphQL error shape (pdbq); the mapping table itself is product code.

const (
	// OK: err was nil.
	OK Class = iota
	// UserInput: 22* data exceptions, 23502/23514, and 42* other than 42501.
	UserInput
	// Permission: 42501 insufficient privilege.
	Permission
	// Conflict: 23505/23503/23P01 and 40001/40P01 (retries exhausted).
	Conflict
	// Resource: 53* insufficient resources, 08* connection exceptions,
	// 57P01-57P03 operator intervention, connect failures.
	Resource
	// Timeout: 57014 statement timeout or a context deadline.
	Timeout
	// Internal: everything else.
	Internal
)

func (Class) String

func (c Class) String() string

type Classified

type Classified struct {
	Class Class
	// SQLState is the five-character code, "" for non-PG errors.
	SQLState string
	// Message is the client-facing text after the Detail policy.
	Message string
	// PG is the underlying error for dev-mode extensions (detail, hint,
	// table, constraint); nil for non-PG errors.
	PG *pgconn.PgError
}

Classified is the result of Classify.

func Classify

func Classify(err error, detail Detail) Classified

Classify categorises err and renders its client-facing message.

type Detail

type Detail int

Detail is the errors.detail policy.

const (
	// Prod passes 22*/23* PG messages through and hides the rest.
	Prod Detail = iota
	// Dev exposes full PG messages (and non-PG error text).
	Dev
	// Strict hides every database message behind a generic one.
	Strict
)

func ParseDetail

func ParseDetail(s string) Detail

ParseDetail maps the config strings "dev", "prod", "strict"; anything else is Prod.

type Identity

type Identity struct {
	// Role is the database role to SET LOCAL ROLE to ("" = no switch).
	Role string
	// Claims are exposed as set_config(ClaimsPrefix.key, value, true).
	// String values are set verbatim; anything else is JSON-encoded. Keys
	// failing ValidClaimKey are skipped.
	Claims map[string]any
	// ClaimsPrefix defaults to DefaultClaimsPrefix.
	ClaimsPrefix string
}

Identity is the request identity applied inside a transaction.

type PoolConfig

type PoolConfig struct {
	URL              string
	MaxConns         int32
	ConnectTimeout   time.Duration
	StatementTimeout time.Duration
}

PoolConfig is the subset of database settings the pool needs.

type Querier

type Querier interface {
	Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
	QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
	Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
}

Querier is the statement-execution surface handed to callbacks; satisfied by *pgxpool.Pool, *pgx.Conn and pgx.Tx, so callers can run the same code inside and outside a transaction.

type TxBeginner

type TxBeginner interface {
	BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error)
}

TxBeginner starts transactions; satisfied by *pgxpool.Pool and *pgx.Conn.

type TxOptions

type TxOptions struct {
	Isolation pgx.TxIsoLevel
	// MaxRetries re-runs the whole transaction after a serialization
	// failure or deadlock (SQLSTATE 40001/40P01), no backoff.
	MaxRetries int
	// RLS enables the SET LOCAL ROLE + set_config claims step.
	RLS bool
	// Log receives the retry warning; nil uses slog.Default().
	Log *slog.Logger
}

TxOptions controls RunTx.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL