-
Notifications
You must be signed in to change notification settings - Fork 1k
Expand file tree
/
Copy pathcompile.go
More file actions
125 lines (120 loc) · 3.03 KB
/
compile.go
File metadata and controls
125 lines (120 loc) · 3.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package compiler
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/sqlc-dev/sqlc/internal/migrations"
"github.com/sqlc-dev/sqlc/internal/multierr"
"github.com/sqlc-dev/sqlc/internal/opts"
"github.com/sqlc-dev/sqlc/internal/rpc"
"github.com/sqlc-dev/sqlc/internal/source"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
"github.com/sqlc-dev/sqlc/internal/sql/sqlerr"
"github.com/sqlc-dev/sqlc/internal/sql/sqlpath"
)
// TODO: Rename this interface Engine
type Parser interface {
Parse(io.Reader) ([]ast.Statement, error)
CommentSyntax() source.CommentSyntax
IsReservedKeyword(string) bool
}
func (c *Compiler) parseCatalog(schemas []string) error {
files, err := sqlpath.Glob(schemas)
if err != nil {
return err
}
merr := multierr.New()
for _, filename := range files {
blob, err := os.ReadFile(filename)
if err != nil {
merr.Add(filename, "", 0, err)
continue
}
contents := migrations.RemoveRollbackStatements(string(blob))
contents, err = migrations.TransformStatements(filepath.Dir(filename), contents)
if err != nil {
merr.Add(filename, contents, 0, err)
continue
}
c.schema = append(c.schema, contents)
stmts, err := c.parser.Parse(strings.NewReader(contents))
if err != nil {
merr.Add(filename, contents, 0, err)
continue
}
for i := range stmts {
if err := c.catalog.Update(stmts[i], c); err != nil {
merr.Add(filename, contents, stmts[i].Pos(), err)
continue
}
}
}
if len(merr.Errs()) > 0 {
return merr
}
return nil
}
func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) {
var q []*Query
merr := multierr.New()
set := map[string]struct{}{}
files, err := sqlpath.Glob(c.conf.Queries)
if err != nil {
return nil, err
}
for _, filename := range files {
blob, err := os.ReadFile(filename)
if err != nil {
merr.Add(filename, "", 0, err)
continue
}
src := string(blob)
stmts, err := c.parser.Parse(strings.NewReader(src))
if err != nil {
merr.Add(filename, src, 0, err)
continue
}
for _, stmt := range stmts {
query, err := c.parseQuery(stmt.Raw, src, o)
if err != nil {
var e *sqlerr.Error
loc := stmt.Raw.Pos()
if errors.As(err, &e) && e.Location != 0 {
loc = e.Location
}
merr.Add(filename, src, loc, err)
// If this rpc unauthenticated error bubbles up, then all future parsing/analysis will fail
if errors.Is(err, rpc.ErrUnauthenticated) {
return nil, merr
}
continue
}
if query == nil {
continue
}
query.Metadata.Filename = filepath.Base(filename)
queryName := query.Metadata.Name
if queryName != "" {
if _, exists := set[queryName]; exists {
merr.Add(filename, src, stmt.Raw.Pos(), fmt.Errorf("duplicate query name: %s", queryName))
continue
}
set[queryName] = struct{}{}
}
q = append(q, query)
}
}
if len(merr.Errs()) > 0 {
return nil, merr
}
if len(q) == 0 {
return nil, fmt.Errorf("no queries contained in paths %s", strings.Join(c.conf.Queries, ","))
}
return &Result{
Catalog: c.catalog,
Queries: q,
}, nil
}