snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
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

This commit is contained in:
upstream-mirror
2026-09-16 02:17:34 +05:00
commit 0f4df23290
7340 changed files with 238743 additions and 0 deletions

129
docs/howto/analyze.md Normal file
View File

@@ -0,0 +1,129 @@
# `analyze` - Analyzing query result types
> [!NOTE]
> `analyze` is in beta. Its flags and JSON output may change in a
> future release, and the types it reports can differ from the ones
> `generate` produces.
`sqlc analyze` analyzes a query against a schema and prints the inferred result
columns and parameters as a single JSON document.
Unlike [`generate`](generate.md), this command does not require a configuration
file and does not connect to a database. It uses sqlc's native static analysis
to infer types directly from the provided schema.
Every dialect is analyzed by the same engine-neutral analysis core: the schema
is loaded into a catalog seeded with the dialect's types, operators and
functions, and each query is resolved against it. `generate` still uses each
engine's own analysis path, so the two can report a type differently — most
visibly, `analyze` reports type names as the catalog stores them, in lower
case.
## Usage
```sh
sqlc analyze --dialect <dialect> --schema <schema-file> [query-file]
```
The query is read from the given file, or from standard input when no file is
provided. The schema is always read from the `--schema` file.
## Flags
- `--dialect`, `-d` - The SQL dialect to use. One of `postgresql`, `mysql`,
`sqlite`, `clickhouse`, `googlesql`, `mssql`, or `duckdb`. Required.
- `--schema`, `-s` - Path to the schema (DDL) file. Required.
- `--ast` - Include each statement's AST in the output. Defaults to `false`.
## Examples
Given a schema in `schema.sql`:
```sql
CREATE TABLE authors (
id BIGSERIAL PRIMARY KEY,
name text NOT NULL,
bio text
);
```
and a query in `query.sql`:
```sql
-- name: GetAuthor :one
SELECT * FROM authors WHERE id = $1;
```
Running:
```sh
sqlc analyze --dialect postgresql --schema schema.sql query.sql
```
reports the result columns and parameters:
```json
[
{
"name": "GetAuthor",
"cmd": ":one",
"columns": [
{
"name": "id",
"type": {
"name": "bigint"
},
"table": "authors"
},
{
"name": "name",
"type": {
"name": "text"
},
"table": "authors"
},
{
"name": "bio",
"type": {
"name": "text",
"nullable": true
},
"table": "authors"
}
],
"params": [
{
"number": 1,
"column": {
"name": "id",
"type": {
"name": "bigint"
},
"table": "authors"
}
}
]
}
]
```
A column's `type` is written as a call expression: a `name` applied to
`args`, each of which carries an optional `label` and exactly one of `type`,
`int`, `bool`, `string` or `ident`, with `nullable` set at whatever depth it
applies. A `numeric(10,2)` column is `numeric` applied to `10` and `2`; an
array of text is `array` applied to `text`, and an array of arrays nests
one `array` per dimension; a `Map(String, Nullable(UInt8))` in ClickHouse is
`map` applied to `string` and a nullable `uint8`; a `STRUCT<a INT64>` in
GoogleSQL is `struct` applied to an `int64` labelled `a`; the `MAX` of SQL
Server's `nvarchar(max)` is the identifier `max`.
Types are reported the way the engine itself stores and reports them rather
than the way the schema spelled them: PostgreSQL's `int` and `bigserial` are
`integer` and `bigint`, as `format_type` prints them; MySQL's `BOOLEAN` is
`tinyint(1)`; ClickHouse's `Decimal32(4)` is `decimal(9, 4)`; DuckDB's
`TEXT` is `varchar`; SQL Server's `FLOAT(24)` is `real`. SQLite, which
keeps a declared type as written, is reported as written.
Pass `--ast` to also include each statement's parsed AST under an `ast` key. It
has the same shape as the output of [`parse`](parse.md), with every node tagged
by type.

159
docs/howto/ci-cd.md Normal file
View File

