From 9e89e8d6e24265395103e2bf7f99e7727114eebe Mon Sep 17 00:00:00 2001 From: Karsten Jeschkies Date: Tue, 26 Sep 2023 12:26:01 +0200 Subject: [PATCH] Check for nil StepResult. (#10704) --- pkg/logql/engine.go | 5 ++++- pkg/logql/evaluator.go | 5 ++++- pkg/logql/evaluator_test.go | 43 +++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/pkg/logql/engine.go b/pkg/logql/engine.go index a0135414c6..4884415c7d 100644 --- a/pkg/logql/engine.go +++ b/pkg/logql/engine.go @@ -351,10 +351,13 @@ func (q *query) evalSample(ctx context.Context, expr syntax.SampleExpr) (promql_ seriesIndex := map[uint64]*promql.Series{} next, ts, r := stepEvaluator.Next() - vec := r.SampleVector() if stepEvaluator.Error() != nil { return nil, stepEvaluator.Error() } + vec := promql.Vector{} + if next { + vec = r.SampleVector() + } // fail fast for the first step or instant query if len(vec) > maxSeries { diff --git a/pkg/logql/evaluator.go b/pkg/logql/evaluator.go index 6bb2ac2a40..1e5a5f1976 100644 --- a/pkg/logql/evaluator.go +++ b/pkg/logql/evaluator.go @@ -952,6 +952,9 @@ type LiteralStepEvaluator struct { func (e *LiteralStepEvaluator) Next() (bool, int64, StepResult) { ok, ts, r := e.nextEv.Next() + if !ok { + return ok, ts, r + } vec := r.SampleVector() results := make(promql.Vector, 0, len(vec)) for _, sample := range vec { @@ -1062,10 +1065,10 @@ type LabelReplaceEvaluator struct { func (e *LabelReplaceEvaluator) Next() (bool, int64, StepResult) { next, ts, r := e.nextEvaluator.Next() - vec := r.SampleVector() if !next { return false, 0, SampleVector{} } + vec := r.SampleVector() if e.labelCache == nil { e.labelCache = make(map[uint64]labels.Labels, len(vec)) } diff --git a/pkg/logql/evaluator_test.go b/pkg/logql/evaluator_test.go index 9e925dc4b3..bc600d6707 100644 --- a/pkg/logql/evaluator_test.go +++ b/pkg/logql/evaluator_test.go @@ -252,3 +252,46 @@ func TestEvaluator_mergeBinOpComparisons(t *testing.T) { }) } } + +func TestEmptyNestedEvaluator(t *testing.T) { + + for _, tc := range []struct { + desc string + ev StepEvaluator + }{ + { + desc: "LiteralStepEvaluator", + ev: &LiteralStepEvaluator{nextEv: &emptyEvaluator{}}, + }, + { + desc: "LabelReplaceEvaluator", + ev: &LabelReplaceEvaluator{nextEvaluator: &emptyEvaluator{}}, + }, + { + desc: "BinOpStepEvaluator", + ev: &BinOpStepEvaluator{rse: &emptyEvaluator{}}, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + ok, _, _ := tc.ev.Next() + require.False(t, ok) + }) + } + +} + +type emptyEvaluator struct{} + +func (*emptyEvaluator) Next() (ok bool, ts int64, r StepResult) { + return false, 0, nil +} + +func (*emptyEvaluator) Close() error { + return nil +} + +func (*emptyEvaluator) Error() error { + return nil +} + +func (*emptyEvaluator) Explain(Node) {}