mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-01-05 22:32:20 +01:00
app/vmselect/promql: hande comparisons with NaN
similar to Prometheus
Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/150
This commit is contained in:
parent
dcce92c63c
commit
218cb4623a
@ -416,10 +416,25 @@ func binaryOpIfnot(left, right float64) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func binaryOpEq(left, right float64) bool {
|
func binaryOpEq(left, right float64) bool {
|
||||||
|
// Special handling for nan == nan.
|
||||||
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/150 .
|
||||||
|
if math.IsNaN(left) {
|
||||||
|
return math.IsNaN(right)
|
||||||
|
}
|
||||||
|
|
||||||
return left == right
|
return left == right
|
||||||
}
|
}
|
||||||
|
|
||||||
func binaryOpNeq(left, right float64) bool {
|
func binaryOpNeq(left, right float64) bool {
|
||||||
|
// Special handling for comparison with nan.
|
||||||
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/150 .
|
||||||
|
if math.IsNaN(left) {
|
||||||
|
return !math.IsNaN(right)
|
||||||
|
}
|
||||||
|
if math.IsNaN(right) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
return left != right
|
return left != right
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,12 +149,6 @@ func scanString(s string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func scanPositiveNumber(s string) (string, error) {
|
func scanPositiveNumber(s string) (string, error) {
|
||||||
if strings.HasPrefix(s, "Inf") {
|
|
||||||
return "Inf", nil
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(s, "NaN") {
|
|
||||||
return "NaN", nil
|
|
||||||
}
|
|
||||||
// Scan integer part. It may be empty if fractional part exists.
|
// Scan integer part. It may be empty if fractional part exists.
|
||||||
i := 0
|
i := 0
|
||||||
for i < len(s) && isDecimalChar(s[i]) {
|
for i < len(s) && isDecimalChar(s[i]) {
|
||||||
@ -333,6 +327,14 @@ func scanTagFilterOpPrefix(s string) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isInfOrNaN(s string) bool {
|
||||||
|
if len(s) != 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
return s == "inf" || s == "nan"
|
||||||
|
}
|
||||||
|
|
||||||
func isOffset(s string) bool {
|
func isOffset(s string) bool {
|
||||||
s = strings.ToLower(s)
|
s = strings.ToLower(s)
|
||||||
return s == "offset"
|
return s == "offset"
|
||||||
@ -361,7 +363,7 @@ func isPositiveNumberPrefix(s string) bool {
|
|||||||
|
|
||||||
// Check for .234 numbers
|
// Check for .234 numbers
|
||||||
if s[0] != '.' || len(s) < 2 {
|
if s[0] != '.' || len(s) < 2 {
|
||||||
return strings.HasPrefix(s, "Inf") || strings.HasPrefix(s, "NaN")
|
return false
|
||||||
}
|
}
|
||||||
return isDecimalChar(s[1])
|
return isDecimalChar(s[1])
|
||||||
}
|
}
|
||||||
|
@ -373,7 +373,7 @@ func (p *parser) parseSingleExpr() (expr, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) parseSingleExprWithoutRollupSuffix() (expr, error) {
|
func (p *parser) parseSingleExprWithoutRollupSuffix() (expr, error) {
|
||||||
if isPositiveNumberPrefix(p.lex.Token) {
|
if isPositiveNumberPrefix(p.lex.Token) || isInfOrNaN(p.lex.Token) {
|
||||||
return p.parsePositiveNumberExpr()
|
return p.parsePositiveNumberExpr()
|
||||||
}
|
}
|
||||||
if isStringPrefix(p.lex.Token) {
|
if isStringPrefix(p.lex.Token) {
|
||||||
@ -417,7 +417,7 @@ func (p *parser) parseSingleExprWithoutRollupSuffix() (expr, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) parsePositiveNumberExpr() (*numberExpr, error) {
|
func (p *parser) parsePositiveNumberExpr() (*numberExpr, error) {
|
||||||
if !isPositiveNumberPrefix(p.lex.Token) {
|
if !isPositiveNumberPrefix(p.lex.Token) && !isInfOrNaN(p.lex.Token) {
|
||||||
return nil, fmt.Errorf(`positiveNumberExpr: unexpected token %q; want "number"`, p.lex.Token)
|
return nil, fmt.Errorf(`positiveNumberExpr: unexpected token %q; want "number"`, p.lex.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,14 +170,34 @@ func TestParsePromQLSuccess(t *testing.T) {
|
|||||||
another(`-.2`, `-0.2`)
|
another(`-.2`, `-0.2`)
|
||||||
another(`-.2E-2`, `-0.002`)
|
another(`-.2E-2`, `-0.002`)
|
||||||
same(`NaN`)
|
same(`NaN`)
|
||||||
|
another(`nan`, `NaN`)
|
||||||
|
another(`NAN`, `NaN`)
|
||||||
|
another(`nAN`, `NaN`)
|
||||||
another(`Inf`, `+Inf`)
|
another(`Inf`, `+Inf`)
|
||||||
|
another(`INF`, `+Inf`)
|
||||||
|
another(`inf`, `+Inf`)
|
||||||
another(`+Inf`, `+Inf`)
|
another(`+Inf`, `+Inf`)
|
||||||
another(`-Inf`, `-Inf`)
|
another(`-Inf`, `-Inf`)
|
||||||
|
another(`-inF`, `-Inf`)
|
||||||
|
|
||||||
// binaryOpExpr
|
// binaryOpExpr
|
||||||
another(`NaN + 2 *3 * Inf`, `NaN`)
|
another(`nan == nan`, `NaN`)
|
||||||
another(`Inf - Inf`, `NaN`)
|
another(`nan ==bool nan`, `1`)
|
||||||
another(`Inf + Inf`, `+Inf`)
|
another(`nan !=bool nan`, `0`)
|
||||||
|
another(`nan !=bool 2`, `1`)
|
||||||
|
another(`2 !=bool nan`, `1`)
|
||||||
|
another(`nan >bool nan`, `0`)
|
||||||
|
another(`nan <bool nan`, `0`)
|
||||||
|
another(`1 ==bool nan`, `0`)
|
||||||
|
another(`NaN !=bool 1`, `1`)
|
||||||
|
another(`inf >=bool 2`, `1`)
|
||||||
|
another(`-1 >bool -inf`, `1`)
|
||||||
|
another(`-1 <bool -inf`, `0`)
|
||||||
|
another(`nan + 2 *3 * inf`, `NaN`)
|
||||||
|
another(`INF - Inf`, `NaN`)
|
||||||
|
another(`Inf + inf`, `+Inf`)
|
||||||
|
another(`1/0`, `+Inf`)
|
||||||
|
another(`0/0`, `NaN`)
|
||||||
another(`-m`, `0 - m`)
|
another(`-m`, `0 - m`)
|
||||||
same(`m + ignoring () n[5m]`)
|
same(`m + ignoring () n[5m]`)
|
||||||
another(`M + IGNORING () N[5m]`, `M + ignoring () N[5m]`)
|
another(`M + IGNORING () N[5m]`, `M + ignoring () N[5m]`)
|
||||||
|
Loading…
Reference in New Issue
Block a user