Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Commit ef19c5f

Browse files
Parse and analyze database-scoped names for views
Signed-off-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
1 parent 34a9f58 commit ef19c5f

File tree

3 files changed

+93
-7
lines changed

3 files changed

+93
-7
lines changed

sql/parse/util.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,27 @@ func readLetter(r *bufio.Reader, buf *bytes.Buffer) error {
127127
return nil
128128
}
129129

130+
func readLetterOrPoint(r *bufio.Reader, buf *bytes.Buffer) error {
131+
ru, _, err := r.ReadRune()
132+
if err != nil {
133+
if err == io.EOF {
134+
return nil
135+
}
136+
137+
return err
138+
}
139+
140+
if !unicode.IsLetter(ru) && ru != '.' {
141+
if err := r.UnreadRune(); err != nil {
142+
return err
143+
}
144+
return nil
145+
}
146+
147+
buf.WriteRune(ru)
148+
return nil
149+
}
150+
130151
func readValidIdentRune(r *bufio.Reader, buf *bytes.Buffer) error {
131152
ru, _, err := r.ReadRune()
132153
if err != nil {
@@ -144,6 +165,23 @@ func readValidIdentRune(r *bufio.Reader, buf *bytes.Buffer) error {
144165
return nil
145166
}
146167

168+
func readValidScopedIdentRune(r *bufio.Reader, separator rune, buf *bytes.Buffer) error {
169+
ru, _, err := r.ReadRune()
170+
if err != nil {
171+
return err
172+
}
173+
174+
if !unicode.IsLetter(ru) && !unicode.IsDigit(ru) && ru != '_' && ru != separator {
175+
if err := r.UnreadRune(); err != nil {
176+
return err
177+
}
178+
return io.EOF
179+
}
180+
181+
buf.WriteRune(ru)
182+
return nil
183+
}
184+
147185
func readValidQuotedIdentRune(r *bufio.Reader, buf *bytes.Buffer) error {
148186
bs, err := r.Peek(2)
149187
if err != nil {
@@ -199,6 +237,29 @@ func readIdent(ident *string) parseFunc {
199237
}
200238
}
201239

240+
func readScopedIdent(separator rune, idents *[]string) parseFunc {
241+
return func(r *bufio.Reader) error {
242+
var buf bytes.Buffer
243+
if err := readLetter(r, &buf); err != nil {
244+
return err
245+
}
246+
247+
for {
248+
if err := readValidScopedIdentRune(r, separator, &buf); err == io.EOF {
249+
break
250+
} else if err != nil {
251+
return err
252+
}
253+
}
254+
255+
*idents = append(
256+
*idents,
257+
strings.Split(strings.ToLower(buf.String()), string(separator))...,
258+
)
259+
return nil
260+
}
261+
}
262+
202263
func readQuotedIdent(ident *string) parseFunc {
203264
return func(r *bufio.Reader) error {
204265
var buf bytes.Buffer

sql/parse/views.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,21 @@ import (
1111
"vitess.io/vitess/go/vt/sqlparser"
1212
)
1313

14+
var ErrMalformedViewName = errors.NewKind("the view name '%s' is not correct")
1415
var ErrMalformedCreateView = errors.NewKind("view definition %#v is not a SELECT query")
1516

1617
// Parses
17-
// CREATE [OR REPLACE] VIEW view_name [(col1, col2, ...)] AS select_statement
18+
// CREATE [OR REPLACE] VIEW [db_name.]view_name [(col1, col2, ...)] AS select_statement
1819
// and returns a NewCreateView node in case of success
1920
func parseCreateView(ctx *sql.Context, s string) (sql.Node, error) {
2021
r := bufio.NewReader(strings.NewReader(s))
2122

2223
var (
23-
viewName, subquery string
24-
columns []string
25-
isReplace bool
24+
databaseName, viewName string
25+
scopedName []string
26+
subquery string
27+
columns []string
28+
isReplace bool
2629
)
2730

2831
err := parseFuncs{
@@ -32,7 +35,7 @@ func parseCreateView(ctx *sql.Context, s string) (sql.Node, error) {
3235
skipSpaces,
3336
expect("view"),
3437
skipSpaces,
35-
readIdent(&viewName),
38+
readScopedIdent('.', &scopedName),
3639
skipSpaces,
3740
maybeList('(', ',', ')', &columns),
3841
skipSpaces,
@@ -46,6 +49,18 @@ func parseCreateView(ctx *sql.Context, s string) (sql.Node, error) {
4649
return nil, err
4750
}
4851

52+
if len(scopedName) < 1 || len(scopedName) > 2 {
53+
return nil, ErrMalformedViewName.New(strings.Join(scopedName, "."))
54+
}
55+
56+
if len(scopedName) == 1 {
57+
viewName = scopedName[0]
58+
}
59+
if len(scopedName) == 2 {
60+
databaseName = scopedName[0]
61+
viewName = scopedName[1]
62+
}
63+
4964
subqueryStatement, err := sqlparser.Parse(subquery)
5065
if err != nil {
5166
return nil, err
@@ -64,6 +79,6 @@ func parseCreateView(ctx *sql.Context, s string) (sql.Node, error) {
6479
subqueryAlias := plan.NewSubqueryAlias(viewName, subqueryNode)
6580

6681
return plan.NewCreateView(
67-
sql.UnresolvedDatabase(""), viewName, columns, subqueryAlias,
82+
sql.UnresolvedDatabase(databaseName), viewName, columns, subqueryAlias,
6883
), nil
6984
}

sql/plan/create_view.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type CreateView struct {
1212
database sql.Database
1313
Name string
1414
Columns []string
15-
Catalog *sql.Catalog
15+
Catalog *sql.Catalog
1616
}
1717

1818
func NewCreateView(
@@ -71,3 +71,13 @@ func (create *CreateView) WithChildren(children ...sql.Node) (sql.Node, error) {
7171
newCreate.Child = children[0]
7272
return newCreate, nil
7373
}
74+
75+
func (create *CreateView) Database() sql.Database {
76+
return create.database
77+
}
78+
79+
func (create *CreateView) WithDatabase(database sql.Database) (sql.Node, error) {
80+
newCreate := *create
81+
newCreate.database = database
82+
return &newCreate, nil
83+
}

0 commit comments

Comments
 (0)