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

2.2 KiB

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.

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.

-- 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