Skip to content

Commit 11d7a62

Browse files
committed
sql: Add generic SQL AST
The three new experimental parsers turn engine-specific ASTs into a generic AST shared by the type-checking and code-gen phases.
1 parent 0a7599e commit 11d7a62

File tree

3 files changed

+285
-0
lines changed

3 files changed

+285
-0
lines changed

internal/sql/ast/ast.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package ast
2+
3+
type Node interface {
4+
Pos() int
5+
}
6+
7+
type Statement struct {
8+
Raw *RawStmt
9+
}
10+
11+
type RawStmt struct {
12+
Stmt Node
13+
}
14+
15+
func (n *RawStmt) Pos() int {
16+
return 0
17+
}
18+
19+
type TableName struct {
20+
Catalog string
21+
Schema string
22+
Name string
23+
}
24+
25+
func (n *TableName) Pos() int {
26+
return 0
27+
}
28+
29+
type CreateTableStmt struct {
30+
IfNotExists bool
31+
Name *TableName
32+
Cols []*ColumnDef
33+
}
34+
35+
func (n *CreateTableStmt) Pos() int {
36+
return 0
37+
}
38+
39+
type DropTableStmt struct {
40+
IfExists bool
41+
Tables []*TableName
42+
}
43+
44+
func (n *DropTableStmt) Pos() int {
45+
return 0
46+
}
47+
48+
type ColumnDef struct {
49+
Colname string
50+
TypeName *TypeName
51+
}
52+
53+
func (n *ColumnDef) Pos() int {
54+
return 0
55+
}
56+
57+
type TypeName struct {
58+
Name string
59+
}
60+
61+
func (n *TypeName) Pos() int {
62+
return 0
63+
}
64+
65+
type SelectStmt struct {
66+
Fields *List
67+
From *List
68+
}
69+
70+
func (n *SelectStmt) Pos() int {
71+
return 0
72+
}
73+
74+
type List struct {
75+
Items []Node
76+
}
77+
78+
func (n *List) Pos() int {
79+
return 0
80+
}
81+
82+
type ResTarget struct {
83+
Val Node
84+
}
85+
86+
func (n *ResTarget) Pos() int {
87+
return 0
88+
}
89+
90+
type ColumnRef struct {
91+
Name string
92+
}
93+
94+
func (n *ColumnRef) Pos() int {
95+
return 0
96+
}

