SQL SELECT parsing, purpose-fit for dependency tracking.
The grammar mirrors the SELECT-related productions of SQLite's own parse.y but is deliberately loose wherever looseness cannot hide a dependency: expression interiors are flat term/op token sequences, so operator precedence, CASE/CAST structure and window frames never matter - only that every identifier occurrence is captured as a ColumnRef, a table reference, or an alias.
Two soundness rules the looseness depends on:
No opaque blobs. Structural keywords (FROM, WHERE, JOIN, ...) are
never consumable inside expressions, so a clause skeleton cannot
be swallowed by an expression and lose a table reference. Bare
IN is only tokenisable when a parenthesis follows, so the
pathological x IN some_table fails to parse and falls back
conservatively instead of silently losing a table.
A leading '*' cannot start an expression (terms first, operators
after), so SELECT * is never misparsed as multiplication and a
star selector is never lost.
Remaining ambiguity is over-approximation, never loss: a function name parsed as a column, a window name parsed as a column - both merely over-trigger recomputation.
Anything unparseable is a parse failure; sqldeps maps that to the conservative :all dependency set. Identifier case is untouched here; sqldeps normalises, since SQLite's ASCII case-insensitivity applies equally to names coming from the database.
SQL SELECT parsing, purpose-fit for dependency tracking. The grammar mirrors the SELECT-related productions of SQLite's own parse.y but is deliberately loose wherever looseness cannot hide a dependency: expression interiors are flat term/op token sequences, so operator precedence, CASE/CAST structure and window frames never matter - only that every identifier occurrence is captured as a ColumnRef, a table reference, or an alias. Two soundness rules the looseness depends on: - No opaque blobs. Structural keywords (FROM, WHERE, JOIN, ...) are never consumable inside expressions, so a clause skeleton cannot be swallowed by an expression and lose a table reference. Bare IN is only tokenisable when a parenthesis follows, so the pathological `x IN some_table` fails to parse and falls back conservatively instead of silently losing a table. - A leading '*' cannot start an expression (terms first, operators after), so `SELECT *` is never misparsed as multiplication and a star selector is never lost. Remaining ambiguity is over-approximation, never loss: a function name parsed as a column, a window name parsed as a column - both merely over-trigger recomputation. Anything unparseable is a parse failure; sqldeps maps that to the conservative :all dependency set. Identifier case is untouched here; sqldeps normalises, since SQLite's ASCII case-insensitivity applies equally to names coming from the database.
(parse sql & opts)Parse a SELECT statement into a tag tree, or nil when the grammar does not cover it. Extra kwargs are forwarded to instaparse/parse (tests use :unhide). On ClojureScript the input is lowercased to compensate for JS regexes lacking inline flags.
Parse a SELECT statement into a tag tree, or nil when the grammar does not cover it. Extra kwargs are forwarded to instaparse/parse (tests use :unhide). On ClojureScript the input is lowercased to compensate for JS regexes lacking inline flags.
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 |