summaryrefslogtreecommitdiff
path: root/internal/mapr
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2023-09-05 16:38:23 +0300
committerPaul Buetow <pbuetow@mimecast.com>2023-09-07 15:32:29 +0300
commit9c77304550d65b8e7c2b724b991eef0dbc13694a (patch)
treeb0401269acf383760e2b2f962e71d11fd55147d2 /internal/mapr
parent360f67bf536372cb6a78fe35c15ba6128fda290b (diff)
Can quote fields in select conditions, e.g. select `count($foo)`, ..
Diffstat (limited to 'internal/mapr')
-rw-r--r--internal/mapr/query.go10
-rw-r--r--internal/mapr/query_test.go40
-rw-r--r--internal/mapr/selectcondition.go19
-rw-r--r--internal/mapr/token.go10
4 files changed, 64 insertions, 15 deletions
diff --git a/internal/mapr/query.go b/internal/mapr/query.go
index 247cdaf..ddcbc90 100644
--- a/internal/mapr/query.go
+++ b/internal/mapr/query.go
@@ -73,6 +73,13 @@ func NewQuery(queryStr string) (*Query, error) {
Interval: time.Second * 5,
Limit: -1,
}
+
+ // If log format is CSV, then use "." as the table. It means, that
+ // we don't do any file filtering, we process all lines of the CSV.
+ if q.LogFormat == "csv" {
+ q.Table = "."
+ }
+
return &q, q.parse(tokens)
}
@@ -87,8 +94,7 @@ func (q *Query) Has(what string) bool {
}
func (q *Query) parse(tokens []token) error {
- tokens, err := q.parseTokens(tokens)
- if err != nil {
+ if _, err := q.parseTokens(tokens); err != nil {
return err
}
diff --git a/internal/mapr/query_test.go b/internal/mapr/query_test.go
index f03ccba..f37b8d4 100644
--- a/internal/mapr/query_test.go
+++ b/internal/mapr/query_test.go
@@ -252,3 +252,43 @@ func TestParseQueryDeep(t *testing.T) {
}
}
}
+
+func TestQuotedSelectCondition(t *testing.T) {
+ queryStr := "select `count($foo)`, foo, $foo, count($foo) logformat csv"
+
+ q, err := NewQuery(queryStr)
+ if err != nil {
+ t.Errorf("Query parse error: %s\n%v: %v", queryStr, q, err)
+ }
+ if len(q.Select) != 4 {
+ t.Errorf("Expected three elements in 'select' clause but got '%v': %s\n%v",
+ q.Select, queryStr, q)
+ }
+
+ if q.Select[0].Field != "count($foo)" {
+ t.Errorf("Expected 'num($foo)' as first element in 'select' clause but got '%v': %s\n%v",
+ q.Select[0].Field, queryStr, q)
+ }
+ if q.Select[0].Operation != Last {
+ t.Errorf("Expected 'Last' as aggregation function of first element in "+
+ "'select' clause but got '%v': %s\n%v", q.Select[0].Operation, queryStr, q)
+ }
+
+ if q.Select[1].Field != "foo" {
+ t.Errorf("Expected 'foo' as first element in 'select' clause but got '%v': %s\n%v",
+ q.Select[1].Field, queryStr, q)
+ }
+ if q.Select[2].Field != "$foo" {
+ t.Errorf("Expected '$foo' as first element in 'select' clause but got '%v': %s\n%v",
+ q.Select[2].Field, queryStr, q)
+ }
+
+ if q.Select[3].Field != "$foo" {
+ t.Errorf("Expected '$foo' as first element in 'select' clause but got '%v': %s\n%v",
+ q.Select[3].Field, queryStr, q)
+ }
+ if q.Select[3].Operation != Count {
+ t.Errorf("Expected 'count' as aggregation function of thourth element in "+
+ "'select' clause but got '%v': %s\n%v", q.Select[3].Operation, queryStr, q)
+ }
+}
diff --git a/internal/mapr/selectcondition.go b/internal/mapr/selectcondition.go
index 45fc16b..78359c7 100644
--- a/internal/mapr/selectcondition.go
+++ b/internal/mapr/selectcondition.go
@@ -40,16 +40,18 @@ func makeSelectConditions(tokens []token) ([]selectCondition, error) {
// Parse select aggregation, e.g. sum(foo)
parse := func(token token) (selectCondition, error) {
var sc selectCondition
- tokenStr := token.str
- if !strings.Contains(tokenStr, "(") && !strings.Contains(tokenStr, ")") {
- sc.Field = tokenStr
- sc.FieldStorage = tokenStr
+ // With quotes stripped: We got a quoted select expression, e.g.
+ // "select `count($foo)` ...", which will literaly look for field
+ // "count($foo)" without performing the count aggregation.
+ if token.quotesStripped || (!strings.Contains(token.str, "(") && !strings.Contains(token.str, ")")) {
+ sc.Field = token.str
+ sc.FieldStorage = token.str
sc.Operation = Last
return sc, nil
}
- a := strings.Split(tokenStr, "(")
+ a := strings.Split(token.str, "(")
if len(a) != 2 {
return sc, errors.New(invalidQuery + "Can't parse 'select' aggregation: " +
token.str)
@@ -61,8 +63,8 @@ func makeSelectConditions(tokens []token) ([]selectCondition, error) {
return sc, errors.New(invalidQuery + "Can't parse 'select' field name " +
"from aggregation: " + token.str)
}
- sc.Field = b[0] // Field name, e.g. 'foo'
- sc.FieldStorage = tokenStr // e.g. 'sum(foo)'
+ sc.Field = b[0] // Field name, e.g. 'foo'
+ sc.FieldStorage = token.str // e.g. 'sum(foo)'
switch agg {
case "count":
@@ -80,8 +82,7 @@ func makeSelectConditions(tokens []token) ([]selectCondition, error) {
case "len":
sc.Operation = Len
default:
- return sc, errors.New(invalidQuery +
- "Unknown aggregation in 'select' clause: " + agg)
+ return sc, errors.New(invalidQuery + "Unknown aggregation in 'select' clause: " + agg)
}
return sc, nil
}
diff --git a/internal/mapr/token.go b/internal/mapr/token.go
index 6ac7631..48d1192 100644
--- a/internal/mapr/token.go
+++ b/internal/mapr/token.go
@@ -9,8 +9,9 @@ var keywords = [...]string{"select", "from", "where", "set", "group", "rorder",
// Represents a parsed token, used to parse the mapr query.
type token struct {
- str string
- isBareword bool
+ str string
+ isBareword bool
+ quotesStripped bool
}
func (t token) isKeyword() bool {
@@ -71,8 +72,9 @@ func tokensConsume(tokens []token) ([]token, []token) {
stripped := t.str[1 : length-1]
//dlog.Common.Trace("stripped", stripped)
t := token{
- str: stripped,
- isBareword: t.isBareword,
+ str: stripped,
+ isBareword: t.isBareword,
+ quotesStripped: true,
}
consumed = append(consumed, t)
continue