Files
upstream-mirror 0f4df23290
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
2026-09-16 02:17:34 +05:00

59 lines
2.2 KiB
Markdown

# Named Parameters Package - Claude Code Guide
This package models a query's parameters: their names, their nullability and
whether they came from `sqlc.slice()`.
It no longer knows anything about sqlc's *syntax*. `sqlc.arg()`, `sqlc.narg()`,
`sqlc.slice()` and `@name` are rewritten to native placeholders by
`internal/sql/preprocess` before any engine parser runs, and that package builds
the `ParamSet` while it rewrites.
## Param
A `Param` carries the user-facing name plus a nullability that combines what was
inferred from the schema with what the user asked for:
- `NewParam(name)` — unspecified nullability, from `sqlc.arg()` or `@name`
- `NewUserNullableParam(name)` — from `sqlc.narg()`, always nullable
- `NewSqlcSlice(name)` — from `sqlc.slice()`
- `NewInferredParam(name, notNull)` — what the compiler inferred
A user-specified nullability outranks an inferred one. `mergeParam` ORs the
nullability bits together, so the order the two sources arrive in does not
matter.
## ParamSet
`ParamSet` maps placeholder numbers to `Param` values for a single statement.
```go
ps := named.NewParamSet(numbersAlreadyUsed, hasNamedSupport)
n := ps.Add(named.NewParam("author_id")) // returns the placeholder number
```
`hasNamedSupport` is false for dialects that send one argument per `?`
(MySQL, ClickHouse). There, every occurrence of a name gets its own number. For
`$1`/`?1`/`@name` dialects repeated uses of a name share a number.
The compiler reads the set back with:
- `NameFor(number)` — the user-facing name for a placeholder
- `FetchMerge(number, inferred)` — the merged param and whether it was named
## MySQL @variable vs sqlc @param
`@name` is only sqlc syntax where the preprocessor's dialect says it is. MySQL
sets `AtSign: false`, so `@user_id` there is a user variable and reaches the
parser untouched (converted to `ast.VariableExpr`). PostgreSQL, SQLite and
GoogleSQL treat `@name` as a named parameter.
```sql
-- PostgreSQL with sqlc @param syntax:
SELECT * FROM users WHERE id = @user_id
-- Preprocessed to: SELECT * FROM users WHERE id = $1
-- MySQL with user variable:
SELECT * FROM users WHERE id != @user_id
-- Stays: SELECT * FROM users WHERE id != @user_id
```