Liking cljdoc? Tell your friends :D

datahike.pg.sql

SQL → Datahike Datalog translator.

Parses SQL strings using JSqlParser and translates the AST into Datahike Datalog queries that can be executed by datahike.api/q.

The core mapping: attribute namespace prefixes become virtual table names. :person/name → table 'person', column 'name' :person/age → table 'person', column 'age'

Main entry points: (parse-sql sql schema) → {:type :select :query {...} :args [...]} | {:type :insert :tx-data [...]} | {:type :system :result QueryResult} | {:type :error :message str}

SQL → Datahike Datalog translator.

Parses SQL strings using JSqlParser and translates the AST into Datahike
Datalog queries that can be executed by `datahike.api/q`.

The core mapping: attribute namespace prefixes become virtual table names.
  :person/name  → table 'person', column 'name'
  :person/age   → table 'person', column 'age'

Main entry points:
  (parse-sql sql schema)  → {:type :select :query {...} :args [...]}
                           | {:type :insert :tx-data [...]}
                           | {:type :system :result QueryResult}
                           | {:type :error :message str}
raw docstring

*ast-cache*clj

Server-wide JSqlParser AST cache, keyed on the preprocessed SQL string. Tests can rebind to an isolated map; nil disables caching.

Server-wide JSqlParser AST cache, keyed on the preprocessed SQL
string. Tests can rebind to an isolated map; nil disables caching.
sourceraw docstring

*catalog-cache*clj

Tests can rebind this to an isolated java.util.Map to keep their data from polluting the global cache (or vice versa). Nil disables caching entirely. Defaults to the server-wide cache.

Tests can rebind this to an isolated `java.util.Map` to keep their
data from polluting the global cache (or vice versa). Nil disables
caching entirely. Defaults to the server-wide cache.
sourceraw docstring

*parse-cache*clj

Server-wide cache for parse-sql results. Tests can rebind to an isolated map; nil disables caching entirely.

Server-wide cache for parse-sql results. Tests can rebind to an
isolated map; nil disables caching entirely.
sourceraw docstring

cached-resultclj

(cached-result k f)

The value of (f), kept in the parse-sql result cache under k, with the same LRU bound and the same clearing on DDL. k must hold everything the value depends on. A result of :type :error, or one that reads a session value, is not kept.

The value of (f), kept in the parse-sql result cache under `k`, with
the same LRU bound and the same clearing on DDL. `k` must hold
everything the value depends on. A result of :type :error, or one
that reads a session value, is not kept.
sourceraw docstring

catalog-basis-ofclj

(catalog-basis-of db)

The exact catalog/schema comparison value of db, as the parse cache's own key takes it: what a cached translation is valid for.

The exact catalog/schema comparison value of `db`, as the parse cache's
own key takes it: what a cached translation is valid for.
sourceraw docstring

cte-namespaceclj

(cte-namespace n cte-name)

The synthetic storage namespace for the nth CTE named cte-name.

Deterministic — a pure function of the SQL text — because the parse caches key on [sql (hash schema)], and a gensym/nanoTime namespace would change the enriched schema on every parse and turn every CTE query into a total cache miss.

The __cte prefix is reserved: datahike.pg.schema/internal-attr? filters it so a CTE can never surface as a table in pg_class or information_schema.

The synthetic storage namespace for the `n`th CTE named `cte-name`.

Deterministic — a pure function of the SQL text — because the parse
caches key on `[sql (hash schema)]`, and a gensym/nanoTime namespace
would change the enriched schema on every parse and turn every CTE
query into a total cache miss.

The `__cte` prefix is reserved: `datahike.pg.schema/internal-attr?`
filters it so a CTE can never surface as a table in pg_class or
information_schema.
sourceraw docstring

enrich-db-with-catalogsclj

(enrich-db-with-catalogs db schema catalog-names)

Materialise the given catalog tables' schema + data on top of db, returning the enriched db (its :schema carries the catalog attrs). Returns db unchanged when catalog-names is empty.

Only catalog schema fragments are cached. Catalog rows are derived from this exact input DB and materialized on top of it on every call. Thus a catalog join cannot accidentally inherit another call's user rows. schema is db's user schema.

Materialise the given catalog tables' schema + data on top of `db`,
returning the enriched db (its `:schema` carries the catalog attrs).
Returns `db` unchanged when `catalog-names` is empty.

Only catalog schema fragments are cached. Catalog rows are derived from
this exact input DB and materialized on top of it on every call. Thus a
catalog join cannot accidentally inherit another call's user rows.
`schema` is `db`'s user schema.
sourceraw docstring

invalidate-catalog-cache!clj

(invalidate-catalog-cache!)

Clear cached catalog schema fragments. Rows and enriched database snapshots are not cached: catalog extensions may read arbitrary current user data.

Clear cached catalog schema fragments. Rows and enriched database snapshots
are not cached: catalog extensions may read arbitrary current user data.
sourceraw docstring

invalidate-parse-cache!clj

(invalidate-parse-cache!)

Clear the server-wide parse-sql result cache. Called from every DDL exec branch (via server/invalidate-schema-cache!). Exact cache keys also detect native catalog changes. The AST cache is untouched: JSqlParser output depends only on SQL text.

