cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.71.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/parser/utils/source.go

1048lines · modeblame

b4490cabLukasz Mierzwa1 years ago1package utils
2
3import (
13c2f1c2Lukasz Mierzwa1 years ago4"fmt"
aaea75cfLukasz Mierzwa1 years ago5"math"
f7d9a38aLukasz Mierzwa1 years ago6"regexp"
b4490cabLukasz Mierzwa1 years ago7"slices"
c269e3b9Lukasz Mierzwa1 years ago8"strconv"
13c2f1c2Lukasz Mierzwa1 years ago9"strings"
b4490cabLukasz Mierzwa1 years ago10
11"github.com/prometheus/prometheus/model/labels"
12promParser "github.com/prometheus/prometheus/promql/parser"
1331c38cLukasz Mierzwa1 years ago13"github.com/prometheus/prometheus/promql/parser/posrange"
b4490cabLukasz Mierzwa1 years ago14)
15
c269e3b9Lukasz Mierzwa1 years ago16var guaranteedLabelsMatches = []labels.MatchType{labels.MatchEqual, labels.MatchRegexp}
17
b4490cabLukasz Mierzwa1 years ago18type SourceType int
19
20const (
21UnknownSource SourceType = iota
22NumberSource
23StringSource
24SelectorSource
25FuncSource
26AggregateSource
27)
28
1331c38cLukasz Mierzwa1 years ago29type ExcludedLabel struct {
30Reason string
f7d9a38aLukasz Mierzwa1 years ago31Fragment posrange.PositionRange
1331c38cLukasz Mierzwa1 years ago32}
33
c269e3b9Lukasz Mierzwa1 years ago34type Join struct {
35Src Source
36}
37
1bca8feeLukasz Mierzwa1 years ago38// FIXME remove Selector/Call/Aggregation?
39// Use a single parser.Node instead?
b4490cabLukasz Mierzwa1 years ago40type Source struct {
c269e3b9Lukasz Mierzwa1 years ago41Selector *promParser.VectorSelector // Vector selector used for this source.
42Call *promParser.Call // Most outer call used inside this source.
43Aggregation *promParser.AggregateExpr // Most outer aggregation expression used inside this source.
44ExcludeReason map[string]ExcludedLabel // Reason why a label was excluded
b4490cabLukasz Mierzwa1 years ago45Operation string
c269e3b9Lukasz Mierzwa1 years ago46IsDeadReason string
0fff8c1eLukasz Mierzwa1 years ago47Returns promParser.ValueType
c269e3b9Lukasz Mierzwa1 years ago48Joins []Join // Any other sources this source joins with.
49Unless []Join // Any other sources this source is suppressed by.
50IncludedLabels []string // Labels that are included by filters, they will be present if exist on source series (by).
51ExcludedLabels []string // Labels guaranteed to be excluded from the results (without).
52GuaranteedLabels []string // Labels guaranteed to be present on the results (matchers).
1bca8feeLukasz Mierzwa1 years ago53Position posrange.PositionRange
54ReturnedNumber float64 // If AlwaysReturns=true this is the number that's returned
b4490cabLukasz Mierzwa1 years ago55Type SourceType
12308218Lukasz Mierzwa1 years ago56FixedLabels bool // Labels are fixed and only allowed labels can be present.
aaea75cfLukasz Mierzwa1 years ago57IsDead bool // True if this source cannot be reached and is dead code.
58AlwaysReturns bool // True if this source always returns results.
73d0e49eLukasz Mierzwa1 years ago59KnownReturn bool // True if we always know the return value.
17fb6517Lukasz Mierzwa1 years ago60IsConditional bool // True if this source is guarded by 'foo > 5' or other condition.
b4490cabLukasz Mierzwa1 years ago61}
62
c269e3b9Lukasz Mierzwa1 years ago63func (s Source) Fragment(expr string) string {
64switch {
65case s.Type == FuncSource && s.Call != nil:
f7d9a38aLukasz Mierzwa1 years ago66return GetQueryFragment(expr, s.Call.PosRange)
c269e3b9Lukasz Mierzwa1 years ago67case s.Call != nil:
f7d9a38aLukasz Mierzwa1 years ago68return GetQueryFragment(expr, s.Call.PosRange)
c269e3b9Lukasz Mierzwa1 years ago69case s.Type == AggregateSource && s.Aggregation != nil:
f7d9a38aLukasz Mierzwa1 years ago70return GetQueryFragment(expr, s.Aggregation.PosRange)
c269e3b9Lukasz Mierzwa1 years ago71case s.Selector != nil:
f7d9a38aLukasz Mierzwa1 years ago72return GetQueryFragment(expr, s.Selector.PosRange)
c269e3b9Lukasz Mierzwa1 years ago73default:
74return ""
75}
76}
77
1bca8feeLukasz Mierzwa1 years ago78func (s Source) GetSmallestPosition() (pr posrange.PositionRange) {
79pr.Start = s.Position.Start
80pr.End = s.Position.End
81
82if s.Selector != nil {
700dca72Lukasz Mierzwa1 years ago83if s.Selector.PosRange.Start > pr.Start {
84pr.Start = s.Selector.PosRange.Start
85pr.End = s.Selector.PosRange.End
86}
1bca8feeLukasz Mierzwa1 years ago87}
88if s.Call != nil {
700dca72Lukasz Mierzwa1 years ago89if s.Call.PosRange.Start > pr.Start {
90pr.Start = s.Call.PosRange.Start
91pr.End = s.Call.PosRange.End
92}
1bca8feeLukasz Mierzwa1 years ago93}
94if s.Aggregation != nil {
700dca72Lukasz Mierzwa1 years ago95if s.Aggregation.PosRange.Start > pr.Start {
96pr.Start = s.Aggregation.PosRange.Start
97pr.End = s.Aggregation.PosRange.End
98}
1bca8feeLukasz Mierzwa1 years ago99}
100return pr
101}
102
103func (s Source) CanHaveLabel(name string) bool {
104if slices.Contains(s.ExcludedLabels, name) {
105return false
106}
107if slices.Contains(s.IncludedLabels, name) {
108return true
109}
110if slices.Contains(s.GuaranteedLabels, name) {
111return true
112}
113return !s.FixedLabels
114}
115
91a38afdLukasz Mierzwa1 years ago116func (s Source) LabelExcludeReason(name string) ExcludedLabel {
117if el, ok := s.ExcludeReason[name]; ok {
118return el
119}
b3b2247eLukasz Mierzwa1 years ago120return s.ExcludeReason[""]
91a38afdLukasz Mierzwa1 years ago121}
122
c269e3b9Lukasz Mierzwa1 years ago123type Visitor func(s Source)
124
125func (s Source) WalkSources(fn Visitor) {
126fn(s)
127for _, j := range s.Joins {
128j.Src.WalkSources(fn)
129}
130for _, u := range s.Unless {
131u.Src.WalkSources(fn)
132}
133}
134
4b70d4afLukasz Mierzwa1 years ago135func LabelsSource(expr string, node promParser.Node) (src []Source) {
f97e7fc2Lukasz Mierzwa1 years ago136return walkNode(expr, node)
b4490cabLukasz Mierzwa1 years ago137}
138
f97e7fc2Lukasz Mierzwa1 years ago139func walkNode(expr string, node promParser.Node) (src []Source) {
140var s Source
b4490cabLukasz Mierzwa1 years ago141switch n := node.(type) {
142case *promParser.AggregateExpr:
f97e7fc2Lukasz Mierzwa1 years ago143src = append(src, walkAggregation(expr, n)...)
b4490cabLukasz Mierzwa1 years ago144
145case *promParser.BinaryExpr:
f97e7fc2Lukasz Mierzwa1 years ago146src = append(src, parseBinOps(expr, n)...)
b4490cabLukasz Mierzwa1 years ago147
2bc6b9e5Lukasz Mierzwa1 years ago148case *promParser.Call:
17fb6517Lukasz Mierzwa1 years ago149src = append(src, parseCall(expr, n)...)
2bc6b9e5Lukasz Mierzwa1 years ago150
b4490cabLukasz Mierzwa1 years ago151case *promParser.MatrixSelector:
f97e7fc2Lukasz Mierzwa1 years ago152src = append(src, walkNode(expr, n.VectorSelector)...)
b4490cabLukasz Mierzwa1 years ago153
154case *promParser.SubqueryExpr:
f97e7fc2Lukasz Mierzwa1 years ago155src = append(src, walkNode(expr, n.Expr)...)
b4490cabLukasz Mierzwa1 years ago156
157case *promParser.NumberLiteral:
158s.Type = NumberSource
0fff8c1eLukasz Mierzwa1 years ago159s.Returns = promParser.ValueTypeScalar
73d0e49eLukasz Mierzwa1 years ago160s.KnownReturn = true
c269e3b9Lukasz Mierzwa1 years ago161s.ReturnedNumber = n.Val
1887ad0aLukasz Mierzwa1 years ago162s.IncludedLabels = nil
163s.GuaranteedLabels = nil
0fff8c1eLukasz Mierzwa1 years ago164s.FixedLabels = true
aaea75cfLukasz Mierzwa1 years ago165s.AlwaysReturns = true
1887ad0aLukasz Mierzwa1 years ago166s.ExcludeReason = setInMap(
167s.ExcludeReason,
168"",
169ExcludedLabel{
f7d9a38aLukasz Mierzwa1 years ago170Reason: "This query returns a number value with no labels.",
171Fragment: n.PosRange,
1887ad0aLukasz Mierzwa1 years ago172},
173)
1bca8feeLukasz Mierzwa1 years ago174s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago175src = append(src, s)
b4490cabLukasz Mierzwa1 years ago176
177case *promParser.ParenExpr:
f97e7fc2Lukasz Mierzwa1 years ago178src = append(src, walkNode(expr, n.Expr)...)
b4490cabLukasz Mierzwa1 years ago179
180case *promParser.StringLiteral:
181s.Type = StringSource
0fff8c1eLukasz Mierzwa1 years ago182s.Returns = promParser.ValueTypeString
1887ad0aLukasz Mierzwa1 years ago183s.IncludedLabels = nil
184s.GuaranteedLabels = nil
0fff8c1eLukasz Mierzwa1 years ago185s.FixedLabels = true
aaea75cfLukasz Mierzwa1 years ago186s.AlwaysReturns = true
1887ad0aLukasz Mierzwa1 years ago187s.ExcludeReason = setInMap(
188s.ExcludeReason,
189"",
190ExcludedLabel{
f7d9a38aLukasz Mierzwa1 years ago191Reason: "This query returns a string value with no labels.",
192Fragment: n.PosRange,
1887ad0aLukasz Mierzwa1 years ago193},
194)
1bca8feeLukasz Mierzwa1 years ago195s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago196src = append(src, s)
b4490cabLukasz Mierzwa1 years ago197
198case *promParser.UnaryExpr:
f97e7fc2Lukasz Mierzwa1 years ago199src = append(src, walkNode(expr, n.Expr)...)
b4490cabLukasz Mierzwa1 years ago200
201case *promParser.StepInvariantExpr:
202// Not possible to get this from the parser.
203
204case *promParser.VectorSelector:
205s.Type = SelectorSource
0fff8c1eLukasz Mierzwa1 years ago206s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago207s.Selector = n
17fb6517Lukasz Mierzwa1 years ago208s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, n)...)
c0bbcf74Lukasz Mierzwa1 years ago209for _, name := range labelsWithEmptyValueSelector(n) {
210s = excludeLabel(s, name)
211s.ExcludeReason = setInMap(
212s.ExcludeReason,
213name,
214ExcludedLabel{
215Reason: fmt.Sprintf("Query uses `{%s=\"\"}` selector which will filter out any time series with the `%s` label set.", name, name),
f7d9a38aLukasz Mierzwa1 years ago216Fragment: n.PosRange,
c0bbcf74Lukasz Mierzwa1 years ago217},
218)
219}
1bca8feeLukasz Mierzwa1 years ago220s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago221src = append(src, s)
b4490cabLukasz Mierzwa1 years ago222
223default:
224// unhandled type
225}
f97e7fc2Lukasz Mierzwa1 years ago226return src
b4490cabLukasz Mierzwa1 years ago227}
2bc6b9e5Lukasz Mierzwa1 years ago228
229func removeFromSlice(sl []string, s ...string) []string {
230for _, v := range s {
231idx := slices.Index(sl, v)
232if idx >= 0 {
233if len(sl) == 1 {
234return nil
235}
0545edccLukasz Mierzwa1 years ago236sl = slices.Delete(sl, idx, idx+1)
2bc6b9e5Lukasz Mierzwa1 years ago237}
238}
239return sl
240}
241
242func appendToSlice(dst []string, values ...string) []string {
243for _, v := range values {
244if !slices.Contains(dst, v) {
245dst = append(dst, v)
246}
247}
248return dst
249}
250
17fb6517Lukasz Mierzwa1 years ago251func includeLabel(s Source, names ...string) Source {
252s.ExcludedLabels = removeFromSlice(s.ExcludedLabels, names...)
253for _, name := range names {
254delete(s.ExcludeReason, name)
255}
256s.IncludedLabels = appendToSlice(s.IncludedLabels, names...)
257return s
258}
259
91a38afdLukasz Mierzwa1 years ago260// Include labels that were not already excluded.
73d0e49eLukasz Mierzwa1 years ago261// FIXME most should use this?
91a38afdLukasz Mierzwa1 years ago262func maybeIncludeLabel(s Source, names ...string) Source {
263for _, name := range names {
264if !slices.Contains(s.ExcludedLabels, name) {
265s.IncludedLabels = appendToSlice(s.IncludedLabels, names...)
266}
267}
268return s
269}
270
993781f3Lukasz Mierzwa1 years ago271func restrictIncludedLabels(s Source, names []string) Source {
272todo := []string{}
273for _, name := range s.IncludedLabels {
274if !slices.Contains(names, name) {
275todo = append(todo, name)
276}
277}
278s.IncludedLabels = removeFromSlice(s.IncludedLabels, todo...)
279return s
280}
281
17fb6517Lukasz Mierzwa1 years ago282func guaranteeLabel(s Source, names ...string) Source {
283s.ExcludedLabels = removeFromSlice(s.ExcludedLabels, names...)
284for _, name := range names {
285delete(s.ExcludeReason, name)
286}
287s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, names...)
288return s
289}
290
c269e3b9Lukasz Mierzwa1 years ago291func restrictGuaranteedLabels(s Source, names []string) Source {
292todo := []string{}
293for _, name := range s.GuaranteedLabels {
294if !slices.Contains(names, name) {
295todo = append(todo, name)
296}
297}
298s.GuaranteedLabels = removeFromSlice(s.GuaranteedLabels, todo...)
299return s
300}
301
17fb6517Lukasz Mierzwa1 years ago302func excludeLabel(s Source, names ...string) Source {
303s.ExcludedLabels = appendToSlice(s.ExcludedLabels, names...)
304s.IncludedLabels = removeFromSlice(s.IncludedLabels, names...)
305s.GuaranteedLabels = removeFromSlice(s.GuaranteedLabels, names...)
306return s
307}
308
1331c38cLukasz Mierzwa1 years ago309func setInMap(dst map[string]ExcludedLabel, key string, val ExcludedLabel) map[string]ExcludedLabel {
13c2f1c2Lukasz Mierzwa1 years ago310if dst == nil {
1331c38cLukasz Mierzwa1 years ago311dst = map[string]ExcludedLabel{}
13c2f1c2Lukasz Mierzwa1 years ago312}
313dst[key] = val
314return dst
315}
316
bd876148Lukasz Mierzwa1 years ago317func labelsFromSelectors(matches []labels.MatchType, selector *promParser.VectorSelector) (names []string) {
e718edd9Lukasz Mierzwa1 years ago318if selector == nil {
319return nil
320}
bd876148Lukasz Mierzwa1 years ago321// Any label used in positive filters is gurnateed to be present.
322for _, lm := range selector.LabelMatchers {
323if lm.Name == labels.MetricName {
324continue
325}
326if !slices.Contains(matches, lm.Type) {
327continue
328}
329names = appendToSlice(names, lm.Name)
c0bbcf74Lukasz Mierzwa1 years ago330}
331return names
332}
333
334func labelsWithEmptyValueSelector(selector *promParser.VectorSelector) (names []string) {
335for _, lm := range selector.LabelMatchers {
336if lm.Name == labels.MetricName {
337continue
338}
339if lm.Type == labels.MatchEqual && lm.Value == "" {
340names = appendToSlice(names, lm.Name)
0fff8c1eLukasz Mierzwa1 years ago341}
342}
343return names
344}
345
f7d9a38aLukasz Mierzwa1 years ago346func GetQueryFragment(expr string, pos posrange.PositionRange) string {
1331c38cLukasz Mierzwa1 years ago347return expr[pos.Start:pos.End]
348}
349
c269e3b9Lukasz Mierzwa1 years ago350// FIXME Aggregations strip __name__.
f97e7fc2Lukasz Mierzwa1 years ago351func walkAggregation(expr string, n *promParser.AggregateExpr) (src []Source) {
352var s Source
353switch n.Op {
354case promParser.SUM:
355for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago356s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago357s.Operation = "sum"
1bca8feeLukasz Mierzwa1 years ago358s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago359src = append(src, s)
13c2f1c2Lukasz Mierzwa1 years ago360}
f97e7fc2Lukasz Mierzwa1 years ago361case promParser.MIN:
362for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago363s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago364s.Operation = "min"
1bca8feeLukasz Mierzwa1 years ago365s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago366src = append(src, s)
367}
368case promParser.MAX:
369for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago370s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago371s.Operation = "max"
1bca8feeLukasz Mierzwa1 years ago372s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago373src = append(src, s)
374}
375case promParser.AVG:
376for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago377s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago378s.Operation = "avg"
1bca8feeLukasz Mierzwa1 years ago379s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago380src = append(src, s)
381}
382case promParser.GROUP:
383for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago384s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago385s.Operation = "group"
1bca8feeLukasz Mierzwa1 years ago386s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago387src = append(src, s)
388}
389case promParser.STDDEV:
390for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago391s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago392s.Operation = "stddev"
1bca8feeLukasz Mierzwa1 years ago393s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago394src = append(src, s)
395}
396case promParser.STDVAR:
397for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago398s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago399s.Operation = "stdvar"
1bca8feeLukasz Mierzwa1 years ago400s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago401src = append(src, s)
402}
403case promParser.COUNT:
404for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago405s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago406s.Operation = "count"
1bca8feeLukasz Mierzwa1 years ago407s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago408src = append(src, s)
409}
410case promParser.COUNT_VALUES:
411for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago412s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago413s.Operation = "count_values"
414// Param is the label to store the count value in.
17fb6517Lukasz Mierzwa1 years ago415s = includeLabel(s, n.Param.(*promParser.StringLiteral).Val)
416s = guaranteeLabel(s, n.Param.(*promParser.StringLiteral).Val)
1bca8feeLukasz Mierzwa1 years ago417s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago418src = append(src, s)
419}
420case promParser.QUANTILE:
421for _, s = range parseAggregation(expr, n) {
c269e3b9Lukasz Mierzwa1 years ago422s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago423s.Operation = "quantile"
1bca8feeLukasz Mierzwa1 years ago424s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago425src = append(src, s)
426}
427case promParser.TOPK:
428for _, s = range walkNode(expr, n.Expr) {
429s.Type = AggregateSource
c269e3b9Lukasz Mierzwa1 years ago430s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago431s.Operation = "topk"
1bca8feeLukasz Mierzwa1 years ago432s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago433src = append(src, s)
434}
435case promParser.BOTTOMK:
436for _, s = range walkNode(expr, n.Expr) {
437s.Type = AggregateSource
c269e3b9Lukasz Mierzwa1 years ago438s.Aggregation = n
f97e7fc2Lukasz Mierzwa1 years ago439s.Operation = "bottomk"
1bca8feeLukasz Mierzwa1 years ago440s.Position = n.PosRange
f97e7fc2Lukasz Mierzwa1 years ago441src = append(src, s)
442}
443/*
444TODO these are experimental and promParser.EnableExperimentalFunctions must be set to true to enable parsing of these.
445case promParser.LIMITK:
446s = walkNode(expr, n.Expr)
447s.Type = AggregateSource
448s.Operation = "limitk"
449case promParser.LIMIT_RATIO:
450s = walkNode(expr, n.Expr)
451s.Type = AggregateSource
452s.Operation = "limit_ratio"
453*/
454}
455return src
456}
457
458func parseAggregation(expr string, n *promParser.AggregateExpr) (src []Source) {
459var s Source
460for _, s = range walkNode(expr, n.Expr) {
461if n.Without {
17fb6517Lukasz Mierzwa1 years ago462s = excludeLabel(s, n.Grouping...)
2bc6b9e5Lukasz Mierzwa1 years ago463for _, name := range n.Grouping {
f97e7fc2Lukasz Mierzwa1 years ago464s.ExcludeReason = setInMap(
465s.ExcludeReason,
466name,
467ExcludedLabel{
468Reason: fmt.Sprintf("Query is using aggregation with `without(%s)`, all labels included inside `without(...)` will be removed from the results.",
469strings.Join(n.Grouping, ", ")),
b7f6e358Lukasz Mierzwa1 years ago470Fragment: FindPosition(expr, n.PosRange, "without"),
f97e7fc2Lukasz Mierzwa1 years ago471},
472)
473}
474} else {
475if len(n.Grouping) == 0 {
476s.IncludedLabels = nil
477s.GuaranteedLabels = nil
478s.ExcludeReason = setInMap(
479s.ExcludeReason,
480"",
481ExcludedLabel{
482Reason: "Query is using aggregation that removes all labels.",
b7f6e358Lukasz Mierzwa1 years ago483Fragment: FindPosition(expr, n.PosRange, "sum"),
f97e7fc2Lukasz Mierzwa1 years ago484},
485)
486} else {
1887ad0aLukasz Mierzwa1 years ago487// Check if source of labels already fixes them.
488if !s.FixedLabels {
91a38afdLukasz Mierzwa1 years ago489s = maybeIncludeLabel(s, n.Grouping...)
1887ad0aLukasz Mierzwa1 years ago490s.ExcludeReason = setInMap(
491s.ExcludeReason,
492"",
493ExcludedLabel{
494Reason: fmt.Sprintf("Query is using aggregation with `by(%s)`, only labels included inside `by(...)` will be present on the results.",
495strings.Join(n.Grouping, ", ")),
b7f6e358Lukasz Mierzwa1 years ago496Fragment: FindPosition(expr, n.PosRange, "by"),
1887ad0aLukasz Mierzwa1 years ago497},
498)
499}
c269e3b9Lukasz Mierzwa1 years ago500s = restrictGuaranteedLabels(s, n.Grouping)
45b5cf5eLukasz Mierzwa1 years ago501s = restrictIncludedLabels(s, n.Grouping)
2bc6b9e5Lukasz Mierzwa1 years ago502}
1887ad0aLukasz Mierzwa1 years ago503s.FixedLabels = true
2bc6b9e5Lukasz Mierzwa1 years ago504}
f97e7fc2Lukasz Mierzwa1 years ago505s.Type = AggregateSource
506s.Returns = promParser.ValueTypeVector
507src = append(src, s)
2bc6b9e5Lukasz Mierzwa1 years ago508}
f97e7fc2Lukasz Mierzwa1 years ago509return src
2bc6b9e5Lukasz Mierzwa1 years ago510}
511
17fb6517Lukasz Mierzwa1 years ago512func parsePromQLFunc(s Source, expr string, n *promParser.Call) Source {
0fff8c1eLukasz Mierzwa1 years ago513switch n.Func.Name {
514case "abs", "sgn", "acos", "acosh", "asin", "asinh", "atan", "atanh", "cos", "cosh", "sin", "sinh", "tan", "tanh":
515// No change to labels.
516s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago517s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago518
519case "ceil", "floor", "round":
520// No change to labels.
521s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago522s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago523
524case "changes", "resets":
525// No change to labels.
526s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago527s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago528
529case "clamp", "clamp_max", "clamp_min":
530// No change to labels.
531s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago532s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago533
534case "absent", "absent_over_time":
535s.Returns = promParser.ValueTypeVector
2bc6b9e5Lukasz Mierzwa1 years ago536s.FixedLabels = true
17fb6517Lukasz Mierzwa1 years ago537s.IncludedLabels = nil
538s.GuaranteedLabels = nil
bd876148Lukasz Mierzwa1 years ago539for _, name := range labelsFromSelectors([]labels.MatchType{labels.MatchEqual}, s.Selector) {
17fb6517Lukasz Mierzwa1 years ago540s = includeLabel(s, name)
541s = guaranteeLabel(s, name)
2bc6b9e5Lukasz Mierzwa1 years ago542}
1887ad0aLukasz Mierzwa1 years ago543s.ExcludeReason = setInMap(
544s.ExcludeReason,
545"",
546ExcludedLabel{
547Reason: fmt.Sprintf(`The [%s()](https://prometheus.io/docs/prometheus/latest/querying/functions/#%s) function is used to check if provided query doesn't match any time series.
548You will only get any results back if the metric selector you pass doesn't match anything.
549Since there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.
550This means that the only labels you can get back from absent call are the ones you pass to it.
551If you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `+"`up`"+` metric instead.`,
552n.Func.Name, n.Func.Name),
b7f6e358Lukasz Mierzwa1 years ago553Fragment: FindPosition(expr, n.PosRange, n.Func.Name),
1887ad0aLukasz Mierzwa1 years ago554},
555)
0fff8c1eLukasz Mierzwa1 years ago556
557case "avg_over_time", "count_over_time", "last_over_time", "max_over_time", "min_over_time", "present_over_time", "quantile_over_time", "stddev_over_time", "stdvar_over_time", "sum_over_time":
558// No change to labels.
559s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago560s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago561
562case "days_in_month", "day_of_month", "day_of_week", "day_of_year", "hour", "minute", "month", "year":
563s.Returns = promParser.ValueTypeVector
564// No labels if we don't pass any arguments.
565// Otherwise no change to labels.
566if len(s.Call.Args) == 0 {
567s.FixedLabels = true
aaea75cfLukasz Mierzwa1 years ago568s.AlwaysReturns = true
1887ad0aLukasz Mierzwa1 years ago569s.IncludedLabels = nil
570s.GuaranteedLabels = nil
571s.ExcludeReason = setInMap(
572s.ExcludeReason,
573"",
574ExcludedLabel{
575Reason: fmt.Sprintf("Calling `%s()` with no arguments will return an empty time series with no labels.",
576n.Func.Name),
f7d9a38aLukasz Mierzwa1 years ago577Fragment: n.PosRange,
1887ad0aLukasz Mierzwa1 years ago578},
579)
0fff8c1eLukasz Mierzwa1 years ago580} else {
bd876148Lukasz Mierzwa1 years ago581s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago582}
583
584case "deg", "rad", "ln", "log10", "log2", "sqrt", "exp":
585// No change to labels.
586s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago587s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago588
589case "delta", "idelta", "increase", "deriv", "irate", "rate":
590// No change to labels.
591s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago592s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago593
594case "histogram_avg", "histogram_count", "histogram_sum", "histogram_stddev", "histogram_stdvar", "histogram_fraction", "histogram_quantile":
595// No change to labels.
596s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago597s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago598
599case "holt_winters", "predict_linear":
600// No change to labels.
601s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago602s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago603
604case "label_replace", "label_join":
605// One label added to the results.
606s.Returns = promParser.ValueTypeVector
6144bc7bLukasz Mierzwa1 years ago607s = guaranteeLabel(s, n.Args[1].(*promParser.StringLiteral).Val)
0fff8c1eLukasz Mierzwa1 years ago608
609case "pi":
610s.Returns = promParser.ValueTypeScalar
1887ad0aLukasz Mierzwa1 years ago611s.IncludedLabels = nil
612s.GuaranteedLabels = nil
0fff8c1eLukasz Mierzwa1 years ago613s.FixedLabels = true
aaea75cfLukasz Mierzwa1 years ago614s.AlwaysReturns = true
1887ad0aLukasz Mierzwa1 years ago615s.ExcludeReason = setInMap(
616s.ExcludeReason,
617"",
618ExcludedLabel{
619Reason: fmt.Sprintf("Calling `%s()` will return a scalar value with no labels.", n.Func.Name),
f7d9a38aLukasz Mierzwa1 years ago620Fragment: n.PosRange,
1887ad0aLukasz Mierzwa1 years ago621},
622)
0fff8c1eLukasz Mierzwa1 years ago623
624case "scalar":
625s.Returns = promParser.ValueTypeScalar
1887ad0aLukasz Mierzwa1 years ago626s.IncludedLabels = nil
627s.GuaranteedLabels = nil
0fff8c1eLukasz Mierzwa1 years ago628s.FixedLabels = true
aaea75cfLukasz Mierzwa1 years ago629s.AlwaysReturns = true
1887ad0aLukasz Mierzwa1 years ago630s.ExcludeReason = setInMap(
631s.ExcludeReason,
632"",
633ExcludedLabel{
634Reason: fmt.Sprintf("Calling `%s()` will return a scalar value with no labels.", n.Func.Name),
b7f6e358Lukasz Mierzwa1 years ago635Fragment: FindPosition(expr, n.PositionRange(), n.Func.Name),
1887ad0aLukasz Mierzwa1 years ago636},
637)
0fff8c1eLukasz Mierzwa1 years ago638
639case "sort", "sort_desc":
640// No change to labels.
641s.Returns = promParser.ValueTypeVector
642
643case "time":
644s.Returns = promParser.ValueTypeScalar
1887ad0aLukasz Mierzwa1 years ago645s.IncludedLabels = nil
646s.GuaranteedLabels = nil
0fff8c1eLukasz Mierzwa1 years ago647s.FixedLabels = true
aaea75cfLukasz Mierzwa1 years ago648s.AlwaysReturns = true
1887ad0aLukasz Mierzwa1 years ago649s.ExcludeReason = setInMap(
650s.ExcludeReason,
651"",
652ExcludedLabel{
653Reason: fmt.Sprintf("Calling `%s()` will return a scalar value with no labels.", n.Func.Name),
f7d9a38aLukasz Mierzwa1 years ago654Fragment: n.PosRange,
1887ad0aLukasz Mierzwa1 years ago655},
656)
0fff8c1eLukasz Mierzwa1 years ago657
658case "timestamp":
659// No change to labels.
660s.Returns = promParser.ValueTypeVector
bd876148Lukasz Mierzwa1 years ago661s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...)
0fff8c1eLukasz Mierzwa1 years ago662
663case "vector":
664s.Returns = promParser.ValueTypeVector
1887ad0aLukasz Mierzwa1 years ago665s.IncludedLabels = nil
666s.GuaranteedLabels = nil
0fff8c1eLukasz Mierzwa1 years ago667s.FixedLabels = true
aaea75cfLukasz Mierzwa1 years ago668s.AlwaysReturns = true
f7d9a38aLukasz Mierzwa1 years ago669for _, vs := range walkNode(expr, n.Args[0]) {
73d0e49eLukasz Mierzwa1 years ago670if vs.KnownReturn {
f7d9a38aLukasz Mierzwa1 years ago671s.ReturnedNumber = vs.ReturnedNumber
73d0e49eLukasz Mierzwa1 years ago672s.KnownReturn = true
f7d9a38aLukasz Mierzwa1 years ago673}
f481b96aLukasz Mierzwa1 years ago674}
1887ad0aLukasz Mierzwa1 years ago675s.ExcludeReason = setInMap(
676s.ExcludeReason,
677"",
678ExcludedLabel{
679Reason: fmt.Sprintf("Calling `%s()` will return a vector value with no labels.", n.Func.Name),
b7f6e358Lukasz Mierzwa1 years ago680Fragment: FindPosition(expr, n.PosRange, n.Func.Name),
1887ad0aLukasz Mierzwa1 years ago681},
682)
0fff8c1eLukasz Mierzwa1 years ago683
684default:
685// Unsupported function
686s.Returns = promParser.ValueTypeNone
687s.Call = nil
2bc6b9e5Lukasz Mierzwa1 years ago688}
689return s
690}
13c2f1c2Lukasz Mierzwa1 years ago691
17fb6517Lukasz Mierzwa1 years ago692func parseCall(expr string, n *promParser.Call) (src []Source) {
693var vt promParser.ValueType
694for i, e := range n.Args {
695if i >= len(n.Func.ArgTypes) {
696vt = n.Func.ArgTypes[len(n.Func.ArgTypes)-1]
697} else {
698vt = n.Func.ArgTypes[i]
699}
700
701switch vt {
702case promParser.ValueTypeVector, promParser.ValueTypeMatrix:
703for _, es := range walkNode(expr, e) {
704es.Type = FuncSource
705es.Operation = n.Func.Name
706es.Call = n
707src = append(src, parsePromQLFunc(es, expr, n))
708}
709case promParser.ValueTypeNone, promParser.ValueTypeScalar, promParser.ValueTypeString:
710}
711}
712
713if len(src) == 0 {
714var s Source
715s.Type = FuncSource
716s.Operation = n.Func.Name
717s.Call = n
1bca8feeLukasz Mierzwa1 years ago718s.Position = n.PosRange
17fb6517Lukasz Mierzwa1 years ago719src = append(src, parsePromQLFunc(s, expr, n))
720}
721
722return src
723}
724
f97e7fc2Lukasz Mierzwa1 years ago725func parseBinOps(expr string, n *promParser.BinaryExpr) (src []Source) {
726var s Source
13c2f1c2Lukasz Mierzwa1 years ago727switch {
aaea75cfLukasz Mierzwa1 years ago728
729// foo{} + 1
730// 1 + foo{}
731// foo{} > 1
732// 1 > foo{}
13c2f1c2Lukasz Mierzwa1 years ago733case n.VectorMatching == nil:
aaea75cfLukasz Mierzwa1 years ago734lhs := walkNode(expr, n.LHS)
735rhs := walkNode(expr, n.RHS)
736for _, ls := range lhs {
bf45639fLukasz Mierzwa1 years ago737ls.IsConditional = isConditional(ls, n.Op)
aaea75cfLukasz Mierzwa1 years ago738for _, rs := range rhs {
bf45639fLukasz Mierzwa1 years ago739rs.IsConditional = isConditional(rs, n.Op)
171c7f7eLukasz Mierzwa1 years ago740var side Source
aaea75cfLukasz Mierzwa1 years ago741switch {
171c7f7eLukasz Mierzwa1 years ago742case ls.Returns == promParser.ValueTypeVector, ls.Returns == promParser.ValueTypeMatrix:
743// Use labels from LHS
744side = ls
745case rs.Returns == promParser.ValueTypeVector, rs.Returns == promParser.ValueTypeMatrix:
746// Use labels from RHS
747side = rs
748default:
749side = ls
750}
751if ls.AlwaysReturns && rs.AlwaysReturns && ls.KnownReturn && rs.KnownReturn {
aaea75cfLukasz Mierzwa1 years ago752// Both sides always return something
171c7f7eLukasz Mierzwa1 years ago753side.ReturnedNumber, side.IsDead, side.IsDeadReason = calculateStaticReturn(
c269e3b9Lukasz Mierzwa1 years ago754expr,
755ls, rs,
756n.Op,
757ls.IsDead,
758)
1887ad0aLukasz Mierzwa1 years ago759}
171c7f7eLukasz Mierzwa1 years ago760src = append(src, side)
1887ad0aLukasz Mierzwa1 years ago761}
762}
13c2f1c2Lukasz Mierzwa1 years ago763
128fada0Lukasz Mierzwa1 years ago764// foo{} + bar{}
765// foo{} + on(...) bar{}
766// foo{} + ignoring(...) bar{}
17fb6517Lukasz Mierzwa1 years ago767// foo{} / bar{}
13c2f1c2Lukasz Mierzwa1 years ago768case n.VectorMatching.Card == promParser.CardOneToOne:
17fb6517Lukasz Mierzwa1 years ago769rhs := walkNode(expr, n.RHS)
f97e7fc2Lukasz Mierzwa1 years ago770for _, s = range walkNode(expr, n.LHS) {
771if n.VectorMatching.On {
772s.FixedLabels = true
17fb6517Lukasz Mierzwa1 years ago773s = includeLabel(s, n.VectorMatching.MatchingLabels...)
c0e1a8c4Lukasz Mierzwa1 years ago774s = restrictIncludedLabels(s, n.VectorMatching.MatchingLabels)
775s = restrictGuaranteedLabels(s, n.VectorMatching.MatchingLabels)
1331c38cLukasz Mierzwa1 years ago776s.ExcludeReason = setInMap(
777s.ExcludeReason,
f97e7fc2Lukasz Mierzwa1 years ago778"",
1331c38cLukasz Mierzwa1 years ago779ExcludedLabel{
780Reason: fmt.Sprintf(
f97e7fc2Lukasz Mierzwa1 years ago781"Query is using %s vector matching with `on(%s)`, only labels included inside `on(...)` will be present on the results.",
1331c38cLukasz Mierzwa1 years ago782n.VectorMatching.Card, strings.Join(n.VectorMatching.MatchingLabels, ", "),
783),
b7f6e358Lukasz Mierzwa1 years ago784Fragment: FindPosition(expr, n.PositionRange(), "on"),
1331c38cLukasz Mierzwa1 years ago785},
786)
f97e7fc2Lukasz Mierzwa1 years ago787} else {
17fb6517Lukasz Mierzwa1 years ago788s = excludeLabel(s, n.VectorMatching.MatchingLabels...)
f97e7fc2Lukasz Mierzwa1 years ago789for _, name := range n.VectorMatching.MatchingLabels {
790s.ExcludeReason = setInMap(
791s.ExcludeReason,
792name,
793ExcludedLabel{
794Reason: fmt.Sprintf(
795"Query is using %s vector matching with `ignoring(%s)`, all labels included inside `ignoring(...)` will be removed on the results.",
796n.VectorMatching.Card, strings.Join(n.VectorMatching.MatchingLabels, ", "),
797),
b7f6e358Lukasz Mierzwa1 years ago798Fragment: FindPosition(expr, n.PositionRange(), "ignoring"),
f97e7fc2Lukasz Mierzwa1 years ago799},
800)
801}
993781f3Lukasz Mierzwa1 years ago802for _, rs := range rhs {
bf45639fLukasz Mierzwa1 years ago803rs.IsConditional = isConditional(rs, n.Op)
73d0e49eLukasz Mierzwa1 years ago804if s.AlwaysReturns && rs.AlwaysReturns && s.KnownReturn && rs.KnownReturn {
993781f3Lukasz Mierzwa1 years ago805// Both sides always return something
806s.ReturnedNumber, s.IsDead, s.IsDeadReason = calculateStaticReturn(
807expr,
808s, rs,
809n.Op,
810s.IsDead,
811)
812}
813}
f97e7fc2Lukasz Mierzwa1 years ago814}
815if s.Operation == "" {
816s.Operation = n.VectorMatching.Card.String()
128fada0Lukasz Mierzwa1 years ago817}
c269e3b9Lukasz Mierzwa1 years ago818for _, rs := range rhs {
819if ok, s := canJoin(s, rs, n.VectorMatching); !ok {
820rs.IsDead = true
821rs.IsDeadReason = s
822}
823s.Joins = append(s.Joins, Join{
824Src: rs,
825})
826}
bf45639fLukasz Mierzwa1 years ago827s.IsConditional = isConditional(s, n.Op)
f97e7fc2Lukasz Mierzwa1 years ago828src = append(src, s)
13c2f1c2Lukasz Mierzwa1 years ago829}
830
c269e3b9Lukasz Mierzwa1 years ago831// foo{} + on(...) group_right(...) bar{}
832// foo{} + ignoring(...) group_right(...) bar{}
13c2f1c2Lukasz Mierzwa1 years ago833case n.VectorMatching.Card == promParser.CardOneToMany:
17fb6517Lukasz Mierzwa1 years ago834lhs := walkNode(expr, n.LHS)
f97e7fc2Lukasz Mierzwa1 years ago835for _, s = range walkNode(expr, n.RHS) {
17fb6517Lukasz Mierzwa1 years ago836s = includeLabel(s, n.VectorMatching.Include...)
c269e3b9Lukasz Mierzwa1 years ago837// If we have:
838// foo * on(instance) group_left(a,b) bar{x="y"}
839// then only group_left() labels will be included.
f97e7fc2Lukasz Mierzwa1 years ago840if n.VectorMatching.On {
17fb6517Lukasz Mierzwa1 years ago841s = includeLabel(s, n.VectorMatching.MatchingLabels...)
128fada0Lukasz Mierzwa1 years ago842}
f97e7fc2Lukasz Mierzwa1 years ago843if s.Operation == "" {
844s.Operation = n.VectorMatching.Card.String()
845}
c269e3b9Lukasz Mierzwa1 years ago846for _, ls := range lhs {
847if ok, s := canJoin(s, ls, n.VectorMatching); !ok {
848ls.IsDead = true
849ls.IsDeadReason = s
850}
851s.Joins = append(s.Joins, Join{
852Src: ls,
853})
854}
bf45639fLukasz Mierzwa1 years ago855s.IsConditional = isConditional(s, n.Op)
f97e7fc2Lukasz Mierzwa1 years ago856src = append(src, s)
13c2f1c2Lukasz Mierzwa1 years ago857}
858
c269e3b9Lukasz Mierzwa1 years ago859// foo{} + on(...) group_left(...) bar{}
860// foo{} + ignoring(...) group_left(...) bar{}
13c2f1c2Lukasz Mierzwa1 years ago861case n.VectorMatching.Card == promParser.CardManyToOne:
17fb6517Lukasz Mierzwa1 years ago862rhs := walkNode(expr, n.RHS)
f97e7fc2Lukasz Mierzwa1 years ago863for _, s = range walkNode(expr, n.LHS) {
17fb6517Lukasz Mierzwa1 years ago864s = includeLabel(s, n.VectorMatching.Include...)
f97e7fc2Lukasz Mierzwa1 years ago865if n.VectorMatching.On {
17fb6517Lukasz Mierzwa1 years ago866s = includeLabel(s, n.VectorMatching.MatchingLabels...)
13c2f1c2Lukasz Mierzwa1 years ago867}
f97e7fc2Lukasz Mierzwa1 years ago868if s.Operation == "" {
869s.Operation = n.VectorMatching.Card.String()
870}
c269e3b9Lukasz Mierzwa1 years ago871for _, rs := range rhs {
872if ok, s := canJoin(s, rs, n.VectorMatching); !ok {
873rs.IsDead = true
874rs.IsDeadReason = s
875}
876s.Joins = append(s.Joins, Join{
877Src: rs,
878})
879}
bf45639fLukasz Mierzwa1 years ago880s.IsConditional = isConditional(s, n.Op)
f97e7fc2Lukasz Mierzwa1 years ago881src = append(src, s)
13c2f1c2Lukasz Mierzwa1 years ago882}
128fada0Lukasz Mierzwa1 years ago883
884// foo{} and on(...) bar{}
885// foo{} and ignoring(...) bar{}
17fb6517Lukasz Mierzwa1 years ago886// foo{} unless bar{}
128fada0Lukasz Mierzwa1 years ago887case n.VectorMatching.Card == promParser.CardManyToMany:
aaea75cfLukasz Mierzwa1 years ago888var lhsCanBeEmpty bool // true if any of the LHS query can produce empty results.
17fb6517Lukasz Mierzwa1 years ago889rhs := walkNode(expr, n.RHS)
f97e7fc2Lukasz Mierzwa1 years ago890for _, s = range walkNode(expr, n.LHS) {
bf45639fLukasz Mierzwa1 years ago891var rhsConditional bool
f97e7fc2Lukasz Mierzwa1 years ago892if n.VectorMatching.On {
17fb6517Lukasz Mierzwa1 years ago893s = includeLabel(s, n.VectorMatching.MatchingLabels...)
f97e7fc2Lukasz Mierzwa1 years ago894}
895if s.Operation == "" {
896s.Operation = n.VectorMatching.Card.String()
128fada0Lukasz Mierzwa1 years ago897}
ee5af5fbLukasz Mierzwa1 years ago898if !s.AlwaysReturns || s.IsConditional {
aaea75cfLukasz Mierzwa1 years ago899lhsCanBeEmpty = true
900}
c269e3b9Lukasz Mierzwa1 years ago901for _, rs := range rhs {
bf45639fLukasz Mierzwa1 years ago902if isConditional(rs, n.Op) {
903rhsConditional = true
904}
c269e3b9Lukasz Mierzwa1 years ago905if ok, s := canJoin(s, rs, n.VectorMatching); !ok {
906rs.IsDead = true
907rs.IsDeadReason = s
908}
909switch {
910case n.Op == promParser.LUNLESS:
947a0055Lukasz Mierzwa1 years ago911if n.VectorMatching.On && len(n.VectorMatching.MatchingLabels) == 0 && rs.AlwaysReturns && !rs.IsConditional {
c269e3b9Lukasz Mierzwa1 years ago912s.IsDead = true
913s.IsDeadReason = "this query will never return anything because the `unless` query always returns something"
914}
915s.Unless = append(s.Unless, Join{
916Src: rs,
917})
918case n.Op != promParser.LOR:
919s.Joins = append(s.Joins, Join{
920Src: rs,
921})
922}
17fb6517Lukasz Mierzwa1 years ago923}
bf45639fLukasz Mierzwa1 years ago924if n.Op == promParser.LAND && rhsConditional {
925s.IsConditional = true
926}
f97e7fc2Lukasz Mierzwa1 years ago927src = append(src, s)
128fada0Lukasz Mierzwa1 years ago928}
929if n.Op == promParser.LOR {
17fb6517Lukasz Mierzwa1 years ago930for _, s = range rhs {
f97e7fc2Lukasz Mierzwa1 years ago931if s.Operation == "" {
932s.Operation = n.VectorMatching.Card.String()
933}
aaea75cfLukasz Mierzwa1 years ago934// If LHS can NOT be empty then RHS is dead code.
935if !lhsCanBeEmpty {
936s.IsDead = true
c269e3b9Lukasz Mierzwa1 years ago937s.IsDeadReason = "the left hand side always returs something and so the right hand side is never used"
aaea75cfLukasz Mierzwa1 years ago938}
f97e7fc2Lukasz Mierzwa1 years ago939src = append(src, s)
940}
128fada0Lukasz Mierzwa1 years ago941}
942}
f97e7fc2Lukasz Mierzwa1 years ago943return src
13c2f1c2Lukasz Mierzwa1 years ago944}
aaea75cfLukasz Mierzwa1 years ago945
bf45639fLukasz Mierzwa1 years ago946func isConditional(s Source, op promParser.ItemType) bool {
947if s.IsConditional {
948return true
949}
950return op.IsComparisonOperator()
951}
952
c269e3b9Lukasz Mierzwa1 years ago953func canJoin(ls, rs Source, vm *promParser.VectorMatching) (bool, string) {
954var side string
955if vm.Card == promParser.CardOneToMany {
956side = "left"
957} else {
958side = "right"
959}
960
961switch {
962case vm.On && len(vm.MatchingLabels) == 0: // ls on() unless rs
963return true, ""
964case vm.On: // ls on(...) unless rs
965for _, name := range vm.MatchingLabels {
1bca8feeLukasz Mierzwa1 years ago966if ls.CanHaveLabel(name) && !rs.CanHaveLabel(name) {
947a0055Lukasz Mierzwa1 years ago967return false, fmt.Sprintf("The %s hand side will never be matched because it doesn't have the `%s` label from `on(...)`. %s",
968side, name, rs.LabelExcludeReason(name).Reason)
c269e3b9Lukasz Mierzwa1 years ago969}
970}
971default: // ls unless rs
972for _, name := range ls.GuaranteedLabels {
1bca8feeLukasz Mierzwa1 years ago973if ls.CanHaveLabel(name) && !rs.CanHaveLabel(name) {
947a0055Lukasz Mierzwa1 years ago974return false, fmt.Sprintf("The %s hand side will never be matched because it doesn't have the `%s` label while the left hand side will. %s",
975side, name, rs.LabelExcludeReason(name).Reason)
c269e3b9Lukasz Mierzwa1 years ago976}
977}
978}
979return true, ""
980}
981
982func ftos(v float64) string {
983return strconv.FormatFloat(v, 'f', -1, 64)
984}
985
986func calculateStaticReturn(expr string, ls, rs Source, op promParser.ItemType, isDead bool) (float64, bool, string) {
987lf := ls.Fragment(expr)
988rf := rs.Fragment(expr)
989var cmpPrefix string
990if lf != "" && rf != "" {
991cmpPrefix = fmt.Sprintf("`%s %s %s` always evaluates to", lf, op, rf)
992} else {
993cmpPrefix = "this query always evaluates to"
994}
995cmpSuffix := "which is not possible, so it will never return anything"
aaea75cfLukasz Mierzwa1 years ago996switch op {
997case promParser.EQLC:
c269e3b9Lukasz Mierzwa1 years ago998if ls.ReturnedNumber != rs.ReturnedNumber {
999return ls.ReturnedNumber, true, fmt.Sprintf("%s `%s == %s` %s", cmpPrefix, ftos(ls.ReturnedNumber), ftos(rs.ReturnedNumber), cmpSuffix)
aaea75cfLukasz Mierzwa1 years ago1000}
1001case promParser.NEQ:
c269e3b9Lukasz Mierzwa1 years ago1002if ls.ReturnedNumber == rs.ReturnedNumber {
1003return ls.ReturnedNumber, true, fmt.Sprintf("%s `%s != %s` %s", cmpPrefix, ftos(ls.ReturnedNumber), ftos(rs.ReturnedNumber), cmpSuffix)
aaea75cfLukasz Mierzwa1 years ago1004}
1005case promParser.LTE:
c269e3b9Lukasz Mierzwa1 years ago1006if ls.ReturnedNumber > rs.ReturnedNumber {
1007return ls.ReturnedNumber, true, fmt.Sprintf("%s `%s <= %s` %s", cmpPrefix, ftos(ls.ReturnedNumber), ftos(rs.ReturnedNumber), cmpSuffix)
aaea75cfLukasz Mierzwa1 years ago1008}
1009case promParser.LSS:
c269e3b9Lukasz Mierzwa1 years ago1010if ls.ReturnedNumber >= rs.ReturnedNumber {
1011return ls.ReturnedNumber, true, fmt.Sprintf("%s `%s < %s` %s", cmpPrefix, ftos(ls.ReturnedNumber), ftos(rs.ReturnedNumber), cmpSuffix)
aaea75cfLukasz Mierzwa1 years ago1012}
1013case promParser.GTE:
c269e3b9Lukasz Mierzwa1 years ago1014if ls.ReturnedNumber < rs.ReturnedNumber {
1015return ls.ReturnedNumber, true, fmt.Sprintf("%s `%s >= %s` %s", cmpPrefix, ftos(ls.ReturnedNumber), ftos(rs.ReturnedNumber), cmpSuffix)
aaea75cfLukasz Mierzwa1 years ago1016}
1017case promParser.GTR:
c269e3b9Lukasz Mierzwa1 years ago1018if ls.ReturnedNumber <= rs.ReturnedNumber {
1019return ls.ReturnedNumber, true, fmt.Sprintf("%s `%s > %s` %s", cmpPrefix, ftos(ls.ReturnedNumber), ftos(rs.ReturnedNumber), cmpSuffix)
aaea75cfLukasz Mierzwa1 years ago1020}
1021case promParser.ADD:
c269e3b9Lukasz Mierzwa1 years ago1022return ls.ReturnedNumber + rs.ReturnedNumber, isDead, ""
aaea75cfLukasz Mierzwa1 years ago1023case promParser.SUB:
c269e3b9Lukasz Mierzwa1 years ago1024return ls.ReturnedNumber - rs.ReturnedNumber, isDead, ""
aaea75cfLukasz Mierzwa1 years ago1025case promParser.MUL:
c269e3b9Lukasz Mierzwa1 years ago1026return ls.ReturnedNumber * rs.ReturnedNumber, isDead, ""
aaea75cfLukasz Mierzwa1 years ago1027case promParser.DIV:
c269e3b9Lukasz Mierzwa1 years ago1028return ls.ReturnedNumber / rs.ReturnedNumber, isDead, ""
aaea75cfLukasz Mierzwa1 years ago1029case promParser.MOD:
c269e3b9Lukasz Mierzwa1 years ago1030return math.Mod(ls.ReturnedNumber, rs.ReturnedNumber), isDead, ""
aaea75cfLukasz Mierzwa1 years ago1031case promParser.POW:
c269e3b9Lukasz Mierzwa1 years ago1032return math.Pow(ls.ReturnedNumber, rs.ReturnedNumber), isDead, ""
aaea75cfLukasz Mierzwa1 years ago1033}
c269e3b9Lukasz Mierzwa1 years ago1034return ls.ReturnedNumber, isDead, ""
aaea75cfLukasz Mierzwa1 years ago1035}
f7d9a38aLukasz Mierzwa1 years ago1036
1037// FIXME sum() on ().
b7f6e358Lukasz Mierzwa1 years ago1038func FindPosition(expr string, within posrange.PositionRange, fn string) posrange.PositionRange {
7b0ce529Lukasz Mierzwa1 years ago1039re := regexp.MustCompile("(?i)(" + regexp.QuoteMeta(fn) + ")[ \n\t]*\\(")
f7d9a38aLukasz Mierzwa1 years ago1040idx := re.FindStringSubmatchIndex(GetQueryFragment(expr, within))
1041if idx == nil {
1042return within
1043}
1044return posrange.PositionRange{
1045Start: within.Start + posrange.Pos(idx[0]),
efdc4479Lukasz Mierzwa1 years ago1046End: within.Start + posrange.Pos(idx[1]-1),
f7d9a38aLukasz Mierzwa1 years ago1047}
1048}