Skip to content

Bind parameters in query (Rust core, Python SDK) - #1576

Merged
thekevinscott merged 4 commits into
mainfrom
bot/1575-bind-params-1104
Nov 4, 2026
Merged

thekevinscott merged 4 commits into
mainfrom
bot/1575-bind-params-1104

Conversation

@thekevinbot

@thekevinbot thekevinbot commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Refs #1575 (Rust core + Python SDK; the TypeScript binding follows in a second PR from fresh main once this merges).

query(sql, params) hands params to SQLite's own parameter binding; values never enter the SQL text. A sequence fills ? placeholders in order; a mapping fills :name (also @name / $name) placeholders, keyed without the prefix. Works for path-tables and declared tables.

  • Python: await db.query(sql, params=None). Accepts None, int, bool, float, str, bytes, bytearray. Any other value type raises TypeError (unsupported parameter type: <type>), and an out-of-range int raises OverflowError. A params that is neither a sequence nor a mapping (a str included) raises TypeError.
  • Rust: Params::{Positional(Vec<Value>), Named(HashMap<String, Value>)}. New methods: DirSQL::query_with, query_ordered_with, query_each_with and AsyncDirSQL::query_with. The existing methods bind Params::default() (empty).
  • Strict fit (DbError::Params, which Python raises as RuntimeError): a wrong count, a missing name, an unused mapping key, or a sequence/mapping that does not match the placeholder style each fail with a message naming the problem.
  • Every core query path binds: run_statement (both runs of a batched function) and query_each_ref (the streaming path, including its batched fallback).
  • No CLI flag.

Parity: this introduces drift, because TypeScript lacks params until the follow-up PR. That PR is tracked by #1575, which stays open. PARITY.md is updated.

Manual run: built with maturin develop --release and wrote three JSON files whose advice holds it's "quoted" — ok, ünïcødé ✓ 日本語 and x'; DROP TABLE t; --. Then ran await db.query("SELECT path FROM './*.json' WHERE content ->> 'advice' = :advice", {"advice": text}) for each. Each returned exactly its own file (a.json, b.json, c.json), and a non-matching value returned []. The error cases printed RuntimeError the query has 1 parameter(s), but 2 value(s) were given, RuntimeError the named parameter :a has no value and TypeError unsupported parameter type: object.

E2E Verification

  • Ran e2e suites locally for every affected SDK
  • Python SDK e2e: pass (impacted query tests)
  • TypeScript SDK e2e: pass (impacted query tests)
  • Rust core e2e (if applicable): pass
  • packages/python/e2e-attestations/<branch>.json receipt written if packages/python changed (just e2e-attest-python)
  • packages/ts/e2e-attestations/<branch>.json receipt written if packages/ts changed (just e2e-attest-ts)
  • Command(s) run:
    • cargo test -p dirsql --features cli
    • cd packages/python && testing-conventions e2e attest 'uv run python -m pytest tests/e2e/query_contract_test.py tests/e2e/on_file_query_test.py tests/e2e/declared_table_name_test.py tests/e2e/use_case_join_test.py tests/e2e/stat_speed_test.py -x -q'
    • cd packages/ts && testing-conventions e2e attest 'pnpm exec vitest run --dir tests/e2e query-contract declared-table-name'
  • Result summary: Rust 2195 passed; Python e2e 17 passed; TypeScript e2e 12 passed.

Changelog / Migrations

  • Changelog fragment added under <root>/<pkg>/changelog.d/ for each changed package (or: skip-changelog trailer on a commit with reason)
  • Migration fragment with the same slug added under <root>/<pkg>/migrations.d/ for each changed package (every subsection but Summary _None._ when nothing breaks)

The query_with methods and the Python params argument exist but ignore
their params, so every new test fails on the unbound placeholders.
A sequence fills ? placeholders and a mapping fills :name placeholders,
through SQLite's own binding, on every query path in the core and in the
Python SDK.
@thekevinscott
thekevinscott marked this pull request as ready for review November 4, 2026 16:41
@thekevinscott
thekevinscott merged commit 4ec1026 into main Nov 4, 2026
105 of 107 checks passed
@thekevinscott
thekevinscott deleted the bot/1575-bind-params-1104 branch November 4, 2026 16:41
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.

2 participants