Clear the server-wide parse-sql result cache. Called from every DDL
exec branch (via server/invalidate-schema-cache!). Exact cache keys also
detect native catalog changes. The AST cache is untouched: JSqlParser
output depends only on SQL text.
sourceraw docstring

parse-sqlclj

(parse-sql sql schema)
(parse-sql sql schema db)

Parse a SQL statement and return a translation result.

Returns one of: {:type :select :query <datalog-map> :find-aliases [...] ...} {:type :insert :tx-data [...] :count N} {:type :update :table str :ns str :assignments [...] :where-expr expr} {:type :delete :table str :ns str :where-expr expr} {:type :ddl-create :tx-data [...]} {:type :system :system-type keyword} {:type :error :message str}

Optional db parameter enables subquery execution during translation.

Three cache levels stack:

  • Result cache (*parse-cache*) — for SQL strings re-issued verbatim (pgjdbc unnamed prepared statements, ORM select-by-id).
  • Lexical INSERT-VALUES templating + AST cache — for INSERT INTO t [(cols)] VALUES (lit, …) shapes the literals are captured, the SQL is normalised to (? , …), and the resulting AST is reused across all rows of the same shape. Translation still runs per row with *bound-params* bound so JdbcParameter nodes resolve to concrete values inline (no ParamRef closure captures).
  • AST cache (*ast-cache*) — covers everything else that hits JSqlParser, repeated or not.
Parse a SQL statement and return a translation result.

Returns one of:
  {:type :select :query <datalog-map> :find-aliases [...] ...}
  {:type :insert :tx-data [...] :count N}
  {:type :update :table str :ns str :assignments [...] :where-expr expr}
  {:type :delete :table str :ns str :where-expr expr}
  {:type :ddl-create :tx-data [...]}
  {:type :system :system-type keyword}
  {:type :error :message str}

Optional db parameter enables subquery execution during translation.

Three cache levels stack:
  - **Result cache** (`*parse-cache*`) — for SQL strings re-issued
    verbatim (pgjdbc unnamed prepared statements, ORM select-by-id).
  - **Lexical INSERT-VALUES templating** + AST cache — for `INSERT
    INTO t [(cols)] VALUES (lit, …)` shapes the literals are
    captured, the SQL is normalised to `(? , …)`, and the resulting
    AST is reused across all rows of the same shape. Translation
    still runs per row with `*bound-params*` bound so JdbcParameter
    nodes resolve to concrete values inline (no ParamRef closure
    captures).
  - **AST cache** (`*ast-cache*`) — covers everything else that
    hits JSqlParser, repeated or not.
sourceraw docstring

simple-query-param-errorclj

(simple-query-param-error sql)

An {:type :error} map when sql uses a $N placeholder in the SIMPLE query protocol, else nil.

Simple Query has no Bind step, so there is nothing a placeholder could refer to and PostgreSQL raises 42P02. We used to translate the statement anyway and let the unresolved placeholder reach the client: SELECT $1 answered with the internal ParamRef record rendered as {"idx":1} — leaking a representation detail as if it were data.

Only reachable from the simple path; the extended path resolves placeholders at Bind. Gated on an indexOf so statements without a $ never pay for tokenising, and driven off the tokeniser's :param classification so a $ inside a string, a dollar-quoted body or a quoted identifier doesn't count.

An `{:type :error}` map when `sql` uses a `$N` placeholder in the
SIMPLE query protocol, else nil.

Simple Query has no Bind step, so there is nothing a placeholder
could refer to and PostgreSQL raises 42P02. We used to translate the
statement anyway and let the unresolved placeholder reach the client:
`SELECT $1` answered with the internal ParamRef record rendered as
`{"idx":1}` — leaking a representation detail as if it were data.

Only reachable from the simple path; the extended path resolves
placeholders at Bind. Gated on an indexOf so statements without a
`$` never pay for tokenising, and driven off the tokeniser's `:param`
classification so a `$` inside a string, a dollar-quoted body or a
quoted identifier doesn't count.
sourceraw docstring

translation-contextclj

(translation-context)

What a translation depends on besides its SQL, schema and catalog: the declared parameter types, the session's temp tables, whether the SQL is nested in a statement (see params/nested-parse?), search_path, DateStyle and the database. The cache is server-wide and its keys compare by value, so two databases built by the same DDL have equal schemas and an equal catalog basis; without the name they would share a plan.

DateStyle belongs here because it is read at TRANSLATE time: a literal date is decoded and folded while translating, so '8/10/2017'::date is a different value under MDY and under DMY. Without it in the key the first execution's answer was served to the second, and SET datestyle TO dmy appeared to do nothing under any driver using the extended protocol -- psql's simple queries happened to miss the cache and looked correct.

What a translation depends on besides its SQL, schema and catalog: the
declared parameter types, the session's temp tables, whether the SQL is
nested in a statement (see params/*nested-parse?*), search_path,
DateStyle and the database. The cache is server-wide and its keys
compare by value, so two databases built by the same DDL have equal
schemas and an equal catalog basis; without the name they would share
a plan.

DateStyle belongs here because it is read at TRANSLATE time: a
literal date is decoded and folded while translating, so
`'8/10/2017'::date` is a different value under MDY and under DMY.
Without it in the key the first execution's answer was served to the
second, and `SET datestyle TO dmy` appeared to do nothing under any
driver using the extended protocol -- psql's simple queries happened
to miss the cache and looked correct.
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