Skip to content

Scan SQL for placeholders and named parameters while skipping literals, identifiers, comments and casts. - #23

Merged
avgvi merged 2 commits into
masterfrom
feat/sql-scanner
Oct 11, 2026
Merged

avgvi merged 2 commits into
masterfrom
feat/sql-scanner

Conversation

@avgvi

@avgvi avgvi commented Oct 11, 2026

Copy link
Copy Markdown
Member

One scanner, scan.go, walks a query once and reports only three tokens: a ? placeholder, the ?? escape and a :name parameter. String literals (with '' doubling, Postgres E'...' escapes and a heuristic for MySQL \'), double-quoted and backtick identifiers, -- and nested /* */ comments and Postgres $tag$ quotes are opaque; [...] identifiers are recognised for the AT bind type only; # is not a comment. Rebind, In and compileNamedQuery all use it, and compileNamedQuery now takes a string.

What that fixes, by upstream issue: a ? inside a literal or comment counted by In (#961, #487, #608) and renumbered by Rebind (the half #984 left out); a : inside a literal or comment taken for a parameter (#206, #253, #302, #368, #443, #872, #947, #394, #894); a trailing name lost at the end of the query (#441); a cast attached to a parameter, :id::uuid (#983); a cast anywhere else, now()::date (#428, #650, #956); non-ASCII parameter names. It supersedes upstream #151, #474, #775, #984, #985 and #1002, whose approaches are credited in the changelog.

Behaviour changes, each getting a changelog line: the documented :: escape is gone, so :: is a cast and :::: stays four colons (a code search found two repositories using the escape against about sixty relying on casts that failed); ?? is a literal ? in In and Rebind, so Rebind(QUESTION, q) is no longer an identity for a query containing ??; a parameter name can no longer start with a digit.

Tests: the 91-row matrix from the design work for In, Rebind and compileNamedQuery; the two :: rows of TestCompileQuery updated; the Unicode row that was commented out since 2013 enabled; TestEscapedColons, skipped since 2015, enabled; #920's comment case now asserts success; and TestNamedPostgresTypeCast runs the cast query end to end on Postgres, failing on master with the exact upstream error. Local run with Postgres 16, MySQL 8.4 and SQLite: 239 pass, 2 skip, 0 fail. Benchmarks on this machine: Rebind 166 to 232 ns, In 113 to 136 ns, allocations unchanged.

@avgvi
avgvi merged commit c9e81f0 into master Oct 11, 2026
6 checks passed
@avgvi
avgvi deleted the feat/sql-scanner branch October 11, 2026 04:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant