diff --git a/promql/engine.go b/promql/engine.go index d9cf43eef1..990198ccee 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -279,6 +279,9 @@ func (ng *Engine) NewRangeQuery(qs string, start, end clientmodel.Timestamp, int if err != nil { return nil, err } + if expr.Type() != ExprVector && expr.Type() != ExprScalar { + return nil, fmt.Errorf("invalid expression type %q for range query, must be scalar or vector", expr.Type()) + } qry := ng.newQuery(expr, start, end, interval) qry.q = qs @@ -413,6 +416,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) ( evalTimer.Stop() return val, nil } + numSteps := int(s.End.Sub(s.Start) / s.Interval) // Range evaluation. sampleStreams := map[clientmodel.Fingerprint]*SampleStream{} @@ -430,26 +434,36 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) ( if err != nil { return nil, err } - vector, ok := val.(Vector) - if !ok { - return nil, fmt.Errorf("value for expression %q must be of type vector but is %s", s.Expr, val.Type()) - } - for _, sample := range vector { - samplePair := metric.SamplePair{ - Value: sample.Value, - Timestamp: sample.Timestamp, + switch v := val.(type) { + case *Scalar: + // As the expression type does not change we can safely default to 0 + // as the fingerprint for scalar expressions. + ss := sampleStreams[0] + if ss == nil { + ss = &SampleStream{Values: make(metric.Values, 0, numSteps)} + sampleStreams[0] = ss } - fp := sample.Metric.Metric.Fingerprint() - if sampleStreams[fp] == nil { - sampleStreams[fp] = &SampleStream{ - Metric: sample.Metric, - Values: metric.Values{samplePair}, + ss.Values = append(ss.Values, metric.SamplePair{ + Value: v.Value, + Timestamp: v.Timestamp, + }) + case Vector: + for _, sample := range v { + fp := sample.Metric.Metric.Fingerprint() + ss := sampleStreams[fp] + if ss == nil { + ss = &SampleStream{Values: make(metric.Values, 0, numSteps)} + sampleStreams[fp] = ss } - } else { - sampleStreams[fp].Values = append(sampleStreams[fp].Values, samplePair) - } + ss.Values = append(ss.Values, metric.SamplePair{ + Value: sample.Value, + Timestamp: sample.Timestamp, + }) + } + default: + panic(fmt.Errorf("promql.Engine.exec: invalid expression type %q", val.Type())) } } evalTimer.Stop()