Skip to content

feat: bind SQL parameters safely and fail before writing output - #15

Merged
omer-cengel merged 1 commit into
masterfrom
feature/safe-sql-parameter-binding
Sep 18, 2026
Merged

omer-cengel merged 1 commit into
masterfrom
feature/safe-sql-parameter-binding

Conversation

@omer-cengel

Copy link
Copy Markdown
Member

Summary

Generated code is only trustworthy if every placeholder in the SQL it executes
has exactly one known Java value behind it. sqlcj previously substituted
placeholder text across the whole query string and analyzed only some of the
expressions it accepted, so a query could compile and still execute SQL whose
markers did not line up with the arguments passed to it. Parameter handling is
now driven by the SQL parser's own tokens, and a query that cannot be bound
safely fails at compile time with a diagnostic that names where it came from.

Changes

  • Replace only the $N parameter tokens the SQL parser actually reported,
    copying every other source byte unchanged, so placeholder-like text inside
    string literals, quoted identifiers, and comments survives byte for byte.
  • Require the parameters resolved against the schema to match the parsed
    placeholder tokens exactly, in the same textual order, so a placeholder in a
    location sqlcj does not analyze is a compile error instead of an argument
    list that silently comes up short.
  • Allow a $N index to repeat or appear out of order: the generated method
    exposes one correctly typed parameter per logical index, and the runtime
    receives that value once per textual ? position.
  • Reject placeholders that cannot be bound — anonymous ?, named :name,
    index $0, gapped indexes, and an index whose occurrences infer conflicting
    Java types — with a focused message that names the offending placeholder.
  • Validate annotation and statement compatibility: SELECT must be :one or
    :many, supported writes must be :exec, and RETURNING is rejected.
  • Report a failure with its source path, query name, header line, and a single
    focused reason instead of a stack trace.
  • Analyze, generate, and collision-check every configured entry before writing
    any file, so a failure in a later source cannot leave a mixture of old and
    new generated classes behind.

Scope and non-goals

The supported SQL subset is unchanged: this affects how the existing SELECT,
single-row INSERT, direct-placeholder UPDATE, and single-table DELETE
shapes are compiled, not which shapes are accepted. No new projections,
predicates, join kinds, write shapes, or SQL types are added, RETURNING stays
unsupported, named parameters and query macros remain out of scope, and SQL is
never reformatted or rewritten beyond parameter markers. The sample
queries.sql now uses $1 where it previously used an anonymous ?.

@omer-cengel
omer-cengel merged commit 8ef4eab into master Sep 18, 2026
6 checks passed
@omer-cengel
omer-cengel deleted the feature/safe-sql-parameter-binding branch September 18, 2026 18:04
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