Repository navigation
Expand file tree
/
Copy pathbinary.go
More file actions
128 lines (125 loc) · 3.87 KB
/
Copy pathbinary.go
File metadata and controls
128 lines (125 loc) · 3.87 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
126
127
128
package sqlparser
import (
"github.com/viant/parsly"
"github.com/viant/parsly/matcher"
"github.com/viant/sqlparser/expr"
"strings"
)
func parseBinaryExpr(cursor *parsly.Cursor, binary *expr.Binary) (err error) {
defer func() {
if err == nil && binary != nil && binary.Op != "" {
// Every operator needs complete operands, including at clause and
// alias boundaries where expectOperand can return nil without error.
if !completeExpression(binary) {
err = cursor.NewError(exprMatcher)
return
}
*binary = *binary.Normalize()
}
}()
if binary.X == nil {
binary.X, err = expectOperand(cursor)
if err != nil || binary.X == nil {
return err
}
}
//fmt.Printf("After op %v,: %s\n", binary.Op, cursor.Input[cursor.Pos:])
skipExpressionSpace(cursor)
pos := cursor.Pos
if binary.Op == "" {
match := cursor.MatchAfterOptional(whitespaceMatcher, betweenKeywordMatcher, notLikeOperatorMatcher, notGlobOperatorMatcher, globOperatorMatcher, binaryOperatorMatcher, logicalOperatorMatcher, placeholderMatcher)
switch match.Code {
case notLikeOperator:
// Keep precedence independent of comments or whitespace between words.
binary.Op = "NOT LIKE"
case globOperator:
binary.Op = "GLOB"
case notGlobOperator:
binary.Op = "NOT GLOB"
case logicalOperator:
if cursor.Pos < len(cursor.Input) && !matcher.IsWhiteSpace(cursor.Input[cursor.Pos]) {
cursor.Pos = pos
return nil
}
binary.Op = match.Text(cursor)
case binaryOperator:
binary.Op = match.Text(cursor)
case betweenToken:
binary.Op = match.Text(cursor)
rng := &expr.Range{}
if rng.Min, err = expectOperand(cursor); err != nil {
return err
}
match := cursor.MatchAfterOptional(whitespaceMatcher, rangeOperatorMatcher)
if match.Code != rangeOperator {
return cursor.NewError(rangeOperatorMatcher)
}
if rng.Max, err = expectOperand(cursor); err != nil {
return err
}
yExpr := &expr.Binary{X: rng}
if err := parseBinaryExpr(cursor, yExpr); err != nil {
return err
}
if yExpr.Y == nil {
binary.Y = rng
} else {
binary.Y = yExpr
}
return nil
case placeholderTokenCode:
binary.Op = ""
if binary.X == nil {
binary.X = &expr.Placeholder{Name: match.Text(cursor)}
} else {
placeholder := &expr.Placeholder{Name: match.Text(cursor)}
binary.Y = placeholder
prevPos := cursor.Pos
match = cursor.MatchAfterOptional(whitespaceMatcher, parenthesesMatcher, groupByMatcher, havingKeywordMatcher, qualifyKeywordMatcher, orderByKeywordMatcher, windowMatcher, unionMatcher, logicalOperatorMatcher)
switch match.Code {
case logicalOperator:
additionalExpr := &expr.Binary{X: binary.Y, Op: match.Text(cursor)}
if err := parseBinaryExpr(cursor, additionalExpr); err != nil {
return err
}
binary.Y = additionalExpr
case parenthesesCode:
placeholder.Name += match.Text(cursor)
case groupByKeyword, havingKeyword, qualifyKeyword, orderByKeyword, windowTokenCode, unionKeyword:
cursor.Pos = prevPos
return nil
case parsly.Invalid:
binary.Y = nil
cursor.Pos = pos
return nil
}
}
default:
return nil
}
}
if binary.Y == nil {
yExpr := &expr.Binary{}
// SQLite permits an empty IN set. Keep it as source syntax; its
// truth value and dialect validity belong to the database.
if strings.EqualFold(binary.Op, "IN") || strings.EqualFold(binary.Op, "NOT IN") {
start := cursor.Pos
match := cursor.MatchAfterOptional(whitespaceMatcher, parenthesesMatcher)
if match.Code == parenthesesCode && strings.TrimSpace(match.Text(cursor)[1:match.Size-1]) == "" {
yExpr.X = expr.NewParenthesis(match.Text(cursor))
} else {
cursor.Pos = start
}
}
if err := parseBinaryExpr(cursor, yExpr); err != nil {
return err
}
if yExpr.X != nil {
binary.Y = yExpr
}
if yExpr.Op == "" && yExpr.Y == nil {
binary.Y = yExpr.X
}
}
return nil
}