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
|
package mapr
import (
"strings"
)
var keywords = [...]string{"select", "from", "where", "set", "group", "rorder",
"order", "interval", "limit", "outfile", "logformat"}
// Represents a parsed token, used to parse the mapr query.
type token struct {
str string
isBareword bool
quotesStripped bool
}
func (t token) isKeyword() bool {
if !t.isBareword {
return false
}
for _, keyword := range keywords {
if strings.ToLower(t.str) == keyword {
return true
}
}
return false
}
func (t token) String() string {
return t.str
}
func tokenize(queryStr string) []token {
var tokens []token
for i, part := range strings.Split(queryStr, "\"") {
// Even i, means that it is not a quoted string
if i%2 == 0 {
commasStripped := strings.Replace(part, ",", " ", -1)
for _, tokenStr := range strings.Fields(commasStripped) {
token := token{
str: tokenStr,
isBareword: true,
}
tokens = append(tokens, token)
}
continue
}
// Add whole quoted string as a token
token := token{
str: part,
isBareword: false,
}
tokens = append(tokens, token)
}
return tokens
}
func tokensConsume(tokens []token) ([]token, []token) {
//dlog.Common.Trace("=====================")
var consumed []token
for i, t := range tokens {
if t.isKeyword() {
//dlog.Common.Trace("keyword", t)
return tokens[i:], consumed
}
// strip escapes, such as ` from `foo`, this allows to use keywords as field names
length := len(t.str)
if length == 0 {
continue
}
if t.str[0] == '`' && t.str[length-1] == '`' {
stripped := t.str[1 : length-1]
//dlog.Common.Trace("stripped", stripped)
t := token{
str: stripped,
isBareword: t.isBareword,
quotesStripped: true,
}
consumed = append(consumed, t)
continue
}
//dlog.Common.Trace("bare", token)
consumed = append(consumed, t)
}
//dlog.Common.Trace("result", consumed)
return nil, consumed
}
func tokensConsumeStr(tokens []token) ([]token, []string) {
var strings []string
tokens, found := tokensConsume(tokens)
for _, token := range found {
strings = append(strings, token.str)
}
return tokens, strings
}
func tokensConsumeOptional(tokens []token, optional string) []token {
if len(tokens) < 1 {
return tokens
}
if strings.ToLower(tokens[0].str) == strings.ToLower(optional) {
return tokens[1:]
}
return tokens
}
|