Browse Source

[bugfix] Parse negative value in PromQL (#4564)

* Parse negative value in PromQL
* Enforce space between values

Signed-off-by: Ganesh Vernekar <cs15btech11018@iith.ac.in>
pull/4617/merge
Ganesh Vernekar 6 years ago committed by Brian Brazil
parent
commit
73db8b8cea
  1. 3
      promql/lex.go
  2. 8
      promql/lex_test.go
  3. 17
      promql/parse.go
  4. 33
      promql/parse_test.go

3
promql/lex.go

@ -143,6 +143,7 @@ const (
itemDuration itemDuration
itemBlank itemBlank
itemTimes itemTimes
itemSpace
operatorsStart operatorsStart
// Operators. // Operators.
@ -247,6 +248,7 @@ var itemTypeStr = map[ItemType]string{
itemSemicolon: ";", itemSemicolon: ";",
itemBlank: "_", itemBlank: "_",
itemTimes: "x", itemTimes: "x",
itemSpace: "<space>",
itemSUB: "-", itemSUB: "-",
itemADD: "+", itemADD: "+",
@ -616,6 +618,7 @@ func lexValueSequence(l *lexer) stateFn {
case r == eof: case r == eof:
return lexStatements return lexStatements
case isSpace(r): case isSpace(r):
l.emit(itemSpace)
lexSpace(l) lexSpace(l)
case r == '+': case r == '+':
l.emit(itemADD) l.emit(itemADD)

8
promql/lex_test.go

@ -406,9 +406,13 @@ var tests = []struct {
expected: []item{ expected: []item{
{itemLeftBrace, 0, `{`}, {itemLeftBrace, 0, `{`},
{itemRightBrace, 1, `}`}, {itemRightBrace, 1, `}`},
{itemSpace, 2, ` `},
{itemBlank, 3, `_`}, {itemBlank, 3, `_`},
{itemSpace, 4, ` `},
{itemNumber, 5, `1`}, {itemNumber, 5, `1`},
{itemSpace, 6, ` `},
{itemTimes, 7, `x`}, {itemTimes, 7, `x`},
{itemSpace, 8, ` `},
{itemNumber, 9, `.3`}, {itemNumber, 9, `.3`},
}, },
seriesDesc: true, seriesDesc: true,
@ -417,9 +421,12 @@ var tests = []struct {
input: `metric +Inf Inf NaN`, input: `metric +Inf Inf NaN`,
expected: []item{ expected: []item{
{itemIdentifier, 0, `metric`}, {itemIdentifier, 0, `metric`},
{itemSpace, 6, ` `},
{itemADD, 7, `+`}, {itemADD, 7, `+`},
{itemNumber, 8, `Inf`}, {itemNumber, 8, `Inf`},
{itemSpace, 11, ` `},
{itemNumber, 12, `Inf`}, {itemNumber, 12, `Inf`},
{itemSpace, 15, ` `},
{itemNumber, 16, `NaN`}, {itemNumber, 16, `NaN`},
}, },
seriesDesc: true, seriesDesc: true,
@ -428,6 +435,7 @@ var tests = []struct {
input: `metric 1+1x4`, input: `metric 1+1x4`,
expected: []item{ expected: []item{
{itemIdentifier, 0, `metric`}, {itemIdentifier, 0, `metric`},
{itemSpace, 6, ` `},
{itemNumber, 7, `1`}, {itemNumber, 7, `1`},
{itemADD, 8, `+`}, {itemADD, 8, `+`},
{itemNumber, 9, `1`}, {itemNumber, 9, `1`},

17
promql/parse.go

@ -175,6 +175,9 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
const ctx = "series values" const ctx = "series values"
for { for {
for p.peek().typ == itemSpace {
p.next()
}
if p.peek().typ == itemEOF { if p.peek().typ == itemEOF {
break break
} }
@ -193,6 +196,11 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
for i := uint64(0); i < times; i++ { for i := uint64(0); i < times; i++ {
vals = append(vals, sequenceValue{omitted: true}) vals = append(vals, sequenceValue{omitted: true})
} }
// This is to ensure that there is a space between this and the next number.
// This is especially required if the next number is negative.
if t := p.expectOneOf(itemSpace, itemEOF, ctx).typ; t == itemEOF {
break
}
continue continue
} }
@ -217,7 +225,8 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
}) })
// If there are no offset repetitions specified, proceed with the next value. // If there are no offset repetitions specified, proceed with the next value.
if t := p.peek(); t.typ == itemNumber || t.typ == itemBlank || t.typ == itemIdentifier && t.val == "stale" { if t := p.peek(); t.typ == itemSpace {
// This ensures there is a space between every value.
continue continue
} else if t.typ == itemEOF { } else if t.typ == itemEOF {
break break
@ -244,6 +253,12 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
value: k, value: k,
}) })
} }
// This is to ensure that there is a space between this expanding notation
// and the next number. This is especially required if the next number
// is negative.
if t := p.expectOneOf(itemSpace, itemEOF, ctx).typ; t == itemEOF {
break
}
} }
return m, vals, nil return m, vals, nil
} }

33
promql/parse_test.go

@ -1737,6 +1737,39 @@ var testSeries = []struct {
}, { }, {
input: `my_metric{a="b"} 1 3 _ 5 _a4`, input: `my_metric{a="b"} 1 3 _ 5 _a4`,
fail: true, fail: true,
}, {
input: `my_metric{a="b"} 1 -1`,
expectedMetric: labels.FromStrings(labels.MetricName, "my_metric", "a", "b"),
expectedValues: newSeq(1, -1),
}, {
input: `my_metric{a="b"} 1 +1`,
expectedMetric: labels.FromStrings(labels.MetricName, "my_metric", "a", "b"),
expectedValues: newSeq(1, 1),
}, {
input: `my_metric{a="b"} 1 -1 -3-10x4 7 9 +5`,
expectedMetric: labels.FromStrings(labels.MetricName, "my_metric", "a", "b"),
expectedValues: newSeq(1, -1, -3, -13, -23, -33, -43, 7, 9, 5),
}, {
input: `my_metric{a="b"} 1 +1 +4 -6 -2 8`,
expectedMetric: labels.FromStrings(labels.MetricName, "my_metric", "a", "b"),
expectedValues: newSeq(1, 1, 4, -6, -2, 8),
}, {
// Trailing spaces should be correctly handles.
input: `my_metric{a="b"} 1 2 3 `,
expectedMetric: labels.FromStrings(labels.MetricName, "my_metric", "a", "b"),
expectedValues: newSeq(1, 2, 3),
}, {
input: `my_metric{a="b"} -3-3 -3`,
fail: true,
}, {
input: `my_metric{a="b"} -3 -3-3`,
fail: true,
}, {
input: `my_metric{a="b"} -3 _-2`,
fail: true,
}, {
input: `my_metric{a="b"} -3 3+3x4-4`,
fail: true,
}, },
} }

Loading…
Cancel
Save