SwadhyAI Notes

All SQL notes

📎Parameters and prepared statements

Shape once, send values many times

Prepared statements send SQL text with placeholders, then ship parameter values on the wire separately from the parse tree, blocking classic injection and often letting the server reuse parse/plan work. Identifiers (table/column names, ORDER BY keys) are still not parameters; whitelist or map them explicitly.

SQL

PostgreSQL PREPARE / EXECUTE (logical view)

PREPARE get_run (text) AS
SELECT run_id, started_at FROM sequencing_runs WHERE instrument_id = $1;

EXECUTE get_run('SEQ-01');
✓Illustrative result set
run_idstarted_at
R-9002026-04-10 08:00
R-9012026-04-11 09:12

âš¡ Advanced / dialect note

Generic plans vs custom plans: optimizers may replan after seeing parameter skew, watch for performance cliffs when a few hot values dominate cardinality; adaptive statistics or plan guides exist on some engines.

Parameters mistaken for every token

  • Interpolating ORDER BY column names or sort direction from user input.
  • Client-side quote escaping instead of driver-level binding.
  • Assuming one prepared statement survives all pooled connections without lifecycle rules.

Bind values, not identifiers

  • Whitelist sort columns in application code; use enums or maps for directions.
  • Monitor plan cache churn and single-use plans in production telemetry.
  • Teach the difference between bind parameters (values) and identifiers (names): only the former are safe from concatenation.

🔌Protocols

Extended query vs simple query mode.

Drivers

Most client stacks use extended query protocol under the hood, know when your pooler disables or emulates it (PgBouncer transaction mode, some serverless proxies).

Stored procedures

Dynamic SQL inside procedures still needs parameterization-PREPARE does not absolve string-built EXEC inside the body.

ORMs

ORM escape hatches that accept raw SQL strings are the usual leak, code review should treat them like eval with a WHERE clause.

TL;DR

Prepared statements send SQL text once with placeholders ($1, ?) and bind values per execution, preventing SQL injection and allowing plan reuse. Session-pinned features (temp tables, some SET options) interact badly with some pooler modes, validate driver + pooler behavior. Use bind types that match column types to avoid implicit cast surprises.