Token-driven SQL source rewrites. Normalize SQL before JSqlParser sees it by excising or injecting source-level spans — all based on positions captured by the datahike.pg.classify tokenizer.
Each rule is a pure function (tokens) -> seq of spans, where a
span is [start end replacement]. The rewriter applies all non-
overlapping spans right-to-left (so earlier offsets stay stable)
and returns the new SQL string.
Why this exists: the previous preprocess-sql was a pile of regex
str/replace calls that could false-positive on keywords inside
string literals, dollar-quotes, or comments (SELECT 'REFERENCES'
was vulnerable to the inline-REFERENCES stripper). Token-based
rules only match tokens of the right kind, so a keyword inside a
:string or :comment is invisible to them.
Callers: sql/preprocess-sql.
Token-driven SQL source rewrites. Normalize SQL before JSqlParser sees it by excising or injecting source-level spans — all based on positions captured by the datahike.pg.classify tokenizer. Each rule is a pure function `(tokens) -> seq of spans`, where a span is `[start end replacement]`. The rewriter applies all non- overlapping spans right-to-left (so earlier offsets stay stable) and returns the new SQL string. Why this exists: the previous preprocess-sql was a pile of regex `str/replace` calls that could false-positive on keywords inside string literals, dollar-quotes, or comments (`SELECT 'REFERENCES'` was vulnerable to the inline-REFERENCES stripper). Token-based rules only match tokens of the right kind, so a keyword inside a :string or :comment is invisible to them. Callers: sql/preprocess-sql.
(create-index-anonymous-rule toks)CREATE [UNIQUE] INDEX ON … → inject idx_auto_<N> between INDEX
and ON. PG allows unnamed indexes; JSqlParser doesn't. The counter
is process-wide and monotonic; collisions across handler sessions
are harmless because the name is thrown away by the :create-index
no-op handler anyway.
`CREATE [UNIQUE] INDEX ON …` → inject `idx_auto_<N>` between INDEX and ON. PG allows unnamed indexes; JSqlParser doesn't. The counter is process-wide and monotonic; collisions across handler sessions are harmless because the name is thrown away by the :create-index no-op handler anyway.
Rules replacing the most-error-prone regex replacements in the old preprocess-sql. Others (reserved-word quoting, ALTER TABLE TYPE USING stripping, complex DEFAULT paren-peel, ALTER COLUMN DROP DEFAULT) remain as regex in sql.clj for now — they're narrow enough that the regex is low-risk. Migrate them incrementally as needed.
Rules replacing the most-error-prone regex replacements in the old preprocess-sql. Others (reserved-word quoting, ALTER TABLE TYPE USING stripping, complex DEFAULT paren-peel, ALTER COLUMN DROP DEFAULT) remain as regex in sql.clj for now — they're narrow enough that the regex is low-risk. Migrate them incrementally as needed.
(inline-references-rule toks)Inline REFERENCES name [(cols)] [ON (DELETE|UPDATE) action] —
strip it (our EAV model doesn't enforce inline FKs; callers must
use the table-level FOREIGN KEY (col) REFERENCES … form to get
enforcement). Before stripping, if the action is CASCADE / SET
NULL / SET DEFAULT, raise 0A000 — we can't silently drop an
unsupported action.
Distinguishes inline from table-level by checking the previous
non-comment token: if it's ) (from FOREIGN KEY (col)), we
leave it alone so JSqlParser parses it as a ForeignKeyIndex.
Inline `REFERENCES name [(cols)] [ON (DELETE|UPDATE) action]` — strip it (our EAV model doesn't enforce inline FKs; callers must use the table-level `FOREIGN KEY (col) REFERENCES …` form to get enforcement). Before stripping, if the action is CASCADE / SET NULL / SET DEFAULT, raise 0A000 — we can't silently drop an unsupported action. Distinguishes inline from table-level by checking the previous non-comment token: if it's `)` (from `FOREIGN KEY (col)`), we leave it alone so JSqlParser parses it as a ForeignKeyIndex.
(rewrite sql rules)Apply rules to sql and return the rewritten string.
Each rule is a (tokens) -> seq of [start end replacement] fn.
Throws exceptions from rules upward (callers rely on this for
unsupported-feature detection — e.g. FK ON DELETE CASCADE).
Apply rules to sql and return the rewritten string. Each rule is a `(tokens) -> seq of [start end replacement]` fn. Throws exceptions from rules upward (callers rely on this for unsupported-feature detection — e.g. FK ON DELETE CASCADE).
(select-from-rule toks)SELECT FROM … (empty projection) → SELECT 1 FROM …. PG allows
projection-less SELECT in EXISTS subqueries; JSqlParser doesn't.
`SELECT FROM …` (empty projection) → `SELECT 1 FROM …`. PG allows projection-less SELECT in EXISTS subqueries; JSqlParser doesn't.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |