Skip to content

Refuse a lone dict for positional ? placeholders instead of binding NULL - #185

Merged
tae898 merged 3 commits into
mainfrom
fix/dict-with-positional-params
Nov 1, 2026
Merged

tae898 merged 3 commits into
mainfrom
fix/dict-with-positional-params

Conversation

@tae898

@tae898 tae898 commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator

Closes #184

Bindings-side guard for the silent null of ArcadeData/arcadedb#11098, on both builds.

  • src/arcadedb/_params.py: refuse_dict_for_positionals, called first in refuse_surplus_positionals (which core.py query/command and the native _exec already call), raises TypeError when all hold: the language is sql or sqlscript; the arguments are a lone dict, [d] or (d,); the statement has a positional ? and no :name / $name placeholder outside string literals and backtick identifiers (a small scanner, _placeholder_kinds, no SQL parsing); no key is a digit string ({"0": v} binds slot 0 by key on the engine and keeps working). The message says a dict is the NAMED map, ? takes a list such as [value], and how to pass a dict as one value.
  • Docs (how-to/databases-and-queries.adoc, Parameters): a dict is always the named map; the exact-count rule covers positional values; the new error and what to do instead.
  • Tests: tests/test_dict_with_positional.py (shared): the three dict spellings refused by command and query, sqlscript, an empty dict, the message; controls that keep binding (a dict with :v, [5] with ?, ? inside string literals, {"0": 7}, an openCypher named map); the scanner's literal handling (11 cases).

Verification: against the main 26.11.1.dev0 wheels both builds fail the 20 refusal and scanner tests (nothing raises today, the scanner does not exist) and pass the 5 controls. bandit, black, isort, pyflakes clean.

🤖 Generated with Claude Code

tae898 and others added 3 commits November 1, 2026 22:47
…lders

A lone dict (also [d] and (d,)) is the named-parameter map on both builds. The
engine's Map overloads bind a positional ? with no key to NULL and nothing
raises (ArcadeData/arcadedb#11098), so INSERT ... SET v = ? with {"a": 1}
stored a record without v. refuse_dict_for_positionals (called first from
refuse_surplus_positionals, which core.py and _native/database.py both call)
raises TypeError for SQL and SQLScript when the text has a ? and no :name or
$name outside string literals/backtick identifiers and no key is a digit
string ({"0": v} keeps binding slot 0 by key). Tests in
tests/test_dict_with_positional.py; Parameters docs section updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The three controls (named, positional list, digit-string key) wrote
outside a transaction, which the engine refuses (Transaction not begun)
on both builds; the repo's tests wrap writes in db.transaction().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eholders

test_each_parameter_shape_reaches_one_java_overload sent a lone dict to
'SELECT ?, ?' to check that it reaches the Map overload; the new guard
(#184) refuses exactly that call. Its two lone-dict cases now use
'SELECT :v, :w' and 'SELECT :p'; the dispatch it checks is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tae898
tae898 merged commit a3e3ed6 into main Nov 1, 2026
37 checks passed
@tae898
tae898 deleted the fix/dict-with-positional-params branch November 1, 2026 16:30
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.

A lone dict with positional ? placeholders binds NULL silently (both builds)

1 participant