internal/sql/catalog/catalog.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package catalog
2+
3+
import (
4+
"errors"
5+
6+
"github.com/kyleconroy/sqlc/internal/sql/ast"
7+
)
8+
9+
func Build(stmts []ast.Statement) (*Catalog, error) {
10+
c := &Catalog{
11+
DefaultSchema: "main", // TODO: Needs to be public for PostgreSQL
12+
Schemas: []*Schema{
13+
&Schema{Name: "main"},
14+
},
15+
}
16+
for i := range stmts {
17+
if stmts[i].Raw == nil {
18+
continue
19+
}
20+
var err error
21+
switch n := stmts[i].Raw.Stmt.(type) {
22+
case *ast.CreateTableStmt:
23+
err = c.createTable(n)
24+
case *ast.DropTableStmt:
25+
err = c.dropTable(n)
26+
}
27+
if err != nil {
28+
return nil, err
29+
}
30+
}
31+
return c, nil
32+
}
33+
34+
var ErrRelationNotFound = errors.New("relation not found")
35+
var ErrSchemaNotFound = errors.New("schema not found")
36+
37+
func (c *Catalog) getSchema(name string) (*Schema, error) {
38+
for i := range c.Schemas {
39+
if c.Schemas[i].Name == name {
40+
return c.Schemas[i], nil
41+
}
42+
}
43+
return nil, ErrSchemaNotFound
44+
}
45+
46+
func (c *Catalog) createTable(stmt *ast.CreateTableStmt) error {
47+
ns := stmt.Name.Schema
48+
if ns == "" {
49+
ns = c.DefaultSchema
50+
}
51+
schema, err := c.getSchema(ns)
52+
if err != nil {
53+
return err
54+
}
55+
if _, _, err := schema.getTable(stmt.Name); err != nil {
56+
if !errors.Is(err, ErrRelationNotFound) {
57+
return err
58+
}
59+
} else if stmt.IfNotExists {
60+
return nil
61+
}
62+
tbl := Table{Rel: stmt.Name}
63+
for _, col := range stmt.Cols {
64+
tbl.Columns = append(tbl.Columns, &Column{
65+
Name: col.Colname,
66+
Type: *col.TypeName,
67+
})
68+
}
69+
schema.Tables = append(schema.Tables, &tbl)
70+
return nil
71+
}
72+
73+
func (c *Catalog) dropTable(stmt *ast.DropTableStmt) error {
74+
for _, name := range stmt.Tables {
75+
ns := name.Schema
76+
if ns == "" {
77+
ns = c.DefaultSchema
78+
}
79+
schema, err := c.getSchema(ns)
80+
if errors.Is(err, ErrSchemaNotFound) && stmt.IfExists {
81+
continue
82+
} else if err != nil {
83+
return err
84+
}
85+
86+
_, idx, err := schema.getTable(name)
87+
if errors.Is(err, ErrRelationNotFound) && stmt.IfExists {
88+
continue
89+
} else if err != nil {
90+
return err
91+
}
92+
93+
schema.Tables = append(schema.Tables[:idx], schema.Tables[idx+1:]...)
94+
}
95+
return nil
96+
}
97+
98+
type Catalog struct {
99+
Name string
100+
Schemas []*Schema
101+
Comment string
102+
103+
DefaultSchema string
104+
}
105+
106+
type Schema struct {
107+
Name string
108+
Tables []*Table
109+
Comment string
110+
}
111+
112+
func (s *Schema) getTable(rel *ast.TableName) (*Table, int, error) {
113+
for i := range s.Tables {
114+
if s.Tables[i].Rel.Name == rel.Name {
115+
return s.Tables[i], i, nil
116+
}
117+
}
118+
return nil, 0, ErrRelationNotFound
119+
}
120+
121+
type Table struct {
122+
Rel *ast.TableName
123+
Columns []*Column
124+
Comment string
125+
}
126+
127+
type Column struct {
128+
Name string
129+
Type ast.TypeName
130+
}

internal/sql/info/info.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package info
2+
3+
import (
4+
"github.com/kyleconroy/sqlc/internal/sql/catalog"
5+
)
6+
7+
// Provide a read-only view into the catalog
8+
func Newo(c *catalog.Catalog) InformationSchema {
9+
return InformationSchema{c: c}
10+
}
11+
12+
type InformationSchema struct {
13+
c *catalog.Catalog
14+
}
15+
16+
type Table struct {
17+
Catalog string
18+
Schema string
19+
Name string
20+
}
21+
22+
// SELECT * FROM information_schema.tables;
23+
func (i *InformationSchema) Tables() []Table {
24+
var tables []Table
25+
for _, s := range i.c.Schemas {
26+
for _, t := range s.Tables {
27+
tables = append(tables, Table{
28+
Catalog: i.c.Name,
29+
Schema: s.Name,
30+
Name: t.Rel.Name,
31+
})
32+
}
33+
}
34+
return tables
35+
}
36+
37+
type Column struct {
38+
Catalog string
39+
Schema string
40+
Table string
41+
Name string
42+
DataType string
43+
IsNullable bool
44+
}
45+
46+
// SELECT * FROM information_schema.columns;
47+
func (i *InformationSchema) Columns() []Column {
48+
return []Column{}
49+
}
50+
51+
type Schema struct {
52+
Catalog string
53+
Name string
54+
}
55+
56+
// SELECT * FROM information_schema.schemata;
57+
func (i *InformationSchema) Schemata() []Schema {
58+
return []Schema{}
59+
}

0 commit comments

Comments
 (0)