Skip to content

Commit

Permalink
feat(compiler): Support subqueries in the FROM clause
Browse files Browse the repository at this point in the history
issue sqlc-dev#2989, sqlc-dev#2400 and probably others
  • Loading branch information
Jille committed Apr 4, 2024
1 parent 811b6b0 commit 5dcdd2f
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 4 deletions.
49 changes: 45 additions & 4 deletions internal/compiler/query_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,36 @@ import (
)

type QueryCatalog struct {
catalog *catalog.Catalog
ctes map[string]*Table
embeds rewrite.EmbedSet
catalog *catalog.Catalog
ctes map[string]*Table
fromClauses map[string]*Table
embeds rewrite.EmbedSet
}

func (comp *Compiler) buildQueryCatalog(c *catalog.Catalog, node ast.Node, embeds rewrite.EmbedSet) (*QueryCatalog, error) {
var with *ast.WithClause
var from *ast.List
switch n := node.(type) {
case *ast.DeleteStmt:
with = n.WithClause
case *ast.InsertStmt:
with = n.WithClause
case *ast.UpdateStmt:
with = n.WithClause
from = n.FromClause
case *ast.SelectStmt:
with = n.WithClause
from = n.FromClause
default:
with = nil
from = nil
}
qc := &QueryCatalog{
catalog: c,
ctes: map[string]*Table{},
fromClauses: map[string]*Table{},
embeds: embeds,
}
qc := &QueryCatalog{catalog: c, ctes: map[string]*Table{}, embeds: embeds}
if with != nil {
for _, item := range with.Ctes.Items {
if cte, ok := item.(*ast.CommonTableExpr); ok {
Expand Down Expand Up @@ -60,6 +70,37 @@ func (comp *Compiler) buildQueryCatalog(c *catalog.Catalog, node ast.Node, embed
}
}
}
if from != nil {
for _, item := range from.Items {
if rs, ok := item.(*ast.RangeSubselect); ok {
cols, err := comp.outputColumns(qc, rs.Subquery)
if err != nil {
return nil, err
}
var names []string
if rs.Alias.Colnames != nil {
for _, item := range rs.Alias.Colnames.Items {
if val, ok := item.(*ast.String); ok {
names = append(names, val.Str)
} else {
names = append(names, "")
}
}
}
rel := &ast.TableName{Name: *rs.Alias.Aliasname}
for i := range cols {
cols[i].Table = rel
if len(names) > i {
cols[i].Name = names[i]
}
}
qc.fromClauses[*rs.Alias.Aliasname] = &Table{
Rel: rel,
Columns: cols,
}
}
}
}
return qc, nil
}

Expand Down
22 changes: 22 additions & 0 deletions internal/compiler/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,28 @@ func (comp *Compiler) resolveCatalogRefs(qc *QueryCatalog, rvs []*ast.RangeVar,
aliasMap[*rv.Alias.Aliasname] = fqn
}
}
for _, f := range qc.fromClauses {
catCols := make([]*catalog.Column, 0, len(f.Columns))
for _, col := range f.Columns {
catCols = append(catCols, &catalog.Column{
Name: col.Name,
Type: ast.TypeName{Name: col.DataType},
IsNotNull: col.NotNull,
IsUnsigned: col.Unsigned,
IsArray: col.IsArray,
ArrayDims: col.ArrayDims,
Comment: col.Comment,
Length: col.Length,
})
}

if err := indexTable(catalog.Table{
Rel: f.Rel,
Columns: catCols,
}); err != nil {
return nil, err
}
}

// resolve a table for an embed
for _, embed := range embeds {
Expand Down
54 changes: 54 additions & 0 deletions internal/endtoend/testdata/join_alias/mysql/go/query.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions internal/endtoend/testdata/join_alias/mysql/query.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ SELECT *
FROM foo f
JOIN bar b ON b.id = f.id
WHERE f.id = ?;

-- name: SubqueryAlias :many
SELECT * FROM (SELECT 1 AS n) AS x WHERE x.n <= ?;

-- name: ColumnAlias :many
SELECT * FROM (SELECT 1 AS n) AS x WHERE n <= ?;

0 comments on commit 5dcdd2f

Please sign in to comment.