Skip to content

Commit e433a4d

Browse files
authored
Implement SELECT for simple SQLite queries (#360)
* Lemon select * sqlite: Translate select stmts * endtoend: Use a single SQL file for experimental
1 parent 7657fb7 commit e433a4d

File tree

10 files changed

+507
-80
lines changed

10 files changed

+507
-80
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE TABLE foo (
2+
bar text NOT NULL
3+
);
4+
5+
CREATE TABLE bar (
6+
baz text NOT NULL
7+
);
8+
9+
SELECT bar FROM foo;
10+
11+
DROP TABLE bar;
12+
DROP TABLE IF EXISTS baz;

internal/endtoend/testdata/experimental_dolphin/query.sql

Lines changed: 0 additions & 8 deletions
This file was deleted.

internal/endtoend/testdata/experimental_dolphin/sqlc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"path": "go",
66
"name": "querytest",
77
"engine": "_dolphin",
8-
"schema": "query.sql",
9-
"queries": "query.sql"
8+
"schema": "../experimental.sql",
9+
"queries": "../experimental.sql"
1010
}
1111
]
1212
}

internal/endtoend/testdata/experimental_elephant/query.sql

Lines changed: 0 additions & 8 deletions
This file was deleted.

internal/endtoend/testdata/experimental_elephant/sqlc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"path": "go",
66
"name": "querytest",
77
"engine": "_elephant",
8-
"schema": "query.sql",
9-
"queries": "query.sql"
8+
"schema": "../experimental.sql",
9+
"queries": "../experimental.sql"
1010
}
1111
]
1212
}

internal/endtoend/testdata/experimental_lemon/query.sql

Lines changed: 0 additions & 8 deletions
This file was deleted.

internal/endtoend/testdata/experimental_lemon/sqlc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"path": "go",
66
"name": "querytest",
77
"engine": "_lemon",
8-
"schema": "query.sql",
9-
"queries": "query.sql"
8+
"schema": "../experimental.sql",
9+
"queries": "../experimental.sql"
1010
}
1111
]
1212
}

internal/sqlite/listener.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package sqlite
2+
3+
import (
4+
"github.com/kyleconroy/sqlc/internal/sql/ast"
5+
"github.com/kyleconroy/sqlc/internal/sqlite/parser"
6+
)
7+
8+
type listener struct {
9+
*parser.BaseSQLiteListener
10+
11+
stmt *ast.RawStmt
12+
13+
stmts []ast.Statement
14+
}
15+
16+
// The Visitor code generated by Antlr doesn't currently work
17+
//
18+
// To make due, we mark the listener as "busy" if it's currently processing a
19+
// node. This helps avoids scenarios where enter is called on nested
20+
// statements.
21+
func (l *listener) busy() bool {
22+
return l.stmt != nil
23+
}
24+
25+
func (l *listener) EnterSql_stmt(c *parser.Sql_stmtContext) {
26+
l.stmt = nil
27+
}
28+
29+
func (l *listener) ExitSql_stmt(c *parser.Sql_stmtContext) {
30+
if l.stmt != nil {
31+
l.stmts = append(l.stmts, ast.Statement{
32+
Raw: l.stmt,
33+
})
34+
}
35+
}
36+
37+
func (l *listener) EnterCreate_table_stmt(c *parser.Create_table_stmtContext) {
38+
if l.busy() {
39+
return
40+
}
41+
42+
name := ast.TableName{
43+
Name: c.Table_name().GetText(),
44+
}
45+
46+
if c.Database_name() != nil {
47+
name.Schema = c.Database_name().GetText()
48+
}
49+
50+
stmt := &ast.CreateTableStmt{
51+
Name: &name,
52+
IfNotExists: c.K_EXISTS() != nil,
53+
}
54+
55+
for _, idef := range c.AllColumn_def() {
56+
if def, ok := idef.(*parser.Column_defContext); ok {
57+
stmt.Cols = append(stmt.Cols, &ast.ColumnDef{
58+
Colname: def.Column_name().GetText(),
59+
TypeName: &ast.TypeName{
60+
Name: def.Type_name().GetText(),
61+
},
62+
})
63+
}
64+
}
65+
66+
l.stmt = &ast.RawStmt{Stmt: stmt}
67+
}
68+
69+
func (l *listener) EnterDrop_table_stmt(c *parser.Drop_table_stmtContext) {
70+
if l.busy() {
71+
return
72+
}
73+
74+
drop := &ast.DropTableStmt{
75+
IfExists: c.K_EXISTS() != nil,
76+
}
77+
78+
name := ast.TableName{
79+
Name: c.Table_name().GetText(),
80+
}
81+
82+
if c.Database_name() != nil {
83+
name.Schema = c.Database_name().GetText()
84+
}
85+
86+
drop.Tables = append(drop.Tables, &name)
87+
l.stmt = &ast.RawStmt{Stmt: drop}
88+
}
89+
90+
func (l *listener) EnterFactored_select_stmt(c *parser.Factored_select_stmtContext) {
91+
if l.busy() {
92+
return
93+
}
94+
95+
var tables []ast.Node
96+
var cols []ast.Node
97+
for _, icore := range c.AllSelect_core() {
98+
core, ok := icore.(*parser.Select_coreContext)
99+
if !ok {
100+
continue
101+
}
102+
for _, icol := range core.AllResult_column() {
103+
col, ok := icol.(*parser.Result_columnContext)
104+
if !ok {
105+
continue
106+
}
107+
iexpr := col.Expr()
108+
if iexpr == nil {
109+
continue
110+
}
111+
expr, ok := iexpr.(*parser.ExprContext)
112+
if !ok {
113+
continue
114+
}
115+
cols = append(cols, &ast.ResTarget{
116+
Val: &ast.ColumnRef{
117+
Name: expr.Column_name().GetText(),
118+
},
119+
})
120+
}
121+
for _, ifrom := range core.AllTable_or_subquery() {
122+
from, ok := ifrom.(*parser.Table_or_subqueryContext)
123+
if !ok {
124+
continue
125+
}
126+
name := ast.TableName{
127+
Name: from.Table_name().GetText(),
128+
}
129+
if from.Schema_name() != nil {
130+
name.Schema = from.Schema_name().GetText()
131+
}
132+
tables = append(tables, &name)
133+
}
134+
}
135+
136+
sel := &ast.SelectStmt{
137+
From: &ast.List{Items: tables},
138+
Fields: &ast.List{Items: cols},
139+
}
140+
l.stmt = &ast.RawStmt{Stmt: sel}
141+
}

