Skip to content

Commit ec32eee

Browse files
luongs3claude
andcommitted
fix(codegen): no spurious lib/pq import for MySQL with sqlc.narg + sqlc.slice (#3783)
Problem ------- A MySQL query that references the same named parameter as both a regular argument (e.g. `sqlc.narg('x') IS NULL`) and a `sqlc.slice('x')` expansion produced Go code that imports `github.com/lib/pq` even though the import is unused — the runtime path expands the slice in-place via the `/*SLICE:...*/?` placeholder and never calls `pq.Array`. Root cause ---------- The two references generate two `goColumn` entries with the same name and type; only the slice variant carries the `IsSqlcSlice` flag. The non-slice duplicate field still satisfies the `[]T && !sqlc.slice` condition in `sliceScan()` inside `internal/codegen/golang/imports.go`, which causes `lib/pq` to be added to the import set. The struct itself is rendered through `UniqueFields` so only one field is emitted, but the import-bookkeeping pass sees both. Fix --- In `sliceScan()`, collect the names of all fields carrying `IsSqlcSlice` first, then skip any field whose name matches one of those when deciding whether to require `lib/pq`. The duplicate is already handled by the slice-expansion code path and does not need `pq.Array`. Tests ----- - New endtoend fixture `mysql_slice_narg_no_pq_3783/mysql` mirrors the issue's repro; golden files confirm no `lib/pq` import in the generated code. - Full `internal/endtoend` TestReplay suite passes. - `go test ./internal/codegen/... ./internal/compiler/... ./internal/sql/...` clean. What does NOT change -------------------- - Postgres / pgx output is unaffected (the field-name filter only suppresses lib/pq when a sqlc.slice with the same name exists, and pgx never went through the lib/pq branch anyway). - MySQL queries that use `sqlc.slice` alone, or a plain `[]T` argument, are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a3b0cfd commit ec32eee

7 files changed

Lines changed: 158 additions & 0 deletions

File tree

internal/codegen/golang/imports.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,24 @@ func (i *importer) queryImports(filename string) fileImports {
376376
}
377377
if !q.Arg.isEmpty() {
378378
if q.Arg.IsStruct() {
379+
// A single named parameter referenced as both a regular
380+
// argument (e.g. `sqlc.narg(x) IS NULL`) and as a
381+
// `sqlc.slice('x')` produces two struct fields sharing
382+
// the same name and type, but only the slice variant
383+
// carries the IsSqlcSlice flag. The non-slice duplicate
384+
// must not be counted as a `[]T` arg requiring lib/pq,
385+
// because the generated code expands the slice in-place
386+
// via `/*SLICE:...*/?` and never calls pq.Array on it.
387+
sqlcSliceNames := map[string]struct{}{}
379388
for _, f := range q.Arg.Struct.Fields {
389+
if f.HasSqlcSlice() {
390+
sqlcSliceNames[f.Name] = struct{}{}
391+
}
392+
}
393+
for _, f := range q.Arg.Struct.Fields {
394+
if _, ok := sqlcSliceNames[f.Name]; ok {
395+
continue
396+
}
380397
if strings.HasPrefix(f.Type, "[]") && f.Type != "[]byte" && !f.HasSqlcSlice() {
381398
return true
382399
}

internal/endtoend/testdata/mysql_slice_narg_no_pq_3783/mysql/go/db.go

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/mysql_slice_narg_no_pq_3783/mysql/go/models.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/mysql_slice_narg_no_pq_3783/mysql/go/query.sql.go

Lines changed: 68 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-- https://github.com/sqlc-dev/sqlc/issues/3783
2+
-- name: CausesPgToBeImported :many
3+
SELECT
4+
id AS author_id,
5+
name AS author_name,
6+
bio AS author_bio
7+
FROM
8+
authors
9+
WHERE
10+
(sqlc.narg('author_ids') IS NULL OR id IN (sqlc.slice('author_ids')));
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CREATE TABLE authors (
2+
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
name text NOT NULL,
4+
bio text
5+
);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": "1",
3+
"packages": [
4+
{
5+
"engine": "mysql",
6+
"path": "go",
7+
"name": "querytest",
8+
"schema": "schema.sql",
9+
"queries": "query.sql"
10+
}
11+
]
12+
}

0 commit comments

Comments
 (0)