From 44862ae9ab3efa39b8442d1ee52aa27a8029c03e Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Oct 2026 15:19:51 +0000 Subject: [PATCH] Respect the engine selector on global Go type overrides Global overrides are shared by every SQL package, but the Go codegen applied all of them regardless of their engine field, so a multi-engine config got the first matching go_type and last matching struct tag in every package. Drop global overrides scoped to a different engine before parsing them. Fixes #4624 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EbVEZseeSLEVPCsmiPymrg --- internal/codegen/golang/opts/options.go | 12 ++++- .../overrides_global_engine/mysql/db.go | 31 +++++++++++ .../overrides_global_engine/mysql/models.go | 15 ++++++ .../mysql/query.sql.go | 28 ++++++++++ .../testdata/overrides_global_engine/pg/db.go | 31 +++++++++++ .../overrides_global_engine/pg/models.go | 15 ++++++ .../overrides_global_engine/pg/query.sql.go | 28 ++++++++++ .../overrides_global_engine/query.sql | 3 ++ .../overrides_global_engine/schema.sql | 5 ++ .../overrides_global_engine/sqlc.yaml | 53 +++++++++++++++++++ .../overrides_global_engine/sqlite/db.go | 31 +++++++++++ .../overrides_global_engine/sqlite/models.go | 11 ++++ .../sqlite/query.sql.go | 27 ++++++++++ 13 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 internal/endtoend/testdata/overrides_global_engine/mysql/db.go create mode 100644 internal/endtoend/testdata/overrides_global_engine/mysql/models.go create mode 100644 internal/endtoend/testdata/overrides_global_engine/mysql/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_global_engine/pg/db.go create mode 100644 internal/endtoend/testdata/overrides_global_engine/pg/models.go create mode 100644 internal/endtoend/testdata/overrides_global_engine/pg/query.sql.go create mode 100644 internal/endtoend/testdata/overrides_global_engine/query.sql create mode 100644 internal/endtoend/testdata/overrides_global_engine/schema.sql create mode 100644 internal/endtoend/testdata/overrides_global_engine/sqlc.yaml create mode 100644 internal/endtoend/testdata/overrides_global_engine/sqlite/db.go create mode 100644 internal/endtoend/testdata/overrides_global_engine/sqlite/models.go create mode 100644 internal/endtoend/testdata/overrides_global_engine/sqlite/query.sql.go diff --git a/internal/codegen/golang/opts/options.go b/internal/codegen/golang/opts/options.go index 646bf1e066..64ceb13796 100644 --- a/internal/codegen/golang/opts/options.go +++ b/internal/codegen/golang/opts/options.go @@ -153,11 +153,19 @@ func parseGlobalOpts(req *plugin.GenerateRequest) (*GlobalOptions, error) { if err := json.Unmarshal(req.GlobalOptions, &options); err != nil { return nil, fmt.Errorf("unmarshalling global options: %w", err) } - for i := range options.Overrides { - if err := options.Overrides[i].parse(req); err != nil { + // Global overrides are shared by every SQL package, so drop the ones + // scoped to a different engine + overrides := options.Overrides[:0] + for _, o := range options.Overrides { + if o.Engine != "" && o.Engine != req.Settings.GetEngine() { + continue + } + if err := o.parse(req); err != nil { return nil, err } + overrides = append(overrides, o) } + options.Overrides = overrides return &options, nil } diff --git a/internal/endtoend/testdata/overrides_global_engine/mysql/db.go b/internal/endtoend/testdata/overrides_global_engine/mysql/db.go new file mode 100644 index 0000000000..8d745411c0 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/mysql/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package mysql + +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, + } +} diff --git a/internal/endtoend/testdata/overrides_global_engine/mysql/models.go b/internal/endtoend/testdata/overrides_global_engine/mysql/models.go new file mode 100644 index 0000000000..eb70e855b8 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/mysql/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package mysql + +import ( + "database/sql" +) + +type Entry struct { + ID int32 + Value sql.NullString `backend:"mysql"` + Code []byte `backend:"mysql"` +} diff --git a/internal/endtoend/testdata/overrides_global_engine/mysql/query.sql.go b/internal/endtoend/testdata/overrides_global_engine/mysql/query.sql.go new file mode 100644 index 0000000000..8325e7d1fe --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/mysql/query.sql.go @@ -0,0 +1,28 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package mysql + +import ( + "context" + "database/sql" +) + +const findEntry = `-- name: FindEntry :one +SELECT id, value, code FROM entries +WHERE value = ? AND code = ? +` + +type FindEntryParams struct { + Value sql.NullString `backend:"mysql"` + Code []byte `backend:"mysql"` +} + +func (q *Queries) FindEntry(ctx context.Context, arg FindEntryParams) (Entry, error) { + row := q.db.QueryRowContext(ctx, findEntry, arg.Value, arg.Code) + var i Entry + err := row.Scan(&i.ID, &i.Value, &i.Code) + return i, err +} diff --git a/internal/endtoend/testdata/overrides_global_engine/pg/db.go b/internal/endtoend/testdata/overrides_global_engine/pg/db.go new file mode 100644 index 0000000000..6614d155e5 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/pg/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package pg + +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, + } +} diff --git a/internal/endtoend/testdata/overrides_global_engine/pg/models.go b/internal/endtoend/testdata/overrides_global_engine/pg/models.go new file mode 100644 index 0000000000..d543e260e0 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/pg/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package pg + +import ( + "encoding/json" +) + +type Entry struct { + ID int32 + Value string `backend:"postgresql"` + Code json.RawMessage `backend:"postgresql"` +} diff --git a/internal/endtoend/testdata/overrides_global_engine/pg/query.sql.go b/internal/endtoend/testdata/overrides_global_engine/pg/query.sql.go new file mode 100644 index 0000000000..b186bff3e3 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/pg/query.sql.go @@ -0,0 +1,28 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package pg + +import ( + "context" + "encoding/json" +) + +const findEntry = `-- name: FindEntry :one +SELECT id, value, code FROM entries +WHERE value = $1 AND code = $2 +` + +type FindEntryParams struct { + Value string `backend:"postgresql"` + Code json.RawMessage `backend:"postgresql"` +} + +func (q *Queries) FindEntry(ctx context.Context, arg FindEntryParams) (Entry, error) { + row := q.db.QueryRowContext(ctx, findEntry, arg.Value, arg.Code) + var i Entry + err := row.Scan(&i.ID, &i.Value, &i.Code) + return i, err +} diff --git a/internal/endtoend/testdata/overrides_global_engine/query.sql b/internal/endtoend/testdata/overrides_global_engine/query.sql new file mode 100644 index 0000000000..09e6a55fc5 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/query.sql @@ -0,0 +1,3 @@ +-- name: FindEntry :one +SELECT id, value, code FROM entries +WHERE value = sqlc.arg(value) AND code = sqlc.arg(code); diff --git a/internal/endtoend/testdata/overrides_global_engine/schema.sql b/internal/endtoend/testdata/overrides_global_engine/schema.sql new file mode 100644 index 0000000000..3d66f2ec20 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE entries ( + id integer NOT NULL, + value text NOT NULL, + code text NOT NULL +); diff --git a/internal/endtoend/testdata/overrides_global_engine/sqlc.yaml b/internal/endtoend/testdata/overrides_global_engine/sqlc.yaml new file mode 100644 index 0000000000..0be9e6e949 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/sqlc.yaml @@ -0,0 +1,53 @@ +version: "2" +overrides: + go: + overrides: + - db_type: text + engine: postgresql + go_type: string + go_struct_tag: 'backend:"postgresql"' + - db_type: text + engine: mysql + go_type: "database/sql.NullString" + go_struct_tag: 'backend:"mysql"' + - db_type: text + engine: sqlite + go_type: + type: byte + slice: true + go_struct_tag: 'backend:"sqlite"' + - column: entries.code + engine: postgresql + go_type: + import: encoding/json + type: RawMessage + - column: entries.code + engine: mysql + go_type: + type: byte + slice: true + - column: entries.code + engine: sqlite + go_type: string +sql: + - engine: postgresql + schema: schema.sql + queries: query.sql + gen: + go: + package: pg + out: pg + - engine: mysql + schema: schema.sql + queries: query.sql + gen: + go: + package: mysql + out: mysql + - engine: sqlite + schema: schema.sql + queries: query.sql + gen: + go: + package: sqlite + out: sqlite diff --git a/internal/endtoend/testdata/overrides_global_engine/sqlite/db.go b/internal/endtoend/testdata/overrides_global_engine/sqlite/db.go new file mode 100644 index 0000000000..be3742276e --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/sqlite/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package sqlite + +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, + } +} diff --git a/internal/endtoend/testdata/overrides_global_engine/sqlite/models.go b/internal/endtoend/testdata/overrides_global_engine/sqlite/models.go new file mode 100644 index 0000000000..031862d729 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/sqlite/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 + +package sqlite + +type Entry struct { + ID int64 + Value []byte `backend:"sqlite"` + Code string `backend:"sqlite"` +} diff --git a/internal/endtoend/testdata/overrides_global_engine/sqlite/query.sql.go b/internal/endtoend/testdata/overrides_global_engine/sqlite/query.sql.go new file mode 100644 index 0000000000..fb70006c88 --- /dev/null +++ b/internal/endtoend/testdata/overrides_global_engine/sqlite/query.sql.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: query.sql + +package sqlite + +import ( + "context" +) + +const findEntry = `-- name: FindEntry :one +SELECT id, value, code FROM entries +WHERE value = ?1 AND code = ?2 +` + +type FindEntryParams struct { + Value []byte `backend:"sqlite"` + Code string `backend:"sqlite"` +} + +func (q *Queries) FindEntry(ctx context.Context, arg FindEntryParams) (Entry, error) { + row := q.db.QueryRowContext(ctx, findEntry, arg.Value, arg.Code) + var i Entry + err := row.Scan(&i.ID, &i.Value, &i.Code) + return i, err +}