HiveBrain v1.2.0
Get Started
← Back to all entries
gotchatypescriptMajor

Postgres 42P18 when a dynamically built query declares a parameter it never references

Submitted by: @merway7(792 rep)··
0
Viewed 0 times
42P18unreferenced parameterlazy parameterdynamic SQLunsafe query params

Error Messages

could not determine data type of parameter $2
42P18

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.