Skip to content

fix(codegen): no spurious lib/pq import for MySQL with sqlc.narg + sqlc.slice (#3783)#4460

Open
luongs3 wants to merge 1 commit into
sqlc-dev:mainfrom
luongs3:fix/3783-mysql-spurious-lib-pq-import
Open

fix(codegen): no spurious lib/pq import for MySQL with sqlc.narg + sqlc.slice (#3783)#4460
luongs3 wants to merge 1 commit into
sqlc-dev:mainfrom
luongs3:fix/3783-mysql-spurious-lib-pq-import

Conversation

@luongs3
Copy link
Copy Markdown

@luongs3 luongs3 commented May 28, 2026

Problem

A MySQL query that references the same named parameter as both a regular argument (e.g. sqlc.narg('x') IS NULL) and as sqlc.slice('x') produces Go code that imports github.com/lib/pq (a Postgres library) even though the import is unused — the runtime path expands the slice in-place via the /*SLICE:...*/? placeholder and never calls pq.Array.

Closes #3783.

Minimal repro (from the issue)

-- name: CausesPgToBeImported :many
SELECT id AS author_id, name AS author_name, bio AS author_bio
FROM authors
WHERE (sqlc.narg('author_ids') IS NULL OR id IN (sqlc.slice('author_ids')));

Generated MySQL output on main contains:

import (
    "context"
    "database/sql"
    "strings"

    "github.com/lib/pq"  // unused
)

Root cause

The two references to author_ids produce 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 adds lib/pq to the import set. The struct itself is rendered through UniqueFields so only one field is emitted, but the import-bookkeeping pass sees both fields.

Fix

In sliceScan(), first collect the names of all fields carrying IsSqlcSlice, 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 internal/endtoend/testdata/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.
  • gofmt -l clean, go vet clean on touched files.

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 in the same query, and pgx never went through the lib/pq branch anyway.
  • MySQL queries that use sqlc.slice alone, a plain []T argument, or a sqlc.narg without a matching sqlc.slice are unchanged.

…lc.slice (sqlc-dev#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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MySQL] Query: Named arg is null or in slice caused Postgres import

1 participant