Liking cljdoc? Tell your friends :D

datahike.pg.errors

Exception → PostgreSQL ErrorResponse classification for the pgwire layer. Owns three things:

  1. Mapping a Throwable → SQLSTATE code (the wire ABI clients branch on).
  2. Producing a PG-shaped user-facing message (don't leak Datahike vocabulary like :foo/bar, {:db/id 47, …}).
  3. Populating the ErrorResponse fields (n / t / c / d / D / H) that ORMs read via getServerErrorMessage() / Diagnostics.constraint_name.

Throw sites within datahike.pg.* describe errors structurally:

(throw (ex-info "<short internal description>" {:error :undefined-column :table "employee" :column "dept_id"}))

The wire boundary (classify-exception) then derives:

  • SQLSTATE via error-categories
  • message via the category's :format fn (falls back to the throw site's own message when nil)
  • fields via extract-error-fields

Why centralised formatting

PG's own backend works the same way: throw sites call ereport(ERROR, errcode(ERRCODE_UNDEFINED_COLUMN), errmsg(...)) with structured args; the wire layer (pqcomm.c) emits the protocol message from the resulting ErrorData struct. There is no report_undefined_column() helper at every throw site. That's the pattern this namespace implements.

Lookup order in classify-exception

  1. Explicit :sqlstate in ex-data (override; bypasses formatter).
  2. :error key in error-categories
    • SQLSTATE from the registry
    • message from the entry's :format fn (or fallback)
  3. :datahike/canceled in ex-data → "57014" (cancelled).
  4. Datahike-emitted message regex (classify-message) — a last-resort safety net for unstructured errors thrown by Datahike core that we don't own. New pgwire throws should NOT rely on this.
  5. Fallback: "XX000" (internal_error).

Categories

Pgwire-side throw categories live in error-categories. Each entry has a :sqlstate and an optional :format fn. Datahike-internal :error keys map directly to SQLSTATEs (no formatter — Datahike's own message text comes through, with the SQLAlchemy-class missing-attribute case rewritten to PG vocabulary).

Canonical PG code list: postgres/src/backend/utils/errcodes.txt.

Exception → PostgreSQL ErrorResponse classification for the pgwire
layer. Owns three things:

  1. Mapping a Throwable → SQLSTATE code (the wire ABI clients
     branch on).
  2. Producing a PG-shaped user-facing message (don't leak
     Datahike vocabulary like `:foo/bar`, `{:db/id 47, …}`).
  3. Populating the ErrorResponse fields (n / t / c / d / D / H)
     that ORMs read via `getServerErrorMessage()` /
     `Diagnostics.constraint_name`.

Throw sites within `datahike.pg.*` describe errors structurally:

  (throw (ex-info "<short internal description>"
                  {:error :undefined-column
                   :table "employee"
                   :column "dept_id"}))

The wire boundary (`classify-exception`) then derives:
  - SQLSTATE  via `error-categories`
  - message   via the category's `:format` fn (falls back to the
              throw site's own message when nil)
  - fields    via `extract-error-fields`

## Why centralised formatting

PG's own backend works the same way: throw sites call
`ereport(ERROR, errcode(ERRCODE_UNDEFINED_COLUMN), errmsg(...))`
with structured args; the wire layer (`pqcomm.c`) emits the protocol
message from the resulting `ErrorData` struct. There is no
`report_undefined_column()` helper at every throw site. That's the
pattern this namespace implements.

## Lookup order in classify-exception

  1. Explicit `:sqlstate` in ex-data (override; bypasses formatter).
  2. `:error` key in `error-categories` →
       - SQLSTATE from the registry
       - message from the entry's `:format` fn (or fallback)
  3. `:datahike/canceled` in ex-data → "57014" (cancelled).
  4. Datahike-emitted message regex (`classify-message`) — a
     last-resort safety net for unstructured errors thrown by
     Datahike core that we don't own. New pgwire throws should NOT
     rely on this.
  5. Fallback: "XX000" (internal_error).

## Categories

Pgwire-side throw categories live in `error-categories`. Each entry
has a `:sqlstate` and an optional `:format` fn. Datahike-internal
`:error` keys map directly to SQLSTATEs (no formatter — Datahike's
own message text comes through, with the SQLAlchemy-class
missing-attribute case rewritten to PG vocabulary).

Canonical PG code list: postgres/src/backend/utils/errcodes.txt.
raw docstring

classify-exceptionclj

(classify-exception e)

Map a Throwable to [sqlstate message fields] for emission via the pgwire ErrorResponse. Falls back to ["XX000" <some-msg> nil] when no rule matches.

Resolution order (first match wins):

  1. Explicit :sqlstate in ex-data — full override; uses the throw site's own message.
  2. :error key matched against error-categories — derives SQLSTATE; runs the category's :format fn over ex-data; if the formatter returns a string, that's the user-facing message, otherwise the throw site's message stands.
  3. :datahike/canceled flag → 57014.
  4. :error key matched against dh-error->sqlstate (Datahike internal). Tries rewrite-datahike-message to upgrade the message + extract extra fields.
  5. rewrite-datahike-message on a bare message (no error key).
  6. classify-message regex (last-resort SQLSTATE only).
  7. Fallback XX000.

fields is a Java Map<String,String> of optional ErrorResponse field codes (n, t, c, d, D, H), or nil.

Map a Throwable to `[sqlstate message fields]` for emission via the
pgwire ErrorResponse. Falls back to `["XX000" <some-msg> nil]`
when no rule matches.

Resolution order (first match wins):
  1. Explicit `:sqlstate` in ex-data — full override; uses the
     throw site's own message.
  2. `:error` key matched against `error-categories` — derives
     SQLSTATE; runs the category's `:format` fn over ex-data; if
     the formatter returns a string, that's the user-facing
     message, otherwise the throw site's message stands.
  3. `:datahike/canceled` flag → 57014.
  4. `:error` key matched against `dh-error->sqlstate` (Datahike
     internal). Tries `rewrite-datahike-message` to upgrade the
     message + extract extra fields.
  5. `rewrite-datahike-message` on a bare message (no error key).
  6. `classify-message` regex (last-resort SQLSTATE only).
  7. Fallback `XX000`.

`fields` is a Java Map<String,String> of optional ErrorResponse
field codes (n, t, c, d, D, H), or nil.
sourceraw docstring

classify-messageclj

(classify-message msg)

Last-resort SQLSTATE-only classifier for Datahike messages we can't structurally rewrite. Returns the SQLSTATE code or nil. Used only when ex-data has no :error / :sqlstate and rewrite-datahike-message doesn't match.

Do not add new reliance on this from pgwire code — set :error or :sqlstate at the throw site instead.

Last-resort SQLSTATE-only classifier for Datahike messages we can't
structurally rewrite. Returns the SQLSTATE code or nil. Used only
when ex-data has no `:error` / `:sqlstate` and
`rewrite-datahike-message` doesn't match.

Do not add new reliance on this from pgwire code — set `:error` or
`:sqlstate` at the throw site instead.
sourceraw docstring

dh-error->sqlstateclj

Map Datahike's :error keyword (set by datahike core when it raises ex-info) to a PG SQLSTATE. Covers errors the wire layer doesn't throw itself but receives via the cause chain.

Datahike's messages are unstructured; the wire layer uses them verbatim unless rewrite-datahike-message recognises a known pattern and produces a PG-shaped substitute.

Map Datahike's `:error` keyword (set by datahike core when it raises
ex-info) to a PG SQLSTATE. Covers errors the wire layer doesn't
throw itself but receives via the cause chain.

