2026-08-31 · 8 min read
- sql
- database
- security
Parameterized queries keep code and data separate, but placeholder syntax belongs to the client library or driver as much as to the database. A statement may use question marks, numbered dollar markers, colon-prefixed names, or an API that names parameters separately.
Porting query text without its binding contract leads to count mismatches, reordered values, invalid type inference, or unsafe attempts to interpolate values manually.
Treat statement and bindings as one contract
Record the driver, execution method, statement text after query-builder generation, and ordered or named binding metadata. Do not paste literal production values into diagnostics.
- Count placeholders after optional clauses are assembled.
- Use exact binding names and document repeated-name behavior.
- Keep positional parameters in a single reviewable order.
- Bind values through the driver, never through string replacement.
Control type inference
Null values, dates, UUIDs, decimals, JSON, byte arrays, and large integers often need explicit database or driver types. Otherwise the first execution or surrounding expression may select an unintended conversion.
Keep timestamps in a documented transport representation and handle decimal values without a lossy floating-point conversion. Verify how the driver serializes JSON and binary values rather than pre-escaping them as SQL text.
Expand collections safely
An IN list normally needs one placeholder per value, while some databases support a typed array parameter with a dedicated operator. Use a trusted query builder or a small placeholder generator and decide what an empty collection means.
- Return no rows or omit the predicate according to explicit product semantics.
- Cap list length to protect query size and planning cost.
- Consider temporary tables or bulk APIs for very large collections.
- Keep identifiers allowlisted because table and column names are not values.
Diagnose without exposing data
Use Flashman's SQL formatter for statement structure, JSON formatter for a synthetic parameter map, diff tool for generated-query revisions, case converter for named-binding drift, and timestamp converter for public date fixtures.
Test zero, one, and many collection values, repeated names, null and explicit types, Unicode, decimals, large integers, transactions, prepared-statement reuse, reconnects, and the exact production driver. Log placeholder metadata and safe type names rather than secrets or personal values.