From 2d7b302a85a2da586681dadd514f836360be4ec5 Mon Sep 17 00:00:00 2001 From: Will Roden Date: Wed, 26 Nov 2025 14:46:51 -0600 Subject: [PATCH 1/3] LATERAL subquery support --- internal/compiler/output_columns.go | 28 +++++++- internal/compiler/query_catalog.go | 2 + .../testdata/lateral_view_column_ref/issue.md | 3 + .../postgresql/pgx/go/db.go | 32 +++++++++ .../postgresql/pgx/go/models.go | 15 ++++ .../postgresql/pgx/go/query.sql.go | 68 +++++++++++++++++++ .../postgresql/pgx/query.sql | 9 +++ .../postgresql/pgx/schema.sql | 13 ++++ .../postgresql/pgx/sqlc.yaml | 10 +++ 9 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/issue.md create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.yaml diff --git a/internal/compiler/output_columns.go b/internal/compiler/output_columns.go index b0a15e6ac4..0122f0d695 100644 --- a/internal/compiler/output_columns.go +++ b/internal/compiler/output_columns.go @@ -592,7 +592,24 @@ func (c *Compiler) sourceTables(qc *QueryCatalog, node ast.Node) ([]*Table, erro tables = append(tables, table) case *ast.RangeSubselect: - cols, err := c.outputColumns(qc, n.Subquery) + lateralQC := qc + if n.Lateral && len(tables) > 0 { + // LATERAL allows the subquery to reference columns from preceding FROM items. + lateralTables := make(map[string]*Table, len(tables)) + for _, table := range tables { + if table.Rel != nil && table.Rel.Name != "" { + lateralTables[table.Rel.Name] = table + } + } + lateralQC = &QueryCatalog{ + catalog: qc.catalog, + ctes: qc.ctes, + embeds: qc.embeds, + lateralTables: lateralTables, + } + } + + cols, err := c.outputColumns(lateralQC, n.Subquery) if err != nil { return nil, err } @@ -637,6 +654,15 @@ func (c *Compiler) sourceTables(qc *QueryCatalog, node ast.Node) ([]*Table, erro return nil, fmt.Errorf("sourceTable: unsupported list item type: %T", n) } } + + // Add LATERAL outer tables to the tables list. + // LATERAL subqueries can reference these outer tables for column resolution. + if qc != nil { + for _, lateralTable := range qc.lateralTables { + tables = append(tables, lateralTable) + } + } + return tables, nil } diff --git a/internal/compiler/query_catalog.go b/internal/compiler/query_catalog.go index 80b59d876c..a65cb53031 100644 --- a/internal/compiler/query_catalog.go +++ b/internal/compiler/query_catalog.go @@ -12,6 +12,8 @@ type QueryCatalog struct { catalog *catalog.Catalog ctes map[string]*Table embeds rewrite.EmbedSet + + lateralTables map[string]*Table } func (comp *Compiler) buildQueryCatalog(c *catalog.Catalog, node ast.Node, embeds rewrite.EmbedSet) (*QueryCatalog, error) { diff --git a/internal/endtoend/testdata/lateral_view_column_ref/issue.md b/internal/endtoend/testdata/lateral_view_column_ref/issue.md new file mode 100644 index 0000000000..7fa8efd9ca --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/issue.md @@ -0,0 +1,3 @@ +https://github.com/sqlc-dev/sqlc/issues/4182 + +LATERAL subquery column references from outer query fail with "column does not exist". diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/db.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/db.go new file mode 100644 index 0000000000..1e00549714 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/models.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/models.go new file mode 100644 index 0000000000..beb91f9393 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package querytest + +type Foo struct { + ID int32 + Val string +} + +type FooLateral struct { + Val string + Result string +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000000..8e7ecd37d2 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/query.sql.go @@ -0,0 +1,68 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getFooLateral = `-- name: GetFooLateral :many +SELECT val, result FROM foo_lateral +` + +func (q *Queries) GetFooLateral(ctx context.Context) ([]FooLateral, error) { + rows, err := q.db.Query(ctx, getFooLateral) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FooLateral + for rows.Next() { + var i FooLateral + if err := rows.Scan(&i.Val, &i.Result); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getFooLateralDirect = `-- name: GetFooLateralDirect :many +SELECT f.id, f.val, sub.result +FROM foo f +CROSS JOIN LATERAL ( + SELECT f.val || '-direct' AS result +) sub +` + +type GetFooLateralDirectRow struct { + ID int32 + Val string + Result interface{} +} + +func (q *Queries) GetFooLateralDirect(ctx context.Context) ([]GetFooLateralDirectRow, error) { + rows, err := q.db.Query(ctx, getFooLateralDirect) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetFooLateralDirectRow + for rows.Next() { + var i GetFooLateralDirectRow + if err := rows.Scan(&i.ID, &i.Val, &i.Result); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/query.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/query.sql new file mode 100644 index 0000000000..d0b8b5f1d8 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/query.sql @@ -0,0 +1,9 @@ +-- name: GetFooLateral :many +SELECT val, result FROM foo_lateral; + +-- name: GetFooLateralDirect :many +SELECT f.id, f.val, sub.result +FROM foo f +CROSS JOIN LATERAL ( + SELECT f.val || '-direct' AS result +) sub; diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/schema.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/schema.sql new file mode 100644 index 0000000000..edb1da22d7 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/schema.sql @@ -0,0 +1,13 @@ +CREATE TABLE foo ( + id integer PRIMARY KEY, + val text NOT NULL +); + +-- Reproduces issue #4182: LATERAL subquery referencing outer column +CREATE VIEW foo_lateral AS +SELECT t.val, sub.result +FROM foo t +CROSS JOIN LATERAL ( + SELECT t.val AS result + FROM foo LIMIT 1 +) sub; diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.yaml new file mode 100644 index 0000000000..5dc63e3f91 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" + schema: "schema.sql" + queries: "query.sql" + gen: + go: + package: "querytest" + out: "go" + sql_package: "pgx/v5" From 7666ff1925e45568419fde20eb665e95f4f09ad1 Mon Sep 17 00:00:00 2001 From: Will Roden Date: Thu, 27 Nov 2025 13:07:59 -0600 Subject: [PATCH 2/3] fix test --- .../postgresql/pgx/sqlc.yaml | 10 --- .../postgresql/pgx/v4/go/db.go | 32 ++++++++ .../postgresql/pgx/{ => v4}/go/models.go | 2 +- .../postgresql/pgx/{ => v4}/go/query.sql.go | 6 +- .../postgresql/pgx/{ => v4}/query.sql | 2 +- .../postgresql/pgx/{ => v4}/schema.sql | 2 +- .../postgresql/pgx/v4/sqlc.json | 17 +++++ .../postgresql/pgx/{ => v5}/go/db.go | 2 +- .../postgresql/pgx/v5/go/models.go | 15 ++++ .../postgresql/pgx/v5/go/query.sql.go | 68 +++++++++++++++++ .../postgresql/pgx/v5/query.sql | 9 +++ .../postgresql/pgx/v5/schema.sql | 13 ++++ .../postgresql/pgx/v5/sqlc.json | 17 +++++ .../postgresql/stdlib/go/db.go | 31 ++++++++ .../postgresql/stdlib/go/models.go | 15 ++++ .../postgresql/stdlib/go/query.sql.go | 74 +++++++++++++++++++ .../postgresql/stdlib/query.sql | 9 +++ .../postgresql/stdlib/schema.sql | 13 ++++ .../postgresql/stdlib/sqlc.json | 16 ++++ 19 files changed, 336 insertions(+), 17 deletions(-) delete mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.yaml create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/db.go rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{ => v4}/go/models.go (90%) rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{ => v4}/go/query.sql.go (94%) rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{ => v4}/query.sql (78%) rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{ => v4}/schema.sql (88%) create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/sqlc.json rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{ => v5}/go/db.go (96%) create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/sqlc.json diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.yaml deleted file mode 100644 index 5dc63e3f91..0000000000 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.yaml +++ /dev/null @@ -1,10 +0,0 @@ -version: "2" -sql: - - engine: "postgresql" - schema: "schema.sql" - queries: "query.sql" - gen: - go: - package: "querytest" - out: "go" - sql_package: "pgx/v5" diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000000..100b164409 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package db + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/models.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/models.go similarity index 90% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/models.go rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/models.go index beb91f9393..df8c88fcdc 100644 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/models.go +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/models.go @@ -2,7 +2,7 @@ // versions: // sqlc v1.30.0 -package querytest +package db type Foo struct { ID int32 diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/query.sql.go similarity index 94% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/query.sql.go rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/query.sql.go index 8e7ecd37d2..794aa4e6a3 100644 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/query.sql.go +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/query.sql.go @@ -3,7 +3,7 @@ // sqlc v1.30.0 // source: query.sql -package querytest +package db import ( "context" @@ -37,14 +37,14 @@ const getFooLateralDirect = `-- name: GetFooLateralDirect :many SELECT f.id, f.val, sub.result FROM foo f CROSS JOIN LATERAL ( - SELECT f.val || '-direct' AS result + SELECT (f.val || '-direct')::text AS result ) sub ` type GetFooLateralDirectRow struct { ID int32 Val string - Result interface{} + Result string } func (q *Queries) GetFooLateralDirect(ctx context.Context) ([]GetFooLateralDirectRow, error) { diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/query.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/query.sql similarity index 78% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/query.sql rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/query.sql index d0b8b5f1d8..12d747d2a2 100644 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/query.sql +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/query.sql @@ -5,5 +5,5 @@ SELECT val, result FROM foo_lateral; SELECT f.id, f.val, sub.result FROM foo f CROSS JOIN LATERAL ( - SELECT f.val || '-direct' AS result + SELECT (f.val || '-direct')::text AS result ) sub; diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/schema.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/schema.sql similarity index 88% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/schema.sql rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/schema.sql index edb1da22d7..623ec64347 100644 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/schema.sql +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/schema.sql @@ -8,6 +8,6 @@ CREATE VIEW foo_lateral AS SELECT t.val, sub.result FROM foo t CROSS JOIN LATERAL ( - SELECT t.val AS result + SELECT t.val::text AS result FROM foo LIMIT 1 ) sub; diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000000..fc06da0bf9 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,17 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "db", + "out": "go", + "sql_package": "pgx/v4" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/db.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/db.go similarity index 96% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/db.go rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/db.go index 1e00549714..9d485b5f16 100644 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/db.go +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/db.go @@ -2,7 +2,7 @@ // versions: // sqlc v1.30.0 -package querytest +package db import ( "context" diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000000..df8c88fcdc --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package db + +type Foo struct { + ID int32 + Val string +} + +type FooLateral struct { + Val string + Result string +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000000..794aa4e6a3 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,68 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: query.sql + +package db + +import ( + "context" +) + +const getFooLateral = `-- name: GetFooLateral :many +SELECT val, result FROM foo_lateral +` + +func (q *Queries) GetFooLateral(ctx context.Context) ([]FooLateral, error) { + rows, err := q.db.Query(ctx, getFooLateral) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FooLateral + for rows.Next() { + var i FooLateral + if err := rows.Scan(&i.Val, &i.Result); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getFooLateralDirect = `-- name: GetFooLateralDirect :many +SELECT f.id, f.val, sub.result +FROM foo f +CROSS JOIN LATERAL ( + SELECT (f.val || '-direct')::text AS result +) sub +` + +type GetFooLateralDirectRow struct { + ID int32 + Val string + Result string +} + +func (q *Queries) GetFooLateralDirect(ctx context.Context) ([]GetFooLateralDirectRow, error) { + rows, err := q.db.Query(ctx, getFooLateralDirect) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetFooLateralDirectRow + for rows.Next() { + var i GetFooLateralDirectRow + if err := rows.Scan(&i.ID, &i.Val, &i.Result); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000000..12d747d2a2 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/query.sql @@ -0,0 +1,9 @@ +-- name: GetFooLateral :many +SELECT val, result FROM foo_lateral; + +-- name: GetFooLateralDirect :many +SELECT f.id, f.val, sub.result +FROM foo f +CROSS JOIN LATERAL ( + SELECT (f.val || '-direct')::text AS result +) sub; diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000000..623ec64347 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/schema.sql @@ -0,0 +1,13 @@ +CREATE TABLE foo ( + id integer PRIMARY KEY, + val text NOT NULL +); + +-- Reproduces issue #4182: LATERAL subquery referencing outer column +CREATE VIEW foo_lateral AS +SELECT t.val, sub.result +FROM foo t +CROSS JOIN LATERAL ( + SELECT t.val::text AS result + FROM foo LIMIT 1 +) sub; diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000000..9fca5b5230 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,17 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "db", + "out": "go", + "sql_package": "pgx/v5" + } + } + } + ] +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/db.go new file mode 100644 index 0000000000..cd5bbb8e08 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *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/lateral_view_column_ref/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/models.go new file mode 100644 index 0000000000..df8c88fcdc --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package db + +type Foo struct { + ID int32 + Val string +} + +type FooLateral struct { + Val string + Result string +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000000..6bc53d78a4 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,74 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: query.sql + +package db + +import ( + "context" +) + +const getFooLateral = `-- name: GetFooLateral :many +SELECT val, result FROM foo_lateral +` + +func (q *Queries) GetFooLateral(ctx context.Context) ([]FooLateral, error) { + rows, err := q.db.QueryContext(ctx, getFooLateral) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FooLateral + for rows.Next() { + var i FooLateral + if err := rows.Scan(&i.Val, &i.Result); 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 +} + +const getFooLateralDirect = `-- name: GetFooLateralDirect :many +SELECT f.id, f.val, sub.result +FROM foo f +CROSS JOIN LATERAL ( + SELECT (f.val || '-direct')::text AS result +) sub +` + +type GetFooLateralDirectRow struct { + ID int32 + Val string + Result string +} + +func (q *Queries) GetFooLateralDirect(ctx context.Context) ([]GetFooLateralDirectRow, error) { + rows, err := q.db.QueryContext(ctx, getFooLateralDirect) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetFooLateralDirectRow + for rows.Next() { + var i GetFooLateralDirectRow + if err := rows.Scan(&i.ID, &i.Val, &i.Result); 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 +} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/query.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/query.sql new file mode 100644 index 0000000000..12d747d2a2 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/query.sql @@ -0,0 +1,9 @@ +-- name: GetFooLateral :many +SELECT val, result FROM foo_lateral; + +-- name: GetFooLateralDirect :many +SELECT f.id, f.val, sub.result +FROM foo f +CROSS JOIN LATERAL ( + SELECT (f.val || '-direct')::text AS result +) sub; diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/schema.sql new file mode 100644 index 0000000000..623ec64347 --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/schema.sql @@ -0,0 +1,13 @@ +CREATE TABLE foo ( + id integer PRIMARY KEY, + val text NOT NULL +); + +-- Reproduces issue #4182: LATERAL subquery referencing outer column +CREATE VIEW foo_lateral AS +SELECT t.val, sub.result +FROM foo t +CROSS JOIN LATERAL ( + SELECT t.val::text AS result + FROM foo LIMIT 1 +) sub; diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000000..480d68e40e --- /dev/null +++ b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/stdlib/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "2", + "sql": [ + { + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "gen": { + "go": { + "package": "db", + "out": "go" + } + } + } + ] +} From b1d6767856fd18befc2bff6747daf37263752f05 Mon Sep 17 00:00:00 2001 From: Will Roden Date: Fri, 28 Nov 2025 11:19:33 -0600 Subject: [PATCH 3/3] move test --- .../postgresql/pgx/{v5 => }/go/db.go | 0 .../postgresql/pgx/{v4 => }/go/models.go | 0 .../postgresql/pgx/{v4 => }/go/query.sql.go | 0 .../postgresql/pgx/{v4 => }/query.sql | 0 .../postgresql/pgx/{v4 => }/schema.sql | 0 .../postgresql/pgx/{v5 => }/sqlc.json | 0 .../postgresql/pgx/v4/go/db.go | 32 --------- .../postgresql/pgx/v4/sqlc.json | 17 ----- .../postgresql/pgx/v5/go/models.go | 15 ---- .../postgresql/pgx/v5/go/query.sql.go | 68 ------------------- .../postgresql/pgx/v5/query.sql | 9 --- .../postgresql/pgx/v5/schema.sql | 13 ---- 12 files changed, 154 deletions(-) rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{v5 => }/go/db.go (100%) rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{v4 => }/go/models.go (100%) rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{v4 => }/go/query.sql.go (100%) rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{v4 => }/query.sql (100%) rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{v4 => }/schema.sql (100%) rename internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/{v5 => }/sqlc.json (100%) delete mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/db.go delete mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/sqlc.json delete mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/models.go delete mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/query.sql.go delete mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/query.sql delete mode 100644 internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/schema.sql diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/db.go similarity index 100% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/db.go rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/db.go diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/models.go similarity index 100% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/models.go rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/models.go diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/query.sql.go similarity index 100% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/query.sql.go rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/go/query.sql.go diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/query.sql similarity index 100% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/query.sql rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/query.sql diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/schema.sql similarity index 100% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/schema.sql rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/schema.sql diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.json similarity index 100% rename from internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/sqlc.json rename to internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/sqlc.json diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/db.go deleted file mode 100644 index 100b164409..0000000000 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/go/db.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.30.0 - -package db - -import ( - "context" - - "github.com/jackc/pgconn" - "github.com/jackc/pgx/v4" -) - -type DBTX interface { - Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) - Query(context.Context, string, ...interface{}) (pgx.Rows, error) - QueryRow(context.Context, string, ...interface{}) pgx.Row -} - -func New(db DBTX) *Queries { - return &Queries{db: db} -} - -type Queries struct { - db DBTX -} - -func (q *Queries) WithTx(tx pgx.Tx) *Queries { - return &Queries{ - db: tx, - } -} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/sqlc.json deleted file mode 100644 index fc06da0bf9..0000000000 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v4/sqlc.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "version": "2", - "sql": [ - { - "engine": "postgresql", - "schema": "schema.sql", - "queries": "query.sql", - "gen": { - "go": { - "package": "db", - "out": "go", - "sql_package": "pgx/v4" - } - } - } - ] -} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/models.go deleted file mode 100644 index df8c88fcdc..0000000000 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/models.go +++ /dev/null @@ -1,15 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.30.0 - -package db - -type Foo struct { - ID int32 - Val string -} - -type FooLateral struct { - Val string - Result string -} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/query.sql.go deleted file mode 100644 index 794aa4e6a3..0000000000 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/go/query.sql.go +++ /dev/null @@ -1,68 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.30.0 -// source: query.sql - -package db - -import ( - "context" -) - -const getFooLateral = `-- name: GetFooLateral :many -SELECT val, result FROM foo_lateral -` - -func (q *Queries) GetFooLateral(ctx context.Context) ([]FooLateral, error) { - rows, err := q.db.Query(ctx, getFooLateral) - if err != nil { - return nil, err - } - defer rows.Close() - var items []FooLateral - for rows.Next() { - var i FooLateral - if err := rows.Scan(&i.Val, &i.Result); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const getFooLateralDirect = `-- name: GetFooLateralDirect :many -SELECT f.id, f.val, sub.result -FROM foo f -CROSS JOIN LATERAL ( - SELECT (f.val || '-direct')::text AS result -) sub -` - -type GetFooLateralDirectRow struct { - ID int32 - Val string - Result string -} - -func (q *Queries) GetFooLateralDirect(ctx context.Context) ([]GetFooLateralDirectRow, error) { - rows, err := q.db.Query(ctx, getFooLateralDirect) - if err != nil { - return nil, err - } - defer rows.Close() - var items []GetFooLateralDirectRow - for rows.Next() { - var i GetFooLateralDirectRow - if err := rows.Scan(&i.ID, &i.Val, &i.Result); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/query.sql deleted file mode 100644 index 12d747d2a2..0000000000 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/query.sql +++ /dev/null @@ -1,9 +0,0 @@ --- name: GetFooLateral :many -SELECT val, result FROM foo_lateral; - --- name: GetFooLateralDirect :many -SELECT f.id, f.val, sub.result -FROM foo f -CROSS JOIN LATERAL ( - SELECT (f.val || '-direct')::text AS result -) sub; diff --git a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/schema.sql deleted file mode 100644 index 623ec64347..0000000000 --- a/internal/endtoend/testdata/lateral_view_column_ref/postgresql/pgx/v5/schema.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE foo ( - id integer PRIMARY KEY, - val text NOT NULL -); - --- Reproduces issue #4182: LATERAL subquery referencing outer column -CREATE VIEW foo_lateral AS -SELECT t.val, sub.result -FROM foo t -CROSS JOIN LATERAL ( - SELECT t.val::text AS result - FROM foo LIMIT 1 -) sub;