-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathselection_kind.go
More file actions
67 lines (61 loc) · 2.21 KB
/
Copy pathselection_kind.go
File metadata and controls
67 lines (61 loc) · 2.21 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
package sqlparser
import (
"strings"
"github.com/viant/parsly"
)
// Keep the complete SELECT modifier in Kind so native AST rendering preserves
// both DISTINCT/ALL and BigQuery's AS STRUCT projection mode.
func parseSelectKind(cursor *parsly.Cursor) (kind string, asStruct bool, err error) {
skipExpressionSpace(cursor)
if match := cursor.MatchOne(selectionKindMatcher); match.Code == selectionKindCode {
kind = match.Text(cursor)
}
skipExpressionSpace(cursor)
pos := cursor.Pos
match := cursor.MatchOne(selectAsKeywordMatcher)
if match.Code != asKeyword {
cursor.Pos = pos
return kind, false, nil
}
as := match.Text(cursor)
skipExpressionSpace(cursor)
match = cursor.MatchOne(selectStructKeywordMatcher)
if match.Code != selectionKindCode || strings.EqualFold(kind, "STRUCT") {
return "", false, cursor.NewError(exprMatcher)
}
if kind != "" {
kind += " "
}
kind += as + " " + match.Text(cursor)
skipExpressionSpace(cursor)
return kind, true, nil
}
// selectionModifier shares the native selector boundary, so ordinary names
// such as all_records and distinct_column are not consumed as modifiers.
type selectionModifier struct {
keywords parsly.Matcher
selector parsly.Matcher
excludeStructCall bool
}
func (m selectionModifier) Match(cursor *parsly.Cursor) int {
matched := m.keywords.Match(cursor)
if matched != 0 && m.selector.Match(cursor) > matched && !startsSQLComment(cursor.Input, cursor.Pos+matched) {
return 0
}
// STRUCT(...) is an expression, including at the start of a projection
// or argument list. The explicit AS STRUCT matcher still accepts it as
// a query modifier followed by a parenthesized projection.
if m.excludeStructCall && matched > 0 && strings.EqualFold(string(cursor.Input[cursor.Pos:cursor.Pos+matched]), "STRUCT") {
lookahead := *cursor
lookahead.Pos += matched
skipExpressionSpace(&lookahead)
if lookahead.Pos < len(lookahead.Input) && lookahead.Input[lookahead.Pos] == '(' {
return 0
}
}
return matched
}
// Comments separate SQL tokens even when no whitespace surrounds them.
func startsSQLComment(input []byte, pos int) bool {
return pos+1 < len(input) && (input[pos] == '/' && input[pos+1] == '*' || input[pos] == '-' && input[pos+1] == '-')
}