internal/sqlite/parse.go

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,55 +11,6 @@ import (
1111
"github.com/kyleconroy/sqlc/internal/sqlite/parser"
1212
)
1313

14-
type listener struct {
15-
*parser.BaseSQLiteListener
16-
17-
stmt *ast.RawStmt
18-
19-
stmts []ast.Statement
20-
}
21-
22-
func (l *listener) EnterSql_stmt(c *parser.Sql_stmtContext) {
23-
l.stmt = nil
24-
}
25-
26-
func (l *listener) ExitSql_stmt(c *parser.Sql_stmtContext) {
27-
if l.stmt != nil {
28-
l.stmts = append(l.stmts, ast.Statement{
29-
Raw: l.stmt,
30-
})
31-
return
32-
}
33-
}
34-
35-
func (l *listener) EnterCreate_table_stmt(c *parser.Create_table_stmtContext) {
36-
name := ast.TableName{
37-
Name: c.Table_name().GetText(),
38-
}
39-
40-
if c.Database_name() != nil {
41-
name.Schema = c.Database_name().GetText()
42-
}
43-
44-
stmt := &ast.CreateTableStmt{
45-
Name: &name,
46-
IfNotExists: c.K_EXISTS() != nil,
47-
}
48-
49-
for _, idef := range c.AllColumn_def() {
50-
if def, ok := idef.(*parser.Column_defContext); ok {
51-
stmt.Cols = append(stmt.Cols, &ast.ColumnDef{
52-
Colname: def.Column_name().GetText(),
53-
TypeName: &ast.TypeName{
54-
Name: def.Type_name().GetText(),
55-
},
56-
})
57-
}
58-
}
59-
60-
l.stmt = &ast.RawStmt{Stmt: stmt}
61-
}
62-
6314
type errorListener struct {
6415
*antlr.DefaultErrorListener
6516

@@ -98,11 +49,11 @@ func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) {
9849
l := &listener{}
9950
el := &errorListener{}
10051
pp.AddErrorListener(el)
52+
// pp.BuildParseTrees = true
10153
tree := pp.Parse()
10254
if el.err != "" {
10355
return nil, errors.New(el.err)
10456
}
105-
// p.BuildParseTrees = true
10657
antlr.ParseTreeWalkerDefault.Walk(l, tree)
10758
return l.stmts, nil
10859
}

0 commit comments

Comments
 (0)