fix(codegen): make dynamic-slice queries compile on sqlx 0.9 - #50
Merged
Merged
Conversation
`sqlc.slice()` parameters that cannot use `= ANY($1)` build their SQL at run
time, and the generated code passed the result as `sqlx::query_as(&sql)`. sqlx
0.9 replaced the `&'q str` parameter with `impl SqlSafeStr`, which is only
implemented for `&'static str` — so every such query fails to compile against
the sqlx version this workspace already declares:
error[E0277]: dynamic SQL strings should be audited for possible injections
Run-time SQL now goes through `sqlx::AssertSqlSafe`, the escape hatch 0.9 added
for exactly this case. The strings are assembled by the generator from the query
text and a placeholder count — no user input reaches them — so the assertion is
sound.
This went unnoticed because nothing exercised the combination: the e2e fixtures
pinned sqlx 0.8, and no example has a `sqlc.slice()` query that misses the
`= ANY($1)` fast path. The fixtures move to 0.9 so the suite now covers the same
version the workspace does.
`AssertSqlSafe` does not exist in 0.8, so generated code cannot support both;
0.9 is now the floor, and the README says so. Only the two dynamic-slice
snapshots change — every other query still passes a `&'static str` const.
jrandolf
force-pushed
the
fix/sqlx-0.9-dynamic-slice
branch
from
September 26, 2026 01:46
4ba81ad to
e22eada
Compare
jrandolf
added a commit
that referenced
this pull request
Sep 26, 2026
🤖 I have created a release *beep* *boop* --- ## [0.2.7](v0.2.6...v0.2.7) (2026-09-26) ### Bug Fixes * **codegen:** Make dynamic-slice queries compile on sqlx 0.9 ([#50](#50)) ([2b69750](2b69750)) * **deps:** Update rustls security fix ([b31da6c](b31da6c)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the first part of the stack proposed in Discussion #47. Thanks to @iamralch for finding the bug and writing the fix. This carries their commit unchanged from iamralch#3.
Problem
The workspace targets sqlx 0.9, but a
sqlc.slice()query that cannot use the= ANY($1)fast path emitssqlx::query_as(&sql)for its run-time SQL. sqlx 0.9 only accepts a&'static strdirectly, so that output does not compile. Reproduced against sqlx 0.9.0 with the codemaincurrently generates fortests/e2e/cases/dynamic_slice:The e2e fixtures pinned sqlx 0.8, and no example had a non-
ANYslice, so nothing compiled this output against the version the workspace declares.Change
query.rsandbatch.rsnow passsqlx::AssertSqlSafe(sql).Why
AssertSqlSafeis soundThe run-time string starts from the generated
constSQL and changes in only two ways: placeholders are renumbered to$n(or expanded to?), and an empty slice becomesNULL. Only the slice's length is decided at run time. Every value still goes through.bind(), so no caller data reaches the SQL text.Support note
Generated code that contains a dynamic slice now needs sqlx 0.9. It no longer compiles against 0.8. Static queries are unchanged and still compile on both versions. The workspace already declared 0.9. If we treat dropping 0.8 for dynamic slices as breaking, retitle with
!before squashing so release-please records it.Verification
cargo fmt --check,cargo clippy --workspace --all-features --all-targets -D warnings, andcargo package --lockedare clean.:one,:many(including an empty slice),:exec,:execrows,:execresult,:execlastid,:batchexec,:batchoneand:batchmany.The MySQL and SQLite parts of the stack (iamralch#1, iamralch#2) are not included. Review follows in the Discussion.