@@ -0,0 +1,159 @@
# Using sqlc in CI/CD
If your project has more than a single developer, we suggest running `sqlc` as
part of your CI/CD pipeline. The four subcommands you'll want to run are `diff`,
`vet`, `verify` and `push`
`sqlc diff` ensures that your generated code is up to date. New developers to a
project may forget to run `sqlc generate` after adding a query or updating a
schema. They also might edit generated code. `sqlc diff` will catch both errors
by comparing the expected output from `sqlc generate` to what's on disk.
```diff
% sqlc diff
--- a/postgresql/query.sql.go
+++ b/postgresql/query.sql.go
@@ -55,7 +55,7 @@
const listAuthors = `-- name: ListAuthors :many
SELECT id, name, bio FROM authors
-ORDER BY name
+ORDER BY bio
`
```
`sqlc vet` runs a set of lint rules against your SQL queries. These rules are
helpful in catching anti-patterns before they make it into production. Please
see the [vet](vet.md) documentation for a complete guide to adding lint rules
for your project.
`sqlc verify` ensures that schema changes do not break production. Existing
queries are checked against new schema changes for correctness. Please see the
[verify](verify.md) documentation for a complete guide.
`sqlc push` pushes your database schema, queries and configuration to sqlc
Cloud. These archives are used by `verify` to catch breaking changes to your
database schema. Learn more about uploading projects [here](push.md)
## General setup
Install `sqlc` using the [suggested instructions](../overview/install.md).
Create three steps in your pipeline for `sqlc diff`, `sqlc vet`, and `sqlc
verify`. Run `sqlc push` after merge on your `main` branch.
## GitHub Actions
We provide the [setup-sqlc](https://github.com/marketplace/actions/setup-sqlc)
GitHub Action to install `sqlc`. The action uses the built-in
[tool-cache](https://github.com/actions/toolkit/blob/main/packages/tool-cache/README.md)
to speed up the installation process.
### diff
The following GitHub Workflow configuration runs `sqlc diff` on every push.
```yaml
name: sqlc
on: [push]
jobs:
diff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: sqlc-dev/setup-sqlc@v3
with:
sqlc-version: '1.31.1'
- run: sqlc diff
```
### vet
The following GitHub Workflow configuration runs [sqlc vet](vet.md) on every push.
You can use `sqlc vet` without a database connection, but you'll need one if your
`sqlc` configuration references the built-in `sqlc/db-prepare` lint rule.
```yaml
name: sqlc
on: [push]
jobs:
vet:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: sqlc-dev/setup-sqlc@v3
with:
sqlc-version: '1.31.1'
# Start a PostgreSQL server
- uses: sqlc-dev/action-setup-postgres@master
with:
postgres-version: "16"
id: postgres
- run: sqlc vet
env:
POSTGRESQL_SERVER_URI: ${{ steps.postgres.outputs.connection-uri }}?sslmode=disable
```
### push
> [!NOTE]
> Pushing a project is powered by [sqlc Cloud](https://dashboard.sqlc.dev). Sign up for [free](https://dashboard.sqlc.dev) today.
The following GitHub Workflow configuration runs [sqlc push](push.md) on
every push to `main`. Create an auth token via the
[dashboard](https://dashboard.sqlc.dev).
```yaml
name: sqlc
on: [push]
jobs:
push:
runs-on: ubuntu-latest
if: ${{ github.ref == 'refs/heads/main' }}
steps:
- uses: actions/checkout@v3
- uses: sqlc-dev/setup-sqlc@v3
with:
sqlc-version: '1.31.1'
- run: sqlc push
env:
SQLC_AUTH_TOKEN: ${{ secrets.SQLC_AUTH_TOKEN }}
```
### verify
> [!NOTE]
> Verify database migrations is powered by [sqlc Cloud](https://dashboard.sqlc.dev). Sign up for [free](https://dashboard.sqlc.dev) today.
```yaml
name: sqlc
on: [push]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: sqlc-dev/setup-sqlc@v3
with:
sqlc-version: '1.31.1'
- uses: sqlc-dev/action-setup-postgres@master
with:
postgres-version: "16"
id: postgres
- run: sqlc verify
env:
POSTGRESQL_SERVER_URI: ${{ steps.postgres.outputs.connection-uri }}?sslmode=disable
SQLC_AUTH_TOKEN: ${{ secrets.SQLC_AUTH_TOKEN }}
push:
runs-on: ubuntu-latest
if: ${{ github.ref == 'refs/heads/main' }}
steps:
- uses: sqlc-dev/setup-sqlc@v3
with:
sqlc-version: '1.31.1'
- run: sqlc push
env:
SQLC_AUTH_TOKEN: ${{ secrets.SQLC_AUTH_TOKEN }}
``````

232
docs/howto/ddl.md Normal file
View File

@@ -0,0 +1,232 @@
# Modifying the database schema
sqlc parses `CREATE TABLE` and `ALTER TABLE` statements in order to generate
the necessary code.
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
birth_year int NOT NULL
);
ALTER TABLE authors ADD COLUMN bio text NOT NULL;
ALTER TABLE authors DROP COLUMN birth_year;
ALTER TABLE authors RENAME TO writers;
```
```go
package db
type Writer struct {
ID int
Bio string
}
```
## Handling SQL migrations
sqlc does not perform database migrations for you. However, sqlc is able to
differentiate between up and down migrations. sqlc ignores down migrations when
parsing SQL files.
sqlc supports parsing migrations from the following tools:
- [atlas](https://github.com/ariga/atlas)
- [dbmate](https://github.com/amacneil/dbmate)
- [golang-migrate](https://github.com/golang-migrate/migrate)
- [goose](https://github.com/pressly/goose)
- [sql-migrate](https://github.com/rubenv/sql-migrate)
- [tern](https://github.com/jackc/tern)
To enable migration parsing, specify the migration directory instead of a schema file:
```yaml
version: "2"
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "db/migrations"
gen:
go:
package: "tutorial"
out: "tutorial"
```
### atlas
```sql
-- Create "post" table
CREATE TABLE "public"."post" ("id" integer NOT NULL, "title" text NULL, "body" text NULL, PRIMARY KEY ("id"));
```
```go
package db
type Post struct {
ID int
Title sql.NullString
Body sql.NullString
}
```
### dbmate
```sql
-- migrate:up
CREATE TABLE foo (bar INT NOT NULL);
-- migrate:down
DROP TABLE foo;
```
```go
package db
type Foo struct {
Bar int32
}
```
### golang-migrate
**Warning:**
[golang-migrate interprets](https://github.com/golang-migrate/migrate/blob/master/MIGRATIONS.md#migration-filename-format)
migration filenames numerically. However, sqlc parses migration files in
lexicographic order. If you choose to have sqlc enumerate your migration files,
make sure their numeric ordering matches their lexicographic ordering to avoid
unexpected behavior. This can be done by prepending enough zeroes to the
migration filenames.
This doesn't work as intended.
```
1_initial.up.sql
...
9_foo.up.sql
# this migration file will be parsed BEFORE 9_foo
10_bar.up.sql
```
This worked as intended.
```
001_initial.up.sql
...
009_foo.up.sql
010_bar.up.sql
```
In `20060102.up.sql`:
```sql
CREATE TABLE post (
id int NOT NULL,
title text,
body text,
PRIMARY KEY(id)
);
```
In `20060102.down.sql`:
```sql
DROP TABLE post;
```
```go
package db
type Post struct {
ID int
Title sql.NullString
Body sql.NullString
}
```
### goose
**Warning:**
sqlc parses migration files in lexicographic order. **If you are using numeric filenames for migrations in Goose and you choose to have sqlc enumerate your migration files**,
make sure their numeric ordering matches their lexicographic ordering to avoid
unexpected behavior. This can be done by prepending enough zeroes to the
migration filenames.
This doesn't work as intended.
```
1_initial.sql
...
9_foo.sql
# this migration file will be parsed BEFORE 9_foo
10_bar.sql
```
This worked as intended.
```
001_initial.sql
...
009_foo.sql
010_bar.sql
```
```sql
-- +goose Up
CREATE TABLE post (
id int NOT NULL,
title text,
body text,
PRIMARY KEY(id)
);
-- +goose Down
DROP TABLE post;
```
```go
package db
type Post struct {
ID int
Title sql.NullString
Body sql.NullString
}
```
### sql-migrate
```sql
-- +migrate Up
-- SQL in section 'Up' is executed when this migration is applied
CREATE TABLE people (id int);
-- +migrate Down
-- SQL section 'Down' is executed when this migration is rolled back
DROP TABLE people;
```
```go
package db
type People struct {
ID int32
}
```
### tern
```sql
CREATE TABLE comment (id int NOT NULL, text text NOT NULL);
---- create above / drop below ----
DROP TABLE comment;
```
```go
package db
type Comment struct {
ID int32
Text string
}
```

52
docs/howto/delete.md Normal file
View File

@@ -0,0 +1,52 @@
# Deleting rows
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
bio text NOT NULL
);
```
The parameter syntax varies by database engine:
**PostgreSQL:**
```sql
-- name: DeleteAuthor :exec
DELETE FROM authors WHERE id = $1;
```
**MySQL and SQLite:**
```sql
-- name: DeleteAuthor :exec
DELETE FROM authors WHERE id = ?;
```
```go
package db
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
const deleteAuthor = `-- name: DeleteAuthor :exec
DELETE FROM authors WHERE id = $1
`
func (q *Queries) DeleteAuthor(ctx context.Context, id int) error {
_, err := q.db.ExecContext(ctx, deleteAuthor, id)
return err
}
```

61
docs/howto/embedding.md Normal file
View File

@@ -0,0 +1,61 @@
# Embedding structs
Embedding allows you to reuse existing model structs in more queries, resulting
in less manual serialization work. First, imagine we have the following schema
with students and test scores.
```sql
CREATE TABLE students (
id bigserial PRIMARY KEY,
name text NOT NULL,
age integer NOT NULL
);
CREATE TABLE test_scores (
student_id bigint NOT NULL,
score integer NOT NULL,
grade text NOT NULL
);
```
We want to select the student record and the scores they got on a test.
Here's how we'd usually do that:
```sql
-- name: ScoreAndTests :many
SELECT students.*, test_scores.*
FROM students
JOIN test_scores ON test_scores.student_id = students.id
WHERE students.id = $1;
```
When using Go, sqlc will produce a struct like this:
```go
type ScoreAndTestsRow struct {
ID int64
Name string
Age int32
StudentID int64
Score int32
Grade string
}
```
With embedding, the struct will contain a model for both tables instead of a
flattened list of columns.
```sql
-- name: ScoreAndTests :many
SELECT sqlc.embed(students), sqlc.embed(test_scores)
FROM students
JOIN test_scores ON test_scores.student_id = students.id
WHERE students.id = $1;
```
```
type ScoreAndTestsRow struct {
Student Student
TestScore TestScore
}
```

74
docs/howto/fmt.md Normal file
View File

@@ -0,0 +1,74 @@
# `fmt` - Formatting queries
> [!NOTE]
> `fmt` is in beta. It rewrites your query files in place, so commit
> or back them up first. The formatting it produces may change in a
> future release.
`sqlc fmt` rewrites the query files referenced by your configuration file in a
canonical format. Each query is parsed with the engine's parser and printed
back from the syntax tree, so formatting never depends on how the query was
written — only on what it means. PostgreSQL, MySQL and SQLite are supported;
query files for other engines are left unchanged.
Like `gofmt`, the formatter does not impose a maximum line width. A statement
written on a single line stays on a single line, and a statement the author
broke across lines keeps its breaks: the printer notices which clause
boundaries (`FROM`, `WHERE`, `ORDER BY`, ...) and list boundaries the author
broke at and preserves them, normalizing indentation and spacing around them.
Comments inside a statement are formatted along with it: each comment is
anchored to the code around it by source position and printed back there —
a comment trailing a select-list item stays with that item, a comment above
a clause stays above its keyword — and a comment that runs to the end of its
line breaks the statement open around it. Any statement that cannot be
proven to survive formatting unchanged is left exactly as written.
## Usage
```sh
sqlc fmt [--diff]
```
Without flags, the query files are rewritten in place. With `--diff`, the
changes are printed to standard output instead and no files are modified.
## Examples
Given this query file:
```sql
-- name: GetAuthor :one
select id,name , bio
from authors
where id = ? limit 1;
-- name: SearchAuthors :many
SELECT id, -- the primary key
name, bio, created_at FROM authors WHERE name LIKE ? AND bio IS NOT NULL AND id > ? AND created_at > ? AND name <> ? ORDER BY name;
```
running `sqlc fmt` rewrites it to:
```sql
-- name: GetAuthor :one
SELECT id, name, bio
FROM authors
WHERE id = ?
LIMIT 1;
-- name: SearchAuthors :many
SELECT
id, -- the primary key
name,
bio,
created_at
FROM authors
WHERE name LIKE ? AND bio IS NOT NULL AND id > ? AND created_at > ? AND name <> ?
ORDER BY name;
```
`GetAuthor` keeps the line breaks its author wrote; had it been written on
one line, it would stay on one line. In `SearchAuthors`, the line comment
cannot share a line with the code after it, so the statement breaks open
around it, while the `WHERE` chain — written on one line — stays on one.

76
docs/howto/generate.md Normal file
View File

@@ -0,0 +1,76 @@
# `generate` - Generating code
`sqlc generate` parses SQL, analyzes the results, and outputs code. Your schema and queries are stored in separate SQL files. The paths to these files live in a `sqlc.yaml` configuration file.
```yaml
version: "2"
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "schema.sql"
gen:
go:
package: "tutorial"
out: "tutorial"
sql_package: "pgx/v5"
```
We've written extensive docs on [retrieving](select.md), [inserting](insert.md),
[updating](update.md), and [deleting](delete.md) rows.
By default, sqlc runs its analysis using a built-in query analysis engine. While fast, this engine can't handle some complex queries and type-inference.
You can configure sqlc to use a database connection for enhanced analysis using metadata from that database.
The database-backed analyzer currently supports PostgreSQL, with [MySQL](https://github.com/sqlc-dev/sqlc/issues/2902) and [SQLite](https://github.com/sqlc-dev/sqlc/issues/2903)
support planned in the future.
## Enhanced analysis with managed databases
With [managed databases](managed-databases.md) configured, `generate` will automatically create a hosted ephemeral database with your
schema and use that database to improve its query analysis. And sqlc will cache its analysis locally
on a per-query basis to speed up future `generate` runs. This saves you the trouble of running and maintaining a database with
an up-to-date schema. Here's a minimal working configuration:
```yaml
version: "2"
servers:
- engine: postgresql
uri: "postgres://locahost:5432/postgres?sslmode=disable"
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "schema.sql"
database:
managed: true
gen:
go:
out: "db"
sql_package: "pgx/v5"
```
## Enhanced analysis using your own database
You can opt-in to database-backed analysis using your own database, by providing a `uri` in your sqlc
[database](../reference/config.md#database) configuration.
The `uri` string can contain references to environment variables using the `${...}`
syntax. In the following example, the connection string will have the value of
the `PG_PASSWORD` environment variable set as its password.
```yaml
version: "2"
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "schema.sql"
database:
uri: "postgres://postgres:${PG_PASSWORD}@localhost:5432/postgres"
gen:
go:
out: "db"
sql_package: "pgx/v5"
```
Databases configured with a `uri` must have an up-to-date schema for query analysis to work correctly, and `sqlc` does not apply schema migrations your database. Use your migration tool of choice to create the necessary
tables and objects before running `sqlc generate`.

238
docs/howto/insert.md Normal file
View File

@@ -0,0 +1,238 @@
# Inserting rows
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
bio text NOT NULL
);
```
The parameter syntax varies by database engine:
**PostgreSQL:**
```sql
-- name: CreateAuthor :exec
INSERT INTO authors (bio) VALUES ($1);
```
**MySQL and SQLite:**
```sql
-- name: CreateAuthor :exec
INSERT INTO authors (bio) VALUES (?);
```
```go
package db
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
const createAuthor = `-- name: CreateAuthor :exec
INSERT INTO authors (bio) VALUES ($1)
`
func (q *Queries) CreateAuthor(ctx context.Context, bio string) error {
_, err := q.db.ExecContext(ctx, createAuthor, bio)
return err
}
```
## Returning columns from inserted rows
sqlc has full support for the `RETURNING` statement.
```sql
-- Example queries for sqlc
CREATE TABLE authors (
id BIGSERIAL PRIMARY KEY,
name text NOT NULL,
bio text
);
```
**PostgreSQL:**
```sql
-- name: CreateAuthor :one
INSERT INTO authors (
name, bio
) VALUES (
$1, $2
)
RETURNING *;
-- name: CreateAuthorAndReturnId :one
INSERT INTO authors (
name, bio
) VALUES (
$1, $2
)
RETURNING id;
```
**SQLite (with RETURNING support):**
```sql
-- name: CreateAuthor :one
INSERT INTO authors (
name, bio
) VALUES (
?, ?
)
RETURNING *;
-- name: CreateAuthorAndReturnId :one
INSERT INTO authors (
name, bio
) VALUES (
?, ?
)
RETURNING id;
```
Note: MySQL does not support the `RETURNING` clause. Use `:execresult` instead to get the last insert ID.
```go
package db
import (
"context"
"database/sql"
)
const createAuthor = `-- name: CreateAuthor :one
INSERT INTO authors (
name, bio
) VALUES (
$1, $2
)
RETURNING id, name, bio
`
type CreateAuthorParams struct {
Name string
Bio sql.NullString
}
func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) {
row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio)
var i Author
err := row.Scan(&i.ID, &i.Name, &i.Bio)
return i, err
}
const createAuthorAndReturnId = `-- name: CreateAuthorAndReturnId :one
INSERT INTO authors (
name, bio
) VALUES (
$1, $2
)
RETURNING id
`
type CreateAuthorAndReturnIdParams struct {
Name string
Bio sql.NullString
}
func (q *Queries) CreateAuthorAndReturnId(ctx context.Context, arg CreateAuthorAndReturnIdParams) (int64, error) {
row := q.db.QueryRowContext(ctx, createAuthorAndReturnId, arg.Name, arg.Bio)
var id int64
err := row.Scan(&id)
return id, err
}
```
## Using CopyFrom
### PostgreSQL
PostgreSQL supports the [COPY protocol](https://www.postgresql.org/docs/current/sql-copy.html) that can insert rows a lot faster than sequential inserts. You can use this easily with sqlc:
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
name text NOT NULL,
bio text NOT NULL
);
-- name: CreateAuthors :copyfrom
INSERT INTO authors (name, bio) VALUES ($1, $2);
```
```go
type CreateAuthorsParams struct {
Name string
Bio string
}
func (q *Queries) CreateAuthors(ctx context.Context, arg []CreateAuthorsParams) (int64, error) {
...
}
```
The `:copyfrom` command requires either `pgx/v4` or `pgx/v5`.
```yaml
version: "2"
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "query.sql"
gen:
go:
package: "db"
sql_package: "pgx/v5"
out: "db"
```
### MySQL
MySQL supports a similar feature using [LOAD DATA](https://dev.mysql.com/doc/refman/8.0/en/load-data.html).
Errors and duplicate keys are treated as warnings and insertion will
continue, even without an error for some cases. Use this in a transaction
and use SHOW WARNINGS to check for any problems and roll back if necessary.
Check the [error handling](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-error-handling) documentation for more information.
```sql
CREATE TABLE foo (a text, b integer, c DATETIME, d DATE);
-- name: InsertValues :copyfrom
INSERT INTO foo (a, b, c, d) VALUES (?, ?, ?, ?);
```
```go
func (q *Queries) InsertValues(ctx context.Context, arg []InsertValuesParams) (int64, error) {
...
}
```
The `:copyfrom` command requires setting the `sql_package` and `sql_driver` options.
```yaml
version: "2"
sql:
- engine: "mysql"
queries: "query.sql"
schema: "query.sql"
gen:
go:
package: "db"
sql_package: "database/sql"
sql_driver: "github.com/go-sql-driver/mysql"
out: "db"
```

View File

@@ -0,0 +1,101 @@
# Managed databases
*Added in v1.22.0*
`sqlc` can automatically create read-only databases to power query analysis,
linting and verification. These databases are immediately useful for powering
sqlc's database-connected query analyzer, an opt-in feature that improves upon
sqlc's built-in query analysis engine. PostgreSQL support is available today,
with MySQL on the way.
Once configured, `sqlc` will also use managed databases when linting queries
with [`sqlc vet`](vet.md) in cases where your lint rules require a connection
to a running database.
Managed databases are under active development, and we're interested in
supporting other use-cases.
## Configuring managed databases
To configure `sqlc` to use managed databases, remove the `uri` key from your
`database` configuration and replace it with the `managed` key set to `true`.
Access to a running database server is required. Add a connection string to the `servers` mapping.
```yaml
version: '2'
servers:
- engine: postgresql
uri: "postgres://localhost:5432/postgres?sslmode=disable"
sql:
- schema: schema.sql
queries: query.sql
engine: postgresql
database:
managed: true
```
An environment variable can also be used via the `${}` syntax.
```yaml
version: '2'
servers:
- engine: postgresql
uri: ${DATABASE_URI}
sql:
- schema: schema.sql
queries: query.sql
engine: postgresql
database:
managed: true
```
## Improving codegen
Without a database connection, sqlc does its best to parse, analyze and compile your queries just using
the schema you pass it and what it knows about the various database engines it supports. In many cases
this works just fine, but for more advanced queries sqlc might not have enough information to produce good code.
With managed databases configured, `sqlc generate` will automatically create a hosted ephemeral database with your
schema and use that database to improve its query analysis. And sqlc will cache its analysis locally
on a per-query basis to speed up future codegen runs. Here's a minimal working configuration:
```yaml
version: '2'
servers:
- engine: postgresql
uri: "postgres://localhost:5432/postgres?sslmode=disable"
sql:
- schema: schema.sql
queries: query.sql
engine: postgresql
database:
managed: true
gen:
go:
out: "db"
```
## Linting queries
With managed databases configured, `sqlc vet` will automatically create a hosted ephemeral database with your
schema and use that database when running lint rules that require a
database connection, e.g. any [rule relying on `EXPLAIN ...` output](vet.md#rules-using-explain--output).
If you don't yet have any vet rules, the [built-in sqlc/db-prepare rule](vet.md#sqlcdb-prepare)
is a good place to start. It prepares each of your queries against the database
to ensure the query is valid. Here's a minimal working configuration:
```yaml
version: '2'
servers:
- engine: postgresql
uri: "postgres://localhost:5432/postgres?sslmode=disable"
sql:
- schema: schema.sql
queries: query.sql
engine: postgresql
database:
managed: true
rules:
- sqlc/db-prepare
```

View File

@@ -0,0 +1,93 @@
# Naming parameters
sqlc tries to generate good names for positional parameters, but sometimes it
lacks enough context. The following SQL generates parameters with less than
ideal names:
```sql
-- name: UpsertAuthorName :one
UPDATE author
SET
name = CASE WHEN $1::bool
THEN $2::text
ELSE name
END
RETURNING *;
```
```go
type UpdateAuthorNameParams struct {
Column1 bool `json:""`
Column2_2 string `json:"_2"`
}
```
In these cases, named parameters give you the control over field names on the
Params struct.
```sql
-- name: UpsertAuthorName :one
UPDATE author
SET
name = CASE WHEN sqlc.arg(set_name)::bool
THEN sqlc.arg(name)::text
ELSE name
END
RETURNING *;
```
```go
type UpdateAuthorNameParams struct {
SetName bool `json:"set_name"`
Name string `json:"name"`
}
```
If the `sqlc.arg()` syntax is too verbose for your taste, you can use the `@`
operator as a shortcut.
> [!NOTE]
> The `@` operator as a shortcut for `sqlc.arg()` is not supported in MySQL.
```sql
-- name: UpsertAuthorName :one
UPDATE author
SET
name = CASE WHEN @set_name::bool
THEN @name::text
ELSE name
END
RETURNING *;
```
## Nullable parameters
sqlc infers the nullability of any specified parameters, and often does exactly
what you want. If you want finer control over the nullability of your
parameters, you may use `sqlc.narg()` (**n**ullable arg) to override the default
behavior. Using `sqlc.narg` tells sqlc to ignore whatever nullability it has
inferred and generate a nullable parameter instead. There is no nullable
equivalent of the `@` syntax.
Here is an example that uses a single query to allow updating an author's
name, bio or both.
```sql
-- name: UpdateAuthor :one
UPDATE author
SET
name = coalesce(sqlc.narg('name'), name),
bio = coalesce(sqlc.narg('bio'), bio)
WHERE id = sqlc.arg('id')
RETURNING *;
```
The following code is generated:
```go
type UpdateAuthorParams struct {
Name sql.NullString
Bio sql.NullString
ID int64
}
```

184
docs/howto/overrides.md Normal file
View File

@@ -0,0 +1,184 @@
# Overriding types
> [!NOTE]
> Type overrides and field renaming are only fully-supported for Go.
In many cases it's useful to tell `sqlc` explicitly what Go type you want it to
use for a query input or output. For instance, by default when you use
`pgx/v5`, `sqlc` will map a PostgreSQL UUID type to `UUID` from `github.com/jackc/pgx/pgtype`.
But you may want `sqlc` to use `UUID` from `github.com/google/uuid` instead.
To tell `sqlc` to use a different Go type, add an entry to the `overrides` list in your
configuration.
`sqlc` offers two kinds of Go type overrides:
* `db_type` overrides, which override the Go type for a specific database type.
* `column` overrides, which override the Go type for a column or columns by name.
Here's an example including one of each kind:
```yaml
version: "2"
sql:
- schema: "postgresql/schema.sql"
queries: "postgresql/query.sql"
engine: "postgresql"
gen:
go:
package: "authors"
out: "db"
sql_package: "pgx/v5"
overrides:
- db_type: "uuid"
nullable: true
go_type:
import: "github.com/google/uuid"
type: "UUID"
- column: "users.birthday"
go_type: "time.Time"
```
> [!TIP]
> A single `db_type` override configuration applies to either nullable or non-nullable
> columns, but not both. If you want the same Go type to override regardless of
> nullability, you'll need to configure two overrides: one with `nullable: true` and one without.
## The `overrides` list
Each element in the `overrides` list has the following keys:
- `db_type`:
- A database type to override. Find the full list of supported types in [postgresql_type.go](https://github.com/sqlc-dev/sqlc/blob/main/internal/codegen/golang/postgresql_type.go#L12) or [mysql_type.go](https://github.com/sqlc-dev/sqlc/blob/main/internal/codegen/golang/mysql_type.go#L12). Note that for Postgres you must use pg_catalog-prefixed names where available. `db_type` and `column` are mutually exclusive.
- `column`:
- A column name to override. The value should be of the form `table.column` but you can also specify `schema.table.column` or `catalog.schema.table.column`. `column` and `db_type` are mutually exclusive.
- `go_type`:
- The fully-qualified name of a Go type to use in generated code. This is usually a string but can also be [a map](#the-go_type-map) for more complex configurations.
- `go_struct_tag`:
- A reflect-style struct tag to use in generated code, e.g. `a:"b" x:"y,z"`.
If you want `json` or `db` tags for all fields, configure `emit_json_tags` or `emit_db_tags` instead.
- `unsigned`:
- If `true`, sqlc will apply this override when a numeric column is unsigned.
Note that this only applies to `db_type` overrides and has no effect on `column` overrides.
Defaults to `false`.
- `nullable`:
- If `true`, sqlc will apply this override when a column is nullable.
Otherwise `sqlc` will apply this override when a column is non-nullable.
Note that this only applies to `db_type` overrides and has no effect on `column` overrides.
Defaults to `false`.
> [!TIP]
> A single `db_type` override configuration applies to either nullable or non-nullable
> columns, but not both. If you want the same Go type to override regardless of nullability, you'll
> need to configure two overrides: one with `nullable: true` and one without.
> [!NOTE]
> When generating code, `column` override configurations take precedence over `db_type` configurations.
### The `go_type` map
Some overrides may require more detailed configuration. If necessary, `go_type`
can be a map with the following keys:
- `import`:
- The import path for the package where the type is defined.
- `package`:
- The package name where the type is defined. This should only be necessary when your import path doesn't end with the desired package name.
- `type`:
- The type name itself, without any package prefix.
- `pointer`:
- If `true`, generated code will use a pointer to the type rather than the type itself.
- `slice`:
- If `true`, generated code will use a slice of the type rather than the type itself.
An example:
```yaml
version: "2"
sql:
- schema: "postgresql/schema.sql"
queries: "postgresql/query.sql"
engine: "postgresql"
gen:
go:
package: "authors"
out: "db"
sql_package: "pgx/v5"
overrides:
- db_type: "uuid"
go_type:
import: "a/b/v2"
package: "b"
type: "MyType"
pointer: true
```
## Global overrides
To override types in all packages that `sqlc` generates, add an override
configuration to the top-level `overrides` section of your `sqlc` config:
```yaml
version: "2"
overrides:
go:
overrides:
- db_type: "pg_catalog.timestamptz"
nullable: true
engine: "postgresql"
go_type:
import: "gopkg.in/guregu/null.v4"
package: "null"
type: "Time"
sql:
- schema: "service1/schema.sql"
queries: "service1/query.sql"
engine: "postgresql"
gen:
go:
package: "service1"
out: "service1"
- schema: "service2/schema.sql"
queries: "service2/query.sql"
engine: "postgresql"
gen:
go:
package: "service2"
out: "service2"
```
Using this configuration, whenever there is a nullable `timestamp with time zone`
column in a Postgres table, `sqlc` will generate Go code using `null.Time`.
Note that the mapping for global type overrides has a field called `engine` that
is absent in per-package type overrides. This field is only used when there are
multiple `sql` sections using different engines. If you're only generating code
for a single database engine you can omit it.
#### Version 1 configuration
If you are using the older version 1 of the `sqlc` configuration format, override
configurations themselves are unchanged but are nested differently.
Per-package configurations are nested under the `overrides` key within an item
in the `packages` list:
```yaml
version: "1"
packages:
- name: "db"
path: "internal/db"
queries: "./sql/query/"
schema: "./sql/schema/"
engine: "postgresql"
overrides: [...]
```
And global configurations are nested under the top-level `overrides` key:
```yaml
version: "1"
packages: [...]
overrides:
- db_type: "uuid"
go_type: "github.com/gofrs/uuid.UUID"
```

111
docs/howto/parse.md Normal file
View File

@@ -0,0 +1,111 @@
# `parse` - Parsing SQL into an AST
> [!NOTE]
> `parse` is in beta. Its flags and the shape of the JSON AST it
> prints may change in a future release.
`sqlc parse` parses SQL from a file or standard input and prints the abstract
syntax tree (AST) as a single JSON document. It does not require a configuration
file or a database connection.
Each statement is reported with its sqlc query name and command (when the
statement carries a [`-- name:`](../reference/query-annotations.md) annotation)
alongside its AST.
## Usage
```sh
sqlc parse --dialect <dialect> [file]
```
The SQL is read from the given file, or from standard input when no file is
provided.
## Flags
- `--dialect`, `-d` - The SQL dialect to use. One of `postgresql`, `mysql`,
`sqlite`, `clickhouse`, `googlesql`, `mssql`, or `duckdb`. Required.
## Examples
Parse a query file:
```sh
sqlc parse --dialect postgresql query.sql
```
Parse SQL piped via standard input:
```sh
echo "SELECT 1;" | sqlc parse --dialect mysql
```
The output is a JSON array with one object per statement:
```json
[
{
"name": "GetAuthor",
"cmd": ":one",
"ast": {
"tag": "RawStmt",
"stmt": {
"...": "..."
},
"stmt_location": 0,
"stmt_len": 42
}
}
]
```
Statements without a `-- name:` annotation (for example schema DDL) omit the
`name` and `cmd` fields. Field names are `snake_case` versions of the AST node
field names.
## Node types
Every node in the AST carries a `tag` naming its type. Some nodes have no
fields of their own, so without it a star, a null literal and an untranslated
clause would all print as `{}`.
```json
"val": {
"tag": "ColumnRef",
"name": "",
"fields": {
"tag": "List",
"items": [
{
"tag": "A_Star"
}
]
},
"location": 93
}
```
A `tag` of `TODO` marks a clause the dialect's converter does not translate
yet. It means the clause was parsed but is not represented in the AST, not that
the clause was absent from the query.
## Absent fields
A field the statement does not use is left out rather than printed as `null`.
An `A_Const` carrying an integer reports only what it has:
```json
"val": {
"tag": "A_Const",
"val": {
"tag": "Integer",
"ival": 1
},
"location": 30
}
```
Only absent fields — and empty lists, which engines construct differently for
the same SQL — are omitted. A zero keeps its place, because zero is a value the
parser can find: `stmt_location` is 0 for the first statement in a file, and
`LIMIT 0` parses to an `ival` of 0.

View File

@@ -0,0 +1,89 @@
# Preparing queries
If you're using `pgx/v5` you get its
[implicit support](https://github.com/jackc/pgx/wiki/Automatic-Prepared-Statement-Caching)
for prepared statements. No additional `sqlc` configuration is required.
For other drivers, `sqlc` can give you the option to explicitly use prepared
queries. These prepared queries also work with transactions.
You'll need to set `emit_prepared_queries` to `true` in your `sqlc` configuration
to generate code similar to the example below.
```sql
CREATE TABLE records (
id SERIAL PRIMARY KEY
);
-- name: GetRecord :one
SELECT * FROM records
WHERE id = $1;
```
```go
package db
import (
"context"
"database/sql"
"fmt"
)
type Record struct {
ID int32
}
type DBTX interface {
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
q := Queries{db: db}
var err error
if q.getRecordStmt, err = db.PrepareContext(ctx, getRecord); err != nil {
return nil, fmt.Errorf("error preparing query GetRecord: %w", err)
}
return &q, nil
}
func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...)
case stmt != nil:
return stmt.QueryRowContext(ctx, args...)
default:
return q.db.QueryRowContext(ctx, query, args...)
}
}
type Queries struct {
db DBTX
tx *sql.Tx
getRecordStmt *sql.Stmt
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
tx: tx,
getRecordStmt: q.getRecordStmt,
}
}
const getRecord = `-- name: GetRecord :one
SELECT id FROM records
WHERE id = $1
`
func (q *Queries) GetRecord(ctx context.Context, id int32) (int32, error) {
row := q.queryRow(ctx, q.getRecordStmt, getRecord, id)
err := row.Scan(&id)
return id, err
}
```

70
docs/howto/push.md Normal file
View File

@@ -0,0 +1,70 @@
# `push` - Uploading projects
> [!NOTE]
> `push` is powered by [sqlc Cloud](https://dashboard.sqlc.dev). Sign up for [free](https://dashboard.sqlc.dev) today.
*Added in v1.24.0*
We've renamed the `upload` sub-command to `push`. We've also changed the data sent along in a push request. Upload used to include the configuration file, migrations, queries, and all generated code. Push drops the generated code in favor of including the [plugin.GenerateRequest](https://buf.build/sqlc/sqlc/docs/main:plugin#plugin.GenerateRequest), which is the protocol buffer message we pass to codegen plugins.
## Add configuration
After creating a project, add the project ID to your sqlc configuration file.
```yaml
version: "2"
cloud:
project: "<PROJECT_ID>"
```
You'll also need to create an auth token and make it available via the
`SQLC_AUTH_TOKEN` environment variable.
```shell
export SQLC_AUTH_TOKEN=sqlc_xxxxxxxx
```
## Dry run
You can see what's included when uploading your project by using using the
`--dry-run` flag:
```shell
$ sqlc push --dry-run
2023/11/21 10:39:51 INFO config file=sqlc.yaml bytes=912
2023/11/21 10:39:51 INFO codegen_request queryset=app file=codegen_request.pb
2023/11/21 10:39:51 INFO schema queryset=app file=migrations/00001_initial.sql bytes=3033
2023/11/21 10:39:51 INFO query queryset=app file=queries/app.sql bytes=1150
```
The output is the files `sqlc` would have sent without the `--dry-run` flag.
## Push
Once you're ready to push, remove the `--dry-run` flag.
```shell
$ sqlc push
```
### Tags
You can provide tags to associate with a push, primarily as a convenient reference when using `sqlc verify` with the `against` argument.
Tags only refer to a single push, so if you pass an existing tag to `push` it will overwrite the previous reference.
```shell
$ sqlc push --tag main
```
### Annotations
Annotations are added to each push request. By default, we include these environment variables (if they are present).
```
GITHUB_REPOSITORY
GITHUB_REF
GITHUB_REF_NAME
GITHUB_REF_TYPE
GITHUB_SHA
```

83
docs/howto/query_count.md Normal file
View File

@@ -0,0 +1,83 @@
# Counting rows
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
hometown text NOT NULL
);
-- name: CountAuthors :one
SELECT count(*) FROM authors;
-- name: CountAuthorsByTown :many
SELECT hometown, count(*) FROM authors
GROUP BY 1
ORDER BY 1;
```
```go
package db
import (
"context"
"database/sql"
)
type DBTX interface {
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
const countAuthors = `-- name: CountAuthors :one
SELECT count(*) FROM authors
`
func (q *Queries) CountAuthors(ctx context.Context) (int, error) {
row := q.db.QueryRowContext(ctx, countAuthors)
var i int
err := row.Scan(&i)
return i, err
}
const countAuthorsByTown = `-- name: CountAuthorsByTown :many
SELECT hometown, count(*) FROM authors
GROUP BY 1
ORDER BY 1
`
type CountAuthorsByTownRow struct {
Hometown string
Count int
}
func (q *Queries) CountAuthorsByTown(ctx context.Context) ([]CountAuthorsByTownRow, error) {
rows, err := q.db.QueryContext(ctx, countAuthorsByTown)
if err != nil {
return nil, err
}
defer rows.Close()
items := []CountAuthorsByTownRow{}
for rows.Next() {
var i CountAuthorsByTownRow
if err := rows.Scan(&i.Hometown, &i.Count); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
```

122
docs/howto/rename.md Normal file
View File

@@ -0,0 +1,122 @@
# Renaming fields
Struct field names are generated from column names using a simple algorithm:
split the column name on underscores and capitalize the first letter of each
part.
```
account -> Account
spotify_url -> SpotifyUrl
app_id -> AppID
```
If you're not happy with a field's generated name, use the `rename` mapping
to pick a new name. The keys are column names and the values are the struct
field name to use.
```yaml
version: "2"
sql:
- schema: "postgresql/schema.sql"
queries: "postgresql/query.sql"
engine: "postgresql"
gen:
go:
package: "authors"
out: "postgresql"
rename:
spotify_url: "SpotifyURL"
```
## Tables
The output structs associated with tables can also be renamed. By default,
the struct name will be the singular version of the table name. For example,
the `authors` table will generate an `Author` struct and the `book_publishers`
table will generate a `BookPublisher` struct.
```sql
CREATE TABLE authors (
id BIGSERIAL PRIMARY KEY,
name text NOT NULL,
bio text
);
CREATE TABLE book_publishers (
id BIGSERIAL PRIMARY KEY,
name text NOT NULL
);
```
```go
package db
import (
"database/sql"
)
type Author struct {
ID int64
Name string
Bio sql.NullString
}
type Publisher struct {
ID int64
Name string
}
```
To rename these structs, you must use the generated struct name. In this
example, that would be `author` and `book_publisher`. Use the `rename` map to
change the name of these struct to `Writer` and `BookPublisher` (note the
camel-casing and the underscore for multi-worded tables).
```yaml
version: '1'
packages:
- path: db
engine: postgresql
schema: query.sql
queries: query.sql
rename:
author: Writer
book_publisher: Publisher
```
```yaml
version: "2"
sql:
- engine: postgresql
queries: query.sql
schema: query.sql
overrides:
go:
rename:
author: Writer
book_publisher: Publisher
```
```go
package db
import (
"database/sql"
)
type Writer struct {
ID int64
Name string
Bio sql.NullString
}
type Publisher struct {
ID int64
Name string
}
```
## Limitations
Rename mappings apply to an entire package. Therefore, a column named `foo` and
a table name `foo` can't map to different rename values.

393
docs/howto/select.md Normal file
View File

@@ -0,0 +1,393 @@
# Retrieving rows
To generate a database access method, annotate a query with a specific comment.
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
bio text NOT NULL,
birth_year int NOT NULL
);
```
The parameter syntax varies by database engine:
**PostgreSQL:**
```sql
-- name: GetAuthor :one
SELECT * FROM authors
WHERE id = $1;
-- name: ListAuthors :many
SELECT * FROM authors
ORDER BY id;
```
**MySQL and SQLite:**
```sql
-- name: GetAuthor :one
SELECT * FROM authors
WHERE id = ?;
-- name: ListAuthors :many
SELECT * FROM authors
ORDER BY id;
```
A few new pieces of code are generated beyond the `Author` struct. An interface
for the underlying database is generated. The `*sql.DB` and `*sql.Tx` types
satisfy this interface.
The database access methods are added to a `Queries` struct, which is created
using the `New` method.
Note that the `*` in our query has been replaced with explicit column names.
This change ensures that the query will never return unexpected data.
Our query was annotated with `:one`, meaning that it should only return a
single row. We scan the data from that one into a `Author` struct.
Since the get query has a single parameter, the `GetAuthor` method takes a single
`int` as an argument.
Since the list query has no parameters, the `ListAuthors` method accepts no
arguments.
```go
package db
import (
"context"
"database/sql"
)
type Author struct {
ID int
Bio string
BirthYear int
}
type DBTX interface {
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
const getAuthor = `-- name: GetAuthor :one
SELECT id, bio, birth_year FROM authors
WHERE id = $1
`
func (q *Queries) GetAuthor(ctx context.Context, id int) (Author, error) {
row := q.db.QueryRowContext(ctx, getAuthor, id)
var i Author
err := row.Scan(&i.ID, &i.Bio, &i.BirthYear)
return i, err
}
const listAuthors = `-- name: ListAuthors :many
SELECT id, bio, birth_year FROM authors
ORDER BY id
`
func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) {
rows, err := q.db.QueryContext(ctx, listAuthors)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Author
for rows.Next() {
var i Author
if err := rows.Scan(&i.ID, &i.Bio, &i.BirthYear); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
```
## Selecting columns
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
bio text NOT NULL,
birth_year int NOT NULL
);
-- name: GetBioForAuthor :one
SELECT bio FROM authors
WHERE id = $1;
-- name: GetInfoForAuthor :one
SELECT bio, birth_year FROM authors
WHERE id = $1;
```
When selecting a single column, only that value is returned. The `GetBioForAuthor`
method takes a single `int` as an argument and returns a `string` and an
`error`.
When selecting multiple columns, a row record (method-specific struct) is
returned. In this case, `GetInfoForAuthor` returns a struct with two fields:
`Bio` and `BirthYear`.
If a query result has no row records, a zero value and an `ErrNoRows` error are
returned instead of a zero value and `nil`. For instance, when the `GetBioForAuthor`
result has no rows, it will return `""` and `ErrNoRows`.
```go
package db
import (
"context"
"database/sql"
)
type DBTX interface {
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
const getBioForAuthor = `-- name: GetBioForAuthor :one
SELECT bio FROM authors
WHERE id = $1
`
func (q *Queries) GetBioForAuthor(ctx context.Context, id int) (string, error) {
row := q.db.QueryRowContext(ctx, getBioForAuthor, id)
var i string
err := row.Scan(&i)
return i, err
}
const getInfoForAuthor = `-- name: GetInfoForAuthor :one
SELECT bio, birth_year FROM authors
WHERE id = $1
`
type GetInfoForAuthorRow struct {
Bio string
BirthYear int
}
func (q *Queries) GetInfoForAuthor(ctx context.Context, id int) (GetInfoForAuthorRow, error) {
row := q.db.QueryRowContext(ctx, getInfoForAuthor, id)
var i GetInfoForAuthorRow
err := row.Scan(&i.Bio, &i.BirthYear)
return i, err
}
```
## Passing a slice as a parameter to a query
### PostgreSQL
In PostgreSQL,
[ANY](https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.28.16)
allows you to check if a value exists in an array expression. Queries using ANY
with a single parameter will generate method signatures with slices as
arguments. Use the postgres data types, eg: int, varchar, etc.
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
bio text NOT NULL,
birth_year int NOT NULL
);
-- name: ListAuthorsByIDs :many
SELECT * FROM authors
WHERE id = ANY($1::int[]);
```
The above SQL will generate the following code:
```go
package db
import (
"context"
"database/sql"
"github.com/lib/pq"
)
type Author struct {
ID int
Bio string
BirthYear int
}
type DBTX interface {
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
const listAuthors = `-- name: ListAuthorsByIDs :many
SELECT id, bio, birth_year FROM authors
WHERE id = ANY($1::int[])
`
func (q *Queries) ListAuthorsByIDs(ctx context.Context, ids []int) ([]Author, error) {
rows, err := q.db.QueryContext(ctx, listAuthors, pq.Array(ids))
if err != nil {
return nil, err
}
defer rows.Close()
var items []Author
for rows.Next() {
var i Author
if err := rows.Scan(&i.ID, &i.Bio, &i.BirthYear); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
```
### MySQL and SQLite
MySQL and SQLite differ from PostgreSQL in that placeholders must be generated based on
the number of elements in the slice you pass in. Though trivial it is still
something of a nuisance. The passed in slice must not be nil or empty or an
error will be returned (ie not a panic). The placeholder insertion location is
marked by the meta-function `sqlc.slice()` (which is similar to `sqlc.arg()`
that you see documented under [Naming parameters](named_parameters.md)).
To rephrase, the `sqlc.slice('param')` behaves identically to `sqlc.arg()` it
terms of how it maps the explicit argument to the function signature, eg:
* `sqlc.slice('ids')` maps to `ids []GoType` in the function signature
* `sqlc.slice(cust_ids)` maps to `custIds []GoType` in the function signature
(like `sqlc.arg()`, the parameter does not have to be quoted)
This feature is not compatible with `emit_prepared_queries` statement found in the
[Configuration file](../reference/config.md).
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
bio text NOT NULL,
birth_year int NOT NULL
);
-- name: ListAuthorsByIDs :many
SELECT * FROM authors
WHERE id IN (sqlc.slice('ids'));
```
The above SQL will generate the following code:
```go
package db
import (
"context"
"database/sql"
"fmt"
"strings"
)
type Author struct {
ID int
Bio string
BirthYear int
}
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
}
}
const listAuthorsByIDs = `-- name: ListAuthorsByIDs :many
SELECT id, bio, birth_year FROM authors
WHERE id IN (/*SLICE:ids*/?)
`
func (q *Queries) ListAuthorsByIDs(ctx context.Context, ids []int64) ([]Author, error) {
sql := listAuthorsByIDs
var queryParams []any
if len(ids) == 0 {
return nil, fmt.Errorf("slice ids must have at least one element")
}
for _, v := range ids {
queryParams = append(queryParams, v)
}
sql = strings.Replace(sql, "/*SLICE:ids*/?", strings.Repeat(",?", len(ids))[1:], 1)
rows, err := q.db.QueryContext(ctx, sql, queryParams...)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Author
for rows.Next() {
var i Author
if err := rows.Scan(&i.ID, &i.Bio, &i.BirthYear); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
```

53
docs/howto/structs.md Normal file
View File

@@ -0,0 +1,53 @@
# Configuring generated structs
## Naming scheme
Structs generated from tables will attempt to use the singular form of a table
name if the table name is pluralized.
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
name text NOT NULL
);
```
```go
package db
// Struct names use the singular form of table names
type Author struct {
ID int
Name string
}
```
## JSON tags
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
created_at timestamp NOT NULL
);
```
sqlc can generate structs with JSON tags by adding the `emit_json_tags` key to the configuration file as it shows on [configuration reference](../reference/config.md).
The JSON name for a field matches
the column name in the database.
```go
package db
import (
"time"
)
type Author struct {
ID int `json:"id"`
CreatedAt time.Time `json:"created_at"`
}
```
## More control
See the guide to [Overriding types](./overrides.md) for fine-grained control over struct field types and tags.

101
docs/howto/transactions.md Normal file
View File

@@ -0,0 +1,101 @@
# Using transactions
In the code generated by sqlc, the `WithTx` method allows a `Queries` instance to be associated with a transaction.
For example, with the following SQL structure:
`schema.sql`:
```sql
CREATE TABLE records (
id SERIAL PRIMARY KEY,
counter INT NOT NULL
);
```
`query.sql`
```sql
-- name: GetRecord :one
SELECT * FROM records
WHERE id = $1;
-- name: UpdateRecord :exec
UPDATE records SET counter = $2
WHERE id = $1;
```
And the generated code from sqlc in `db.go`:
```go
package tutorial
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
}
}
```
You'd use it like this:
```go
// Using `github/lib/pq` as the driver.
func bumpCounter(ctx context.Context, db *sql.DB, queries *tutorial.Queries, id int32) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
qtx := queries.WithTx(tx)
r, err := qtx.GetRecord(ctx, id)
if err != nil {
return err
}
if err := qtx.UpdateRecord(ctx, tutorial.UpdateRecordParams{
ID: r.ID,
Counter: r.Counter + 1,
}); err != nil {
return err
}
return tx.Commit()
}
// Using `github.com/jackc/pgx/v5` as the driver.
func bumpCounter(ctx context.Context, db *pgx.Conn, queries *tutorial.Queries, id int32) error {
tx, err := db.Begin(ctx)
if err != nil {
return err
}
defer tx.Rollback(ctx)
qtx := queries.WithTx(tx)
r, err := qtx.GetRecord(ctx, id)
if err != nil {
return err
}
if err := qtx.UpdateRecord(ctx, tutorial.UpdateRecordParams{
ID: r.ID,
Counter: r.Counter + 1,
}); err != nil {
return err
}
return tx.Commit(ctx)
}
```

115
docs/howto/update.md Normal file
View File

@@ -0,0 +1,115 @@
# Updating rows
```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
bio text NOT NULL
);
```
## Single parameter
If your query has a single parameter, your Go method will also have a single
parameter.
The parameter syntax varies by database engine:
**PostgreSQL:**
```sql
-- name: UpdateAuthorBios :exec
UPDATE authors SET bio = $1;
```
**MySQL and SQLite:**
```sql
-- name: UpdateAuthorBios :exec
UPDATE authors SET bio = ?;
```
```go
package db
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
const updateAuthorBios = `-- name: UpdateAuthorBios :exec
UPDATE authors SET bio = $1
`
func (q *Queries) UpdateAuthorBios(ctx context.Context, bio string) error {
_, err := q.db.ExecContext(ctx, updateAuthorBios, bio)
return err
}
```
## Multiple parameters
If your query has more than one parameter, your Go method will accept a
`Params` struct.
**PostgreSQL:**
```sql
-- name: UpdateAuthor :exec
UPDATE authors SET bio = $2
WHERE id = $1;
```
**MySQL and SQLite:**
```sql
-- name: UpdateAuthor :exec
UPDATE authors SET bio = ?
WHERE id = ?;
```
Note: For MySQL and SQLite, parameters are bound in the order they appear in the query, regardless of the order in the function signature.
```go
package db
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
const updateAuthor = `-- name: UpdateAuthor :exec
UPDATE authors SET bio = $2
WHERE id = $1
`
type UpdateAuthorParams struct {
ID int32
Bio string
}
func (q *Queries) UpdateAuthor(ctx context.Context, arg UpdateAuthorParams) error {
_, err := q.db.ExecContext(ctx, updateAuthor, arg.ID, arg.Bio)
return err
}
```

105
docs/howto/verify.md Normal file
View File

@@ -0,0 +1,105 @@
# `verify` - Verifying schema changes
*Added in v1.24.0*
Schema updates and poorly-written queries often bring down production databases. That’s bad.
Out of the box, `sqlc generate` catches some of these issues. Running `sqlc vet` with the `sqlc/db-prepare` rule catches more subtle problems. But there is a large class of issues that sqlc can’t prevent by looking at current schema and queries alone.
For instance, when a schema change is proposed, existing queries and code running in production might fail when the schema change is applied. Enter `sqlc verify`, which analyzes existing queries against new schema changes and errors if there are any issues.
Let's look at an example. Assume you have these two tables in production.
```sql
CREATE TABLE users (
id UUID PRIMARY KEY
);
CREATE TABLE user_actions (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
action TEXT,
created_at TIMESTAMP
);
```
Your application contains the following query to join user actions against the users table.
```sql
-- name: GetUserActions :many
SELECT * FROM users u
JOIN user_actions ua ON u.id = ua.user_id
ORDER BY created_at;
```
So far, so good. Then assume you propose this schema change:
```sql
ALTER TABLE users ADD COLUMN created_at TIMESTAMP;
```
Running `sqlc generate` fails with this change, returning a `column reference "created_at" is ambiguous` error. You update your query to fix the issue.
```sql
-- name: GetUserActions :many
SELECT * FROM users u
JOIN user_actions ua ON u.id = ua.user_id
ORDER BY u.created_at;
```
While that change fixes the issue, there's a production outage waiting to happen. When the schema change is applied, the existing `GetUserActions` query will begin to fail. The correct way to fix this is to deploy the updated query before applying the schema migration.
It ensures migrations are safe to deploy by sending your current schema and queries to sqlc cloud. There, we run the queries for your latest push against your new schema changes. This check catches backwards incompatible schema changes for existing queries.
Here `sqlc verify` alerts you to the fact that ORDER BY "created_at" is ambiguous.
```sh
$ sqlc verify
FAIL: app query.sql
=== Failed
=== FAIL: app query.sql GetUserActions
ERROR: column reference "created_at" is ambiguous (SQLSTATE 42702)
```
By the way, this scenario isn't made up! It happened to us a few weeks ago. We've been happily testing early versions of `verify` for the last two weeks and haven't had any issues since.
This type of verification is only the start. If your application is deployed on-prem by your customers, `verify` could tell you if it's safe for your customers to rollback to an older version of your app, even after schema migrations have been run.
Using `verify` requires that you push your queries and schema when you tag a release of your application. We run it on every push to main, as we continuously deploy those commits.
## Authentication
`sqlc` expects to find a valid auth token in the value of the `SQLC_AUTH_TOKEN`
environment variable. You can create an auth token via the [dashboard](https://dashboard.sqlc.dev).
```shell
export SQLC_AUTH_TOKEN=sqlc_xxxxxxxx
```
## Expected workflow
Using `sqlc verify` requires pushing your queries and schema to sqlc Cloud. When
you release a new version of your application, you should push your schema and
queries as well. For example, we run `sqlc push` after any change has been
merged into our `main` branch on Github, as we deploy every commit to
production.
```shell
$ sqlc push --tag main
```
Locally or in pull requests, run `sqlc verify` to check that existing queries
continue to work with your current database schema.
```shell
$ sqlc verify --against main
```
## Picking a tag
Without an `against` argument, `verify` will run its analysis of the provided schema using your most-recently pushed queries. We suggest using the `against` argument to explicitly select a set of queries for comparison.
```shell
$ sqlc verify --against [tag]
```

286
docs/howto/vet.md Normal file
View File

@@ -0,0 +1,286 @@
# `vet` - Linting queries
*Added in v1.19.0*
`sqlc vet` runs queries through a set of lint rules.
Rules are defined in the `sqlc` [configuration](../reference/config.md) file. They
consist of a name, message, and a [Common Expression Language
(CEL)](https://github.com/google/cel-spec) expression. Expressions are evaluated
using [cel-go](https://github.com/cel-expr/cel-go). If an expression evaluates to
`true`, `sqlc vet` will report an error using the given message.
## Defining lint rules
Each lint rule's CEL expression has access to information from your sqlc
configuration and queries via variables defined in the following proto messages.
```proto
message Config
{
string version = 1;
string engine = 2 ;
repeated string schema = 3;
repeated string queries = 4;
}
message Query
{
// SQL body
string sql = 1;
// Name of the query
string name = 2;
// One of "many", "one", "exec", etc.
string cmd = 3;
// Query parameters, if any
repeated Parameter params = 4;
}
message Parameter
{
int32 number = 1;
}
```
In addition to this basic information, when you have a PostgreSQL or MySQL
[database connection configured](../reference/config.md#database)
each CEL expression has access to the output from running `EXPLAIN ...` on your query
via the `postgresql.explain` and `mysql.explain` variables.
This output is quite complex and depends on the structure of your query but sqlc attempts
to parse and provide as much information as it can. See
[Rules using `EXPLAIN ...` output](#rules-using-explain--output) for more information.
Here are a few example rules just using the basic configuration and query information available
to the CEL expression environment. While these examples are simplistic, they give you a flavor
of the types of rules you can write.
```yaml
version: 2
sql:
- schema: "query.sql"
queries: "query.sql"
engine: "postgresql"
gen:
go:
package: "authors"
out: "db"
rules:
- no-pg
- no-delete
- only-one-param
- no-exec
rules:
- name: no-pg
message: "invalid engine: postgresql"
rule: |
config.engine == "postgresql"
- name: no-delete
message: "don't use delete statements"
rule: |
query.sql.contains("DELETE")
- name: only-one-param
message: "too many parameters"
rule: |
query.params.size() > 1
- name: no-exec
message: "don't use exec"
rule: |
query.cmd == "exec"
```
### Rules using `EXPLAIN ...` output
*Added in v1.20.0*
The CEL expression environment has two variables containing `EXPLAIN ...` output,
`postgresql.explain` and `mysql.explain`. `sqlc` only populates the variable associated with
your configured database engine, and only when you have a
[database connection configured](../reference/config.md#database).
For the `postgresql` engine, `sqlc` runs
```sql
EXPLAIN (ANALYZE false, VERBOSE, COSTS, SETTINGS, BUFFERS, FORMAT JSON) ...
```
where `"..."` is your query string, and parses the output into a [`PostgreSQLExplain`](https://buf.build/sqlc/sqlc/docs/v1.20.0:vet#vet.PostgreSQLExplain) proto message.
For the `mysql` engine, `sqlc` runs
```sql
EXPLAIN FORMAT=JSON ...
```
where `"..."` is your query string, and parses the output into a [`MySQLExplain`](https://buf.build/sqlc/sqlc/docs/v1.20.0:vet#vet.MySQLExplain) proto message.
These proto message definitions are too long to include here, but you can find them in the `protos`
directory within the `sqlc` source tree.
The output from `EXPLAIN ...` depends on the structure of your query so it's a bit difficult
to offer generic examples. Refer to the
[PostgreSQL documentation](https://www.postgresql.org/docs/current/using-explain.html) and
[MySQL documentation](https://dev.mysql.com/doc/refman/en/explain-output.html) for more
information.
```yaml
...
rules:
- name: postgresql-query-too-costly
message: "Query cost estimate is too high"
rule: "postgresql.explain.plan.total_cost > 1.0"
- name: postgresql-no-seq-scan
message: "Query plan results in a sequential scan"
rule: "postgresql.explain.plan.node_type == 'Seq Scan'"
- name: mysql-query-too-costly
message: "Query cost estimate is too high"
rule: "has(mysql.explain.query_block.cost_info) && double(mysql.explain.query_block.cost_info.query_cost) > 2.0"
- name: mysql-must-use-primary-key
message: "Query plan doesn't use primary key"
rule: "has(mysql.explain.query_block.table.key) && mysql.explain.query_block.table.key != 'PRIMARY'"
```
When building rules that depend on `EXPLAIN ...` output, it may be helpful to see the actual JSON
returned from the database. `sqlc` will print it When you set the environment variable
`SQLCDEBUG=dumpexplain=1`. Use this environment variable together with a dummy rule to see
`EXPLAIN ...` output for all of your queries.
```yaml
version: 2
sql:
- schema: "query.sql"
queries: "query.sql"
engine: "postgresql"
database:
uri: "postgresql://postgres:postgres@localhost:5432/postgres"
gen:
go:
package: "db"
out: "db"
rules:
- debug
rules:
- name: debug
rule: "!has(postgresql.explain)" # A dummy rule to trigger explain
```
Please note that databases configured with a `uri` must have an up-to-date
schema for `vet` to work correctly, and `sqlc` does not apply schema migrations
to your database. Use your migration tool of choice to create the necessary
tables and objects before running `sqlc vet` with rules that depend on
`EXPLAIN ...` output.
Alternatively, configure [managed databases](managed-databases.md) to have
`sqlc` create hosted ephemeral databases with the correct schema automatically.
## Built-in rules
### sqlc/db-prepare
When a [database](../reference/config.md#database) connection is configured, you can
run the built-in `sqlc/db-prepare` rule. This rule will attempt to prepare
each of your queries against the connected database and report any failures.
```yaml
version: 2
sql:
- schema: "schema.sql"
queries: "query.sql"
engine: "postgresql"
gen:
go:
package: "authors"
out: "db"
database:
uri: "postgresql://postgres:password@localhost:5432/postgres"
rules:
- sqlc/db-prepare
```
Please note that databases configured with a `uri` must have an up-to-date
schema for `vet` to work correctly, and `sqlc` does not apply schema migrations
to your database. Use your migration tool of choice to create the necessary
tables and objects before running `sqlc vet` with the `sqlc/db-prepare` rule.
Alternatively, configure [managed databases](managed-databases.md) to have
`sqlc` create hosted ephemeral databases with the correct schema automatically.
```yaml
version: 2
cloud:
project: "<PROJECT_ID>"
sql:
- schema: "schema.sql"
queries: "query.sql"
engine: "postgresql"
gen:
go:
package: "authors"
out: "db"
database:
managed: true
rules:
- sqlc/db-prepare
```
To see this in action, check out the [authors
example](https://github.com/sqlc-dev/sqlc/blob/main/examples/authors/sqlc.yaml).
## Running lint rules
When you add the name of a defined rule to the rules list
for a [sql package](../reference/config.md#sql),
`sqlc vet` will evaluate that rule against every query in the package.
In the example below, two rules are defined but only one is enabled.
```yaml
version: 2
sql:
- schema: "query.sql"
queries: "query.sql"
engine: "postgresql"
gen:
go:
package: "authors"
out: "db"
rules:
- no-delete
rules:
- name: no-pg
message: "invalid engine: postgresql"
rule: |
config.engine == "postgresql"
- name: no-delete
message: "don't use delete statements"
rule: |
query.sql.contains("DELETE")
```
### Opting-out of lint rules
For any query, you can tell `sqlc vet` not to evaluate lint rules using the
`@sqlc-vet-disable` query annotation. The annotation accepts a list of rules to ignore.
```sql
/* name: GetAuthor :one */
/* @sqlc-vet-disable sqlc/db-prepare no-pg */
SELECT * FROM authors
WHERE id = ? LIMIT 1;
```
The rules can also be split across lines.
```sql
/* name: GetAuthor :one */
/* @sqlc-vet-disable sqlc/db-prepare */
/* @sqlc-vet-disable no-pg */
SELECT * FROM authors
WHERE id = ? LIMIT 1;
```
To skip all rules for a query, you can provide the `@sqlc-vet-disable` annotation without any parameters.
```sql
/* name: GetAuthor :one */
/* @sqlc-vet-disable */
SELECT * FROM authors
WHERE id = ? LIMIT 1;
```