Skip to content

Commit b707428

Browse files
author
awitas
committed
updated parser
1 parent 44272f4 commit b707428

17 files changed

Lines changed: 390 additions & 28 deletions

File tree

column/spec.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package column
2+
3+
type Spec struct {
4+
Name string
5+
Comments string
6+
Type string
7+
Nullable bool
8+
Default *string
9+
Key string
10+
IsAutoincrement bool
11+
}

delete.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func parseDelete(stmt *del.Statement, cursor *parsly.Cursor) error {
3939
}
4040

4141
func buildDeleteTarget(stmt *del.Statement, cursor *parsly.Cursor) (int, error) {
42-
matchable := []*parsly.Token{whereKeywordMatcher, joinToken, selectorMatcher}
42+
matchable := []*parsly.Token{whereKeywordMatcher, joinMatcher, selectorMatcher}
4343

4444
var targetData []string
4545
lastMatched := parsly.Invalid
@@ -59,7 +59,7 @@ func buildDeleteTarget(stmt *del.Statement, cursor *parsly.Cursor) (int, error)
5959
matchable = matchable[:len(matchable)-1]
6060
}
6161

62-
case joinTokenCode:
62+
case joinToken:
6363
join := query.NewJoin(matched.Text(cursor))
6464
if _, err := parseJoin(cursor, join); err != nil {
6565
return lastMatched, err

expr/binary.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,44 @@
11
package expr
22

3-
import "github.com/viant/sqlparser/node"
3+
import (
4+
"github.com/viant/sqlparser/node"
5+
)
46

57
type Binary struct {
68
X, Y node.Node
79
Op string
810
}
911

12+
//HasPlaceholder returns true if x or y operand is placeholder
13+
func (b *Binary) HasPlaceholder() bool {
14+
if _, ok := b.X.(*Placeholder); ok {
15+
return ok
16+
}
17+
_, ok := b.Y.(*Placeholder)
18+
return ok
19+
}
20+
21+
//Parenthesis returns parenthesis
22+
func (b *Binary) Parenthesis() *Parenthesis {
23+
if p, ok := b.X.(*Parenthesis); ok {
24+
return p
25+
}
26+
p, _ := b.Y.(*Parenthesis)
27+
return p
28+
}
29+
30+
//HasIdentity returns true if x or y opperand is identity
31+
func (b *Binary) HasIdentity() bool {
32+
return b.Identity() != nil
33+
}
34+
35+
func (b *Binary) Identity() node.Node {
36+
if x := Identity(b.X); x != nil {
37+
return x
38+
}
39+
return Identity(b.Y)
40+
}
41+
1042
func NewBinary(x node.Node) *Binary {
1143
return &Binary{X: x}
1244
}

expr/ident.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
package expr
22

3+
import "github.com/viant/sqlparser/node"
4+
35
type Ident struct {
46
Name string
57
}
8+
9+
//Identity returns ident or selector expr
10+
func Identity(node node.Node) node.Node {
11+
switch actual := node.(type) {
12+
case *Ident:
13+
return actual
14+
case *Selector:
15+
return actual
16+
}
17+
return nil
18+
}

expr/parent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ type Parenthesis struct {
44
Raw string
55
}
66

7-
func NewParenthesis(raww string) *Parenthesis {
8-
return &Parenthesis{Raw: raww}
7+
func NewParenthesis(raw string) *Parenthesis {
8+
return &Parenthesis{Raw: raw}
99
}

join.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func parseJoins(cursor *parsly.Cursor, join *query.Join, dest *query.Select) err
1414

1515
hasMatch, err := matchPostFrom(cursor, dest, match)
1616
if !hasMatch && err == nil {
17-
err = cursor.NewError(joinToken, joinToken, groupByMatcher, havingKeywordMatcher, whereKeywordMatcher, orderByKeywordMatcher, windowMatcher)
17+
err = cursor.NewError(joinMatcher, joinMatcher, groupByMatcher, havingKeywordMatcher, whereKeywordMatcher, orderByKeywordMatcher, windowMatcher)
1818
}
1919

2020
return err
@@ -47,13 +47,13 @@ func parseJoin(cursor *parsly.Cursor, join *query.Join) (*parsly.TokenMatch, err
4747
if err := parseBinaryExpr(cursor, binary); err != nil {
4848
return match, err
4949
}
50-
match = cursor.MatchAfterOptional(whitespaceMatcher, joinToken, groupByMatcher, havingKeywordMatcher, whereKeywordMatcher, orderByKeywordMatcher, windowMatcher)
50+
match = cursor.MatchAfterOptional(whitespaceMatcher, joinMatcher, groupByMatcher, havingKeywordMatcher, whereKeywordMatcher, orderByKeywordMatcher, windowMatcher)
5151
if match.Code == parsly.EOF {
5252
return match, nil
5353
}
5454
if match.Code == commentBlock {
5555
join.Comments = match.Text(cursor)
56-
match = cursor.MatchAfterOptional(whitespaceMatcher, joinToken, groupByMatcher, havingKeywordMatcher, whereKeywordMatcher, orderByKeywordMatcher, windowMatcher)
56+
match = cursor.MatchAfterOptional(whitespaceMatcher, joinMatcher, groupByMatcher, havingKeywordMatcher, whereKeywordMatcher, orderByKeywordMatcher, windowMatcher)
5757
if match.Code == parsly.EOF {
5858
return match, nil
5959
}

lex.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,20 @@ const (
4444
selectionKind
4545
fromKeyword
4646
onKeyword
47-
joinTokenCode
47+
joinToken
4848
whereKeyword
4949
groupByKeyword
5050
havingKeyword
5151
orderByKeyword
5252
rangeOperator
5353
windowTokenCode
5454
literalCode
55+
keyTokenCode
56+
notNullToken
57+
createTableToken
58+
defaultToken
59+
ifNotExistsToken
60+
dropTableToken
5561
deleteCode
5662
)
5763

@@ -77,13 +83,19 @@ var exceptKeywordMatcher = parsly.NewToken(exceptKeyword, "EXCEPT", matcher.NewF
7783
var betweenKeywordMatcher = parsly.NewToken(betweenToken, "BETWEEN", matcher.NewFragment("between", &option.Case{}))
7884

7985
var fromKeywordMatcher = parsly.NewToken(fromKeyword, "FROM", matcher.NewFragment("from", &option.Case{}))
80-
var joinToken = parsly.NewToken(joinTokenCode, "LEFT OUTER JOIN|LEFT JOIN|JOIN", matcher.NewSpacedSet([]string{
86+
var joinMatcher = parsly.NewToken(joinToken, "LEFT OUTER JOIN|LEFT JOIN|JOIN", matcher.NewSpacedSet([]string{
8187
"left outer join",
8288
"left join",
8389
"inner join",
8490
"join",
8591
}, &option.Case{}))
8692

93+
var keyMatcher = parsly.NewToken(keyTokenCode, "[RANGE|HASH|PRIMARY] KEY", matcher.NewSpacedSet([]string{
94+
"range key",
95+
"hash key",
96+
"primary key",
97+
}, &option.Case{}))
98+
8799
var onKeywordMatcher = parsly.NewToken(onKeyword, "ON", matcher.NewFragment("on", &option.Case{}))
88100

89101
var whereKeywordMatcher = parsly.NewToken(whereKeyword, "WHERE", matcher.NewFragment("where", &option.Case{}))
@@ -119,3 +131,15 @@ var selectorMatcher = parsly.NewToken(selectorTokenCode, "SELECTOR", smatcher.Ne
119131
var placeholderMatcher = parsly.NewToken(placeholderTokenCode, "SELECTOR", smatcher.NewPlaceholder())
120132
var literalMatcher = parsly.NewToken(literalCode, "LITERAL", matcher.NewNop())
121133
var deleteMatcher = parsly.NewToken(deleteCode, "DELETE", matcher.NewFragmentsFold([]byte("delete")))
134+
var notNullMatcher = parsly.NewToken(notNullToken, "NOT NULL", matcher.NewSpacedSet([]string{
135+
"not null"}, &option.Case{}))
136+
var ifNotExistsMatcher = parsly.NewToken(ifNotExistsToken, "IF NOT EXISTS", matcher.NewSpacedSet([]string{
137+
"if not exists"}, &option.Case{}))
138+
139+
var createTableMatcher = parsly.NewToken(createTableToken, "CREATE TABLE", matcher.NewSpacedSet([]string{
140+
"create table"}, &option.Case{}))
141+
142+
var defaultMatcher = parsly.NewToken(defaultToken, "DEFAULT", matcher.NewFragment("default", &option.Case{}))
143+
144+
var dropTableMatcher = parsly.NewToken(dropTableToken, "DROP TABLE", matcher.NewSpacedSet([]string{
145+
"drop table"}, &option.Case{}))

list.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
)
88

99
func parseSelectListItem(cursor *parsly.Cursor, list *query.List) error {
10-
1110
operand, err := expectOperand(cursor)
1211
if operand == nil {
1312
return err
@@ -49,6 +48,44 @@ func parseSelectListItem(cursor *parsly.Cursor, list *query.List) error {
4948
return nil
5049
}
5150

51+
func parseCallArgs(cursor *parsly.Cursor, list *query.List) error {
52+
53+
operand, err := expectOperand(cursor)
54+
if operand == nil {
55+
return err
56+
}
57+
item := query.NewItem(operand)
58+
if matched := cursor.MatchAfterOptional(whitespaceMatcher, orderDirectionMatcher); matched.Code == orderDirection {
59+
item.Direction = matched.Text(cursor)
60+
}
61+
list.Append(item)
62+
match := cursor.MatchAfterOptional(whitespaceMatcher, inlineCommentMatcher, commentBlockMatcher, binaryOperatorMatcher, logicalOperatorMatcher, nextMatcher)
63+
switch match.Code {
64+
case commentBlock:
65+
item.Comments = match.Text(cursor)
66+
match = cursor.MatchAfterOptional(whitespaceMatcher, nextMatcher)
67+
if match.Code == nextCode {
68+
return parseCallArgs(cursor, list)
69+
}
70+
case logicalOperator, binaryOperator:
71+
cursor.Pos -= match.Size
72+
binaryExpr := expr.NewBinary(item.Expr)
73+
item.Expr = binaryExpr
74+
if err := parseBinaryExpr(cursor, binaryExpr); err != nil {
75+
return err
76+
}
77+
item.Alias = discoverAlias(cursor)
78+
match = cursor.MatchAfterOptional(whitespaceMatcher, nextMatcher)
79+
if match.Code != nextCode {
80+
return nil
81+
}
82+
fallthrough
83+
case nextCode:
84+
return parseCallArgs(cursor, list)
85+
}
86+
return nil
87+
}
88+
5289
func parseOrderByListItem(cursor *parsly.Cursor, list *query.List) error {
5390

5491
operand, err := expectOperand(cursor)
@@ -86,3 +123,10 @@ func parseOrderByListItem(cursor *parsly.Cursor, list *query.List) error {
86123
}
87124
return nil
88125
}
126+
127+
//ParseList parses list
128+
func ParseList(raw string) (query.List, error) {
129+
cursor := parsly.NewCursor("", []byte(raw), 0)
130+
list := query.List{}
131+
return list, parseSelectListItem(cursor, &list)
132+
}

operand.go

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ import (
1010

1111
func discoverAlias(cursor *parsly.Cursor) string {
1212
pos := cursor.Pos
13-
match := cursor.MatchAfterOptional(whitespaceMatcher, exceptKeywordMatcher, asKeywordMatcher, onKeywordMatcher, fromKeywordMatcher, joinToken, whereKeywordMatcher, groupByMatcher, havingKeywordMatcher, orderByKeywordMatcher, windowMatcher, identifierMatcher)
13+
match := cursor.MatchAfterOptional(whitespaceMatcher, exceptKeywordMatcher, asKeywordMatcher, onKeywordMatcher, fromKeywordMatcher, joinMatcher, whereKeywordMatcher, groupByMatcher, havingKeywordMatcher, orderByKeywordMatcher, windowMatcher, identifierMatcher)
1414
switch match.Code {
1515
case asKeyword:
1616
match := cursor.MatchAfterOptional(whitespaceMatcher, identifierMatcher)
1717
return match.Text(cursor)
1818
case identifierCode:
1919
return match.Text(cursor)
20-
case exceptKeyword, fromKeyword, onKeyword, orderByKeyword, joinTokenCode, whereKeyword, groupByKeyword, havingKeyword, windowTokenCode:
20+
case exceptKeyword, fromKeyword, onKeyword, orderByKeyword, joinToken, whereKeyword, groupByKeyword, havingKeyword, windowTokenCode:
2121
cursor.Pos = pos
2222
}
2323
return ""
@@ -33,7 +33,7 @@ func expectOperand(cursor *parsly.Cursor) (node.Node, error) {
3333
orderByKeywordMatcher,
3434
asKeywordMatcher,
3535
exceptKeywordMatcher,
36-
onKeywordMatcher, fromKeywordMatcher, whereKeywordMatcher, joinToken, groupByMatcher, havingKeywordMatcher, windowMatcher, nextMatcher,
36+
onKeywordMatcher, fromKeywordMatcher, whereKeywordMatcher, joinMatcher, groupByMatcher, havingKeywordMatcher, windowMatcher, nextMatcher,
3737
parenthesesMatcher,
3838
caseBlockMatcher,
3939
starTokenMatcher,
@@ -59,16 +59,9 @@ func expectOperand(cursor *parsly.Cursor) (node.Node, error) {
5959
switch match.Code {
6060
case parenthesesCode:
6161
raw := match.Text(cursor)
62-
var args []node.Node
63-
if len(raw) > 0 {
64-
argCursor := parsly.NewCursor(cursor.Path, []byte(raw[1:len(raw)-1]), pos)
65-
list := query.List{}
66-
if err := parseOrderByListItem(argCursor, &list); err != nil {
67-
return nil, err
68-
}
69-
for i := range list {
70-
args = append(args, list[i].Expr)
71-
}
62+
args, err := parseCallArguments(cursor, raw, pos)
63+
if err != nil {
64+
return nil, err
7265
}
7366
return &expr.Call{X: selector, Raw: raw, Args: args}, nil
7467

@@ -113,12 +106,47 @@ func expectOperand(cursor *parsly.Cursor) (node.Node, error) {
113106
}
114107
return unary, nil
115108

116-
case asKeyword, orderByKeyword, onKeyword, fromKeyword, whereKeyword, joinTokenCode, groupByKeyword, havingKeyword, windowTokenCode, nextCode, commentBlock:
109+
case asKeyword, orderByKeyword, onKeyword, fromKeyword, whereKeyword, joinToken, groupByKeyword, havingKeyword, windowTokenCode, nextCode, commentBlock:
117110
cursor.Pos -= pos
118111
}
119112
return nil, nil
120113
}
121114

115+
func parseCallArguments(cursor *parsly.Cursor, raw string, pos int) ([]node.Node, error) {
116+
var args []node.Node
117+
if len(raw) > 0 {
118+
argCursor := parsly.NewCursor(cursor.Path, []byte(raw[1:len(raw)-1]), pos)
119+
list := query.List{}
120+
if err := parseCallArgs(argCursor, &list); err != nil {
121+
return nil, err
122+
}
123+
for i := range list {
124+
args = append(args, list[i].Expr)
125+
}
126+
}
127+
return args, nil
128+
}
129+
130+
func ParseCallExpr(rawExpr string) (*expr.Call, error) {
131+
cursor := parsly.NewCursor("", []byte(rawExpr), 0)
132+
match := cursor.MatchAfterOptional(whitespaceMatcher, selectorMatcher)
133+
if match.Code != selectorTokenCode {
134+
return nil, cursor.NewError(selectorMatcher)
135+
}
136+
selector := expr.NewSelector(match.Text(cursor))
137+
pos := cursor.Pos
138+
match = cursor.MatchAfterOptional(whitespaceMatcher, parenthesesMatcher)
139+
if match.Code != parenthesesCode {
140+
return nil, cursor.NewError(parenthesesMatcher)
141+
}
142+
raw := match.Text(cursor)
143+
args, err := parseCallArguments(cursor, raw, pos)
144+
if err != nil {
145+
return nil, err
146+
}
147+
return &expr.Call{X: selector, Raw: rawExpr, Args: args}, nil
148+
}
149+
122150
func parseStarExpr(cursor *parsly.Cursor, selRaw string, selector node.Node) (node.Node, error) {
123151
star := expr.NewStar(selector, "")
124152
if !strings.HasSuffix(selRaw, "*") {

query.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ func parseQuery(cursor *parsly.Cursor, dest *query.Select) error {
6565

6666
dest.Joins = make([]*query.Join, 0)
6767

68-
match = cursor.MatchAfterOptional(whitespaceMatcher, joinToken, whereKeywordMatcher, groupByMatcher, havingKeywordMatcher, orderByKeywordMatcher, windowMatcher)
68+
match = cursor.MatchAfterOptional(whitespaceMatcher, joinMatcher, whereKeywordMatcher, groupByMatcher, havingKeywordMatcher, orderByKeywordMatcher, windowMatcher)
6969
if match.Code == parsly.EOF {
7070
return nil
7171
}
7272
hasMatch, err := matchPostFrom(cursor, dest, match)
7373
if !hasMatch && err == nil {
74-
err = cursor.NewError(joinToken, whereKeywordMatcher, groupByMatcher, havingKeywordMatcher, orderByKeywordMatcher, windowMatcher)
74+
err = cursor.NewError(joinMatcher, whereKeywordMatcher, groupByMatcher, havingKeywordMatcher, orderByKeywordMatcher, windowMatcher)
7575
}
7676
if err != nil {
7777
return err
@@ -92,7 +92,7 @@ func matchComment(cursor *parsly.Cursor) string {
9292

9393
func matchPostFrom(cursor *parsly.Cursor, dest *query.Select, match *parsly.TokenMatch) (bool, error) {
9494
switch match.Code {
95-
case joinTokenCode:
95+
case joinToken:
9696
if err := appendJoin(cursor, match, dest); err != nil {
9797
return false, err
9898
}

0 commit comments

Comments
 (0)