fix(params): give a placeholder inside an INSERT VALUES call its slot - #335
Merged
Conversation
Params<DB, 'insert into users (id, name) values (coalesce(?, 0), ?)'>
// was [string] - one slot for two placeholders
MatchInsertValues runs IsPlaceholder on each VALUES entry as a single token,
and StripCallWrapper gives up on a call carrying an inner comma, so the
placeholder inside it registered nothing. WHERE only works by accident of
space-splitting, which isolates `coalesce($1,` as its own token.
The `@name` spelling is the one that bites hardest. The caller can only pass
one value, resolveMixedParameters scans `@a` first and gives it that value,
binds `@b` to null, and the INSERT succeeds having written into the wrong
column. No error anywhere.
Splitting the call's own argument list is enough to fix it: each argument is
a token again, and a single-argument call around a placeholder (`lower(?)`)
is something CleanScanToken already unwraps, so nesting keeps working. The
column type still comes from the matching entry in the INSERT column list.
Fixes #269
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tiagolauer
force-pushed
the
fix/269-insert-values-call-params
branch
from
August 2, 2026 13:03
6f75af3 to
2800d87
Compare
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.
Fixes #269.
The bug
The README promises the opposite — "A placeholder inside a call is typed (
lower($1),coalesce($1, 0))" — and it does work in WHERE.The
@variant is the one that bites hardest, and it does it silently: the caller can only pass one value,resolveMixedParametersscans@afirst and gives it that value, binds@b = null, and the INSERT succeeds having written into the wrong column.The fix
MatchInsertValuesrunsIsPlaceholderon each VALUES entry as one token, andStripCallWrapperbails on any inner comma, so the placeholders inside the call never registered. (WHERE only works by accident of space-splitting, which isolatescoalesce($1,as its own token.)An entry that is not itself a placeholder now has its call's argument list split, and each argument is checked again. That is enough: a single-argument call around a placeholder (
lower(?)) is somethingCleanScanTokenalready unwraps, so nesting keeps working. The type still comes from the matching entry in the INSERT column list.Verification
tests/insert-values-call-params.test-d.ts, eight cases. Four red on master:?,@nameand$ninsidecoalesce(x, 0)all reach[number, string]coalesce(lower(@b), $$x$$)too, which also pins that a dollar-quoted body is not read as a placeholderControls: bare placeholders, a single-argument call, literals taking no slot, and the WHERE-clause form that already worked.
tsc --noEmitclean, 192 runtime tests pass, budget 192,807 (+321).