From 88e1b7d144e87c632765ce4c2f8f9abd7596efa8 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 18 Jun 2020 23:04:59 +0300 Subject: [PATCH] app/vmselect/promql: fill gaps on right side with values from left side of `or` operator in the same way as Prometheus does Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/552 --- app/vmselect/promql/binary_op.go | 19 ++++++++++++++++--- app/vmselect/promql/exec_test.go | 11 +++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/vmselect/promql/binary_op.go b/app/vmselect/promql/binary_op.go index 7ba5257a8..cd25a115d 100644 --- a/app/vmselect/promql/binary_op.go +++ b/app/vmselect/promql/binary_op.go @@ -310,9 +310,22 @@ func binaryOpOr(bfa *binaryOpFuncArg) ([]*timeseries, error) { for _, tss := range mLeft { rvs = append(rvs, tss...) } - for k, tss := range mRight { - if mLeft[k] == nil { - rvs = append(rvs, tss...) + for k, tssRight := range mRight { + tssLeft := mLeft[k] + if tssLeft == nil { + rvs = append(rvs, tssRight...) + continue + } + // Fill gaps in tssLeft with values from tssRight as Prometheus does. + // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/552 + valuesRight := tssRight[0].Values + for _, tsLeft := range tssLeft { + valuesLeft := tsLeft.Values + for i, v := range valuesLeft { + if math.IsNaN(v) { + valuesLeft[i] = valuesRight[i] + } + } } } return rvs, nil diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go index a833533c8..5c2913ad8 100644 --- a/app/vmselect/promql/exec_test.go +++ b/app/vmselect/promql/exec_test.go @@ -1849,6 +1849,17 @@ func TestExecSuccess(t *testing.T) { resultExpected := []netstorage.Result{r} f(q, resultExpected) }) + t.Run(`scalar or scalar`, func(t *testing.T) { + t.Parallel() + q := `time() > 1400 or 123` + r := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{123, 123, 123, 1600, 1800, 2000}, + Timestamps: timestampsExpected, + } + resultExpected := []netstorage.Result{r} + f(q, resultExpected) + }) t.Run(`timseries-with-tags unless 2`, func(t *testing.T) { t.Parallel() q := `label_set(time(), "foo", "bar") unless 2`