Skip to content

duckdb: sqlc.arg(), sqlc.narg() and @name are not rewritten #4658

Open

Description

@xen0l

Version

main at commit 3ad8b20 (2026-10-23), built with CGO_ENABLED=0 go install github.com/sqlc-dev/sqlc/cmd/sqlc@3ad8b20fb02b5bea81591b673da0758b8685d951.
sqlc version prints v1.31.1 because internal/info/facts.go hard-codes it.
The DuckDB engine was added in #4621 and is not in a tagged release.

What happened?

With engine: "duckdb", the sqlc macros for named parameters are not rewritten.
sqlc.arg(name), sqlc.narg(name) and sqlc.slice(name) fail with unknown column "name".
The @name form fails in the DuckDB parser.
Only the positional form $1 works. A query with many positional parameters gets names such as
Column1 ... Column7, unless a comparison with a column gives a name.

I do not know if this is planned. #4621 describes named arguments only for engines that use @name or {name:Type}.
If it is not planned, a note in the docs would help.

Expected: the macros work like they do in the other engines.

Cause

The preprocessor rewrites the sqlc macros before the engine parser runs (internal/sql/preprocess).
Its table dialects in dialect.go has no entry for config.EngineDuckDB, and an engine with no entry gets its
source back unchanged. The macros then reach the analyzer as function calls and column names.

Reproduction

repro4.sh
#!/usr/bin/env bash
rm -rf repro4 && mkdir repro4 && cd repro4
cat > sqlc.yaml <<'EOF'
version: "2"
sql:
  - engine: "duckdb"
    schema: "schema.sql"
    queries: "query.sql"
    gen:
      go:
        package: "repro"
        out: "out"
EOF
cat > schema.sql <<'EOF'
CREATE TABLE items (id INTEGER NOT NULL, name VARCHAR NOT NULL);
EOF
while IFS= read -r q; do
  printf -- '-- name: Q :many\n%s\n' "$q" > query.sql; rm -rf out
  echo "== $q"; sqlc generate 2>&1 | head -3; grep -hE '^func \(q \*Queries\) Q' out/query.sql.go 2>/dev/null
done <<'EOF'
SELECT id FROM items WHERE id = $1;
SELECT id FROM items WHERE id = sqlc.arg(want_id);
SELECT id FROM items WHERE id = sqlc.narg(want_id);
SELECT id FROM items WHERE id = @want_id;
SELECT id FROM items WHERE id IN (sqlc.slice(ids));
EOF

Fix and notes

I have a patch with end-to-end test cases, and I will open a pull request. Two notes on it:

  • sqlc.slice must stay rejected for this dialect. With $1 placeholders the generated Go still contains the strings.Replace that expands ? markers. The SQL has no marker, so the call changes nothing and the query binds only the first element. I ran id IN (sqlc.slice(ids)) with []int32{1, 3} on DuckDB: it returned one row and no error. The PostgreSQL engine does the same today (IN ($1) and the same no-op Replace). I did not report that here. A DuckDB user binds a list with x = ANY($1::INTEGER[]) or list_contains($1::INTEGER[], x). I ran both with []int32{1, 3} and each returned the right two rows.
  • A query that mixes sqlc.arg(a) with an explicit $2 fails with could not determine data type of parameter $1. The PostgreSQL and SQLite engines give the same error for the same mix, so I left it.

Relevant log output

== SELECT id FROM items WHERE id = $1;
func (q *Queries) Q(ctx context.Context, id int32) ([]int32, error) {
== SELECT id FROM items WHERE id = sqlc.arg(want_id);
# package repro
query.sql:1:1: where: unknown column "want_id"
== SELECT id FROM items WHERE id = sqlc.narg(want_id);
# package repro
query.sql:1:1: where: unknown column "want_id"
== SELECT id FROM items WHERE id = @want_id;
# package repro
query.sql:2:33: Parser Error: syntax error at or near "@"
== SELECT id FROM items WHERE id IN (sqlc.slice(ids));
# package repro
query.sql:1:1: where: unknown column "ids"

Database schema

CREATE TABLE items (id INTEGER NOT NULL, name VARCHAR NOT NULL);

SQL queries

SELECT id FROM items WHERE id = $1;
SELECT id FROM items WHERE id = sqlc.arg(want_id);
SELECT id FROM items WHERE id = sqlc.narg(want_id);
SELECT id FROM items WHERE id = @want_id;
SELECT id FROM items WHERE id IN (sqlc.slice(ids));

Configuration

version: "2"
sql:
  - engine: "duckdb"
    schema: "schema.sql"
    queries: "query.sql"
    gen:
      go:
        package: "repro"
        out: "out"

Playground URL

Not available. play.sqlc.dev runs only v1.18.0–v1.25.0, and the DuckDB engine is not in a release (v1.25.0 answers unknown engine: duckdb; main, a commit and every later release return HTTP 500). The report has a script that needs only go install github.com/sqlc-dev/sqlc/cmd/sqlc@3ad8b20fb02b5bea81591b673da0758b8685d951.

What operating system are you using?

Linux

What database engines are you using?

(none of the listed options; the engine is duckdb)

What type of code are you generating?

Go

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions