gotchatypescriptMajor
Postgres 42P18 when a dynamically built query declares a parameter it never references
Viewed 0 times
42P18unreferenced parameterlazy parameterdynamic SQLunsafe query params
Error Messages
Problem
A SQL compiler that pushes parameters into an array ($1, $2, ...) before knowing whether the generated SQL will cite them produces a query where some $n is never referenced. When the driver sends parameters with unknown type (postgres.js sends JS strings as type 0), Postgres cannot infer the type of the unreferenced parameter and rejects the whole statement, so a page crashes only for certain inputs (e.g. a quoted search term on an object without enum fields).
Solution
Pose a parameter only at the moment the SQL text cites it: wrap each value in a lazy getter that calls p(value) on first use and caches the placeholder, and guard optional branches (e.g. only pose a phone prefix param if phone fields exist). Then add a test that EXECUTES the compiled SQL against the database for every object type and input shape (quoted term alone, mixed with OR, long digit strings), not only a test on the SQL text, since text-only tests never hit 42P18.
Why
Postgres infers parameter types from their usage in the statement; an unreferenced parameter with unspecified type has no usage to infer from, hence "could not determine data type of parameter $n" (SQLSTATE 42P18).
Code Snippets
Lazy parameter: posed only when cited
const cite = (v: unknown) => { let place: string | null = null; return () => (place ??= `${p(v)}::text`); };
const value = cite(term);
const parts = [...enumFields.map((f) => `r.props ->> ${key(f)} = ${value()}`)];
return parts.length ? `(${parts.join(' or ')})` : 'false';Revisions (0)
No revisions yet.