Datahike's messages are unstructured; the wire layer uses them
verbatim unless `rewrite-datahike-message` recognises a known
pattern and produces a PG-shaped substitute.
sourceraw docstring

error-categoriesclj

Pgwire-side error categories. Throw sites set :error in ex-data to one of these keys.

The :format fn receives the full ex-data map and returns the PG-shaped user-facing message, or nil to fall through to the throw site's own message string.

Pgwire-side error categories. Throw sites set `:error` in ex-data to
one of these keys.

The `:format` fn receives the full ex-data map and returns the
PG-shaped user-facing message, or nil to fall through to the
throw site's own message string.
sourceraw docstring

pg-errorclj

(pg-error category data)

Build an ex-info whose message is the PG-shaped formatted form for the category + data, suitable to pass to throw. Sets :error so classify-exception produces the right SQLSTATE + fields when the exception flows through the wire boundary's catch.

Throw sites should prefer this over raw ex-info because:

  • .getMessage(e) returns the PG-shaped string directly, so paths that bypass classify-exception (e.g. QueryHandler.parse() going straight to the Java wire layer) still produce a correct user-facing message.
  • The full ex-data is preserved so downstream classifier passes extract structured fields (table, column, constraint, …).
Build an ex-info whose message is the PG-shaped formatted form for
the category + data, suitable to pass to `throw`. Sets `:error` so
`classify-exception` produces the right SQLSTATE + fields when the
exception flows through the wire boundary's catch.

Throw sites should prefer this over raw `ex-info` because:
- `.getMessage(e)` returns the PG-shaped string directly, so paths
  that bypass `classify-exception` (e.g. QueryHandler.parse() going
  straight to the Java wire layer) still produce a correct
  user-facing message.
- The full ex-data is preserved so downstream classifier passes
  extract structured fields (table, column, constraint, …).
sourceraw docstring

pg-error-messageclj

(pg-error-message category data)

Return the PG-shaped formatted message for category given data, or nil when the category has no formatter or it doesn't produce a message for the given data.

Return the PG-shaped formatted message for `category` given `data`,
or nil when the category has no formatter or it doesn't produce
a message for the given data.
sourceraw docstring

rewrite-datahike-messageclj

(rewrite-datahike-message msg)

Translate a Datahike-emitted error message into PG vocabulary. Returns [code message extra-fields] if the message matches a known pattern, nil otherwise.

Datahike's :transact/schema for an unknown attribute reads: Bad entity attribute :employee/dept_id at {:db/id 47, …}, not defined in current schema PG would say: column "dept_id" of relation "employee" does not exist with SQLSTATE 42703 (UndefinedColumn). Without this rewrite, SQL clients see SQLSTATE 22P02 (InvalidTextRepresentation) and :db/id 47 in the user-facing string.

Translate a Datahike-emitted error message into PG vocabulary.
Returns `[code message extra-fields]` if the message matches a
known pattern, nil otherwise.

Datahike's `:transact/schema` for an unknown attribute reads:
  `Bad entity attribute :employee/dept_id at {:db/id 47, …},
   not defined in current schema`
PG would say:
  `column "dept_id" of relation "employee" does not exist`
with SQLSTATE 42703 (UndefinedColumn). Without this rewrite,
SQL clients see SQLSTATE 22P02 (InvalidTextRepresentation) and
`:db/id 47` in the user-facing string.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close