Files
base/core/db_connect_postgres.go
zeekayandHanzo Dev 4bbbc5560d settings encrypt on Postgres, and the write pool is not pinned to one
Three things kept the sql tier from being the tier it is described as.

Settings encryption refused to boot. The ciphertext is base64 and the column
is jsonb, so Postgres rejected the insert while parsing it as JSON. It is
marshalled as a JSON string now and unwrapped on read. This changes the
stored shape: a legacy row is read as-is and rewritten on the first settings
write, after which an older binary refuses to start rather than misreading
it. Forward-only, and loud in the one direction that is not.

Every schema change caused a burst of failures. A pooled connection holds a
prepared plan whose result type the change invalidates, so the next read on
that connection fails once. Reads across twenty add-a-field rounds went from
83 of 160 to 160 of 160. The exec mode is describe_exec, which pgx documents
as the one that stays safe when the schema changes underneath it; it costs a
parse per execution, worst measured on a local socket and pipelined into the
same round trip over a real network.

The write pool was capped at one connection on every engine. That is SQLite's
single-writer rule and Postgres does not need it. The cap is asked of the
connection's own driver now, so the aux database answers for itself.

Lifting it makes lock-order deadlocks reachable in one process, where a single
connection had been serialising them away. Retrying a serialization failure is
what turns concurrent writes from possible into correct.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-13 12:26:38 -07:00

38 lines
1014 B
Go

//go:build !no_pg_driver
package core
import (
"fmt"
"github.com/hanzoai/dbx"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/stdlib"
)
// PostgresDBConnect creates a new PostgreSQL database connection.
// The dsn should be a PostgreSQL connection string like:
// "postgres://user:pass@host:5432/dbname?sslmode=disable"
//
// Sizing the pool is the caller's, the same as for a SQLite connection.
func PostgresDBConnect(dsn string) (*dbx.DB, error) {
config, err := pgx.ParseConfig(dsn)
if err != nil {
return nil, fmt.Errorf("failed to parse PostgreSQL DSN: %w", err)
}
// a statement is described where it is executed, so a connection already
// in the pool serves the schema as it stands rather than as it stood
config.DefaultQueryExecMode = pgx.QueryExecModeDescribeExec
db := dbx.NewFromDB(stdlib.OpenDB(*config), "pgx")
// Verify connection
if err := db.DB().Ping(); err != nil {
db.Close()
return nil, fmt.Errorf("failed to connect to PostgreSQL: %w", err)
}
return db, nil
}