Skip to content

Bindings: more positional values than placeholders is a TypeError, not a silently dropped value (P-07) - #536

Merged
tae898 merged 1 commit into
mainfrom
fix/p05-positional-count
Oct 25, 2026
Merged

tae898 merged 1 commit into
mainfrom
fix/p05-positional-count

Conversation

@tae898

@tae898 tae898 commented Oct 25, 2026 •

Copy link
Copy Markdown

Backlog row P-07. db.query("sql", "SELECT FROM V WHERE @rid IN ?", [rid_a, rid_b]) reads the lone list as the positional-parameter list (the documented form, one element per ?). The statement has one ?, so the engine binds rid_a, drops rid_b without a word, and the query returns one row where two were meant. The engine does not count: it also ignores a second value for a ? and binds null for a missing one (verified on the 26.10.2 release jars and on a 26.11.1-SNAPSHOT build through the Java API, upstream issue drafted separately). The documented example in docs/api/database.md (query("sql", "... ?", [0.9, 0.1, 0.0]) binds ? to 0.9) was this silent case.

Reproduced on both wheels before the change (rows returned against expected): @rid IN ? with [rid_a, rid_b], a tuple, or two arguments returned 1 of 2; k IN ? with [0, 1, 2] returned 1 of 3; the wrapped form [[a, b]] and the named form IN :ids returned all. Identical on the JVM wheel (main at 78e97b1cff) and the native image (nnext).

What changes: a call with more positional values than the SQL statement can bind raises TypeError before the statement runs, naming both ways out (wrap the list, [[a, b]], or bind it by name, IN :ids). A new module _params.py holds the check and both wheels call it from query()/command() (JVM) and _exec (native), so the behaviour is the same. The count is an upper bound taken from the ?, $ and : characters of the text, with SQL and SQLScript checked, not an exact count: the parsed statement's placeholder count is no public engine call, the native library would need a new entry point and an image rebuild, and named parameters carry positional numbers in the parser, so a count from the text that was exact would be a SQL tokenizer. The bound never refuses a call that binds (a ? inside a string literal counts as a placeholder, so such a statement is checked more loosely). Fewer values than placeholders are not checked. The documented API is unchanged: a lone list is still the positional list, and a call with one value per placeholder binds as before. The only calls refused are those that dropped a value.

One existing test changed: test_each_parameter_shape_reaches_one_java_overload passed values to SELECT 1 (no placeholder); it now uses SELECT ?, ? (it checks overload resolution only).

Tests first: test_positional_count.py was red on both wheels (9 of 20 failed, none raised) and is green after. Docs: docs/api/database.md (query and command), docs/guide/core/queries.md, docs/development/testing.md.

Checked: JVM wheel, full suite on the worktree source over the main wheel (1386 passed; the 5 failures and 2 errors are the subprocess tests that need the installed package, requests, and a Ctrl-C test, none touching parameters); native image nnext, full suite (895 passed; the 2 failures need setuptools in my throwaway environment). Not timed: the check costs one isinstance and a length compare on the one-value paths and a cached str.count on calls with two or more values; no timing claim is made.

Overlap: touches the same functions as #524 and #525 (query/command and _exec, one added if args: call each) and the parameter paragraph of docs/api/database.md that #529, #530 and #531 also edit; expect a trivial rebase.

🤖 Generated with Claude Code

…t a silently dropped value (P-07)

A lone list is the positional list, so IN ? with [a, b] bound a and dropped b. The check is an upper bound over the SQL text, so it never refuses a call that binds.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@tae898
tae898 marked this pull request as ready for review October 25, 2026 09:32
@tae898
tae898 merged commit 3f6eb82 into main Oct 25, 2026
50 of 52 checks passed
@tae898
tae898 deleted the fix/p05-positional-count branch October 25, 2026 13:01
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