db

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrLockAlreadyAcquired = errors.New("lock already acquired")

ErrLockAlreadyAcquired is returned by AcquireLock when called on a *Postgres that already holds the advisory lock.

View Source
var ErrLockNotAcquired = errors.New("lock not acquired")

ErrLockNotAcquired is returned by ReleaseLock when called on a *Postgres that does not currently hold the advisory lock.

View Source
var ErrLockNotHeld = errors.New("advisory lock was not held at release time")

ErrLockNotHeld is returned by ReleaseLock when pg_advisory_unlock reports the lock was not held by this session, meaning something released it out of band.

View Source
var ErrLockTimeout = errors.New("timed out waiting for the migration advisory lock")

ErrLockTimeout is returned by AcquireLock when the configured lock timeout elapsed while waiting, which means another process holds the migration lock. Postgres aborts the waiting statement itself, so this reliably means the lock was not granted.

View Source
var ErrPoolTooSmall = errors.New(
	"sql.DB allows only 1 open connection: the advisory lock pins a dedicated " +
		"connection for the whole migration run, so at least 2 concurrent connections " +
		"are required (call SetMaxOpenConns(0) or >= 2)",
)

ErrPoolTooSmall is returned by AcquireLock when the underlying *sql.DB is configured with SetMaxOpenConns(1). The advisory lock pins a dedicated connection for the whole migration run, so at least 2 concurrent connections are required or every other query would block forever waiting for a connection that can never free up.

Functions

This section is empty.

Types

type Postgres

type Postgres struct {
	// contains filtered or unexported fields
}

func NewPostgresFromDB

func NewPostgresFromDB(db *sql.DB, cfg PostgresConfig) *Postgres

NewPostgresFromDB wraps an already-open *sql.DB (opened by the caller with whatever driver they choose) in a *Postgres. See internal/dbconn for a pgx-backed constructor that opens the connection itself.

func (*Postgres) AcquireLock

func (p *Postgres) AcquireLock(ctx context.Context) error

AcquireLock acquires the advisory lock on a dedicated connection, waiting at most the configured lock timeout.

The timeout is enforced by the server via lock_timeout rather than by cancelling the query from the client. That distinction matters: a cancelled query may already have been granted the lock, and since the connection then goes back to the pool rather than being closed, the lock would be stranded on a pooled connection with nothing tracking it. A server-side abort is unambiguous — the lock was not granted.

lock_timeout is set with transaction scope, so it reverts on COMMIT and never leaks onto the pooled connection. The advisory lock is session-scoped and outlives that transaction.

func (*Postgres) Close

func (p *Postgres) Close() error

func (*Postgres) ExportLockConn

func (p *Postgres) ExportLockConn() *sql.Conn

ExportLockConn exposes the private lockConn field for testing.

func (*Postgres) GetDB

func (p *Postgres) GetDB() *sql.DB

func (*Postgres) ReleaseLock

func (p *Postgres) ReleaseLock(ctx context.Context) error

ReleaseLock releases the advisory lock and returns the dedicated connection to the pool.

The release is not optional. (*sql.Conn).Close only returns the connection to the pool — the session stays alive, so a session-level advisory lock survives it. If the lock cannot be confirmed released, the connection is destroyed rather than reused, since Postgres does release the lock when the session actually ends.

type PostgresConfig

type PostgresConfig struct {
	// DSN, when set, is used verbatim and every discrete field below is ignored.
	// Both the URL form ("postgres://user:pass@host/db?sslmode=require") and the
	// keyword/value form ("host=... dbname=...") are accepted, since pgx parses
	// either.
	DSN string

	Host     string
	Port     string
	User     string
	Password string
	DBName   string

	// SSLMode maps to libpq's sslmode. Empty leaves it unset, so the driver's
	// own default applies ("prefer": TLS when the server offers it, plaintext
	// otherwise). Managed Postgres generally needs "require" or stricter.
	SSLMode string

	// LockTimeout bounds the wait for the advisory lock. Zero is ambiguous on its
	// own, so LockTimeoutSet says whether it was configured: unset means the
	// default, an explicit zero means wait indefinitely (Postgres' lock_timeout=0).
	LockTimeout    time.Duration
	LockTimeoutSet bool

	LockID int64
}

func (PostgresConfig) GetDataSource

func (c PostgresConfig) GetDataSource() string

GetDataSource returns the connection string.

A DSN set explicitly is returned as-is. Otherwise a keyword/value string is built from the discrete fields, quoting values per libpq's rules: a value is wrapped in single quotes (with internal \ and ' backslash-escaped) when it contains whitespace, a single quote or a backslash.

Empty fields are omitted rather than emitted as empty values, so that the driver's defaults and the standard PG* environment variables still apply to anything not configured here. Emitting them bare would be unsafe in any case: libpq's parser swallows the next key=value pair as the value of an empty key.

Jump to

Keyboard shortcuts

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