SQL Expressions / Alerting: Do not allow duplicates (#103394)

This commit is contained in:
Kyle Brandt
2025-04-04 10:00:30 -04:00
committed by GitHub
parent 3766deed34
commit b1490a10e8
3 changed files with 164 additions and 12 deletions

View File

@ -182,6 +182,20 @@ func totalCells(frames []*data.Frame) (total int64) {
return
}
// extractNumberSetFromSQLForAlerting converts a data frame produced by a SQL expression
// into a slice of mathexp.Number values for use in alerting.
//
// This function enforces strict semantics: each row must have exactly one numeric value
// and a unique label set. If any label set appears more than once, an error is returned.
//
// It is the responsibility of the SQL query to ensure uniqueness — for example, by
// applying GROUP BY or aggregation clauses. This function will not deduplicate rows;
// it will reject the entire input if any duplicates are present.
//
// Returns an error if:
// - No numeric field is found.
// - More than one numeric field exists.
// - Any label set appears more than once.
func extractNumberSetFromSQLForAlerting(frame *data.Frame) ([]mathexp.Number, error) {
var (
numericField *data.Field
@ -202,7 +216,13 @@ func extractNumberSetFromSQLForAlerting(frame *data.Frame) ([]mathexp.Number, er
return nil, fmt.Errorf("no numeric field found in frame")
}
numbers := make([]mathexp.Number, frame.Rows())
type row struct {
value float64
labels data.Labels
}
rows := make([]row, 0, frame.Rows())
counts := map[data.Fingerprint]int{}
labelMap := map[data.Fingerprint]string{}
for i := 0; i < frame.Rows(); i++ {
val, err := numericField.FloatAt(i)
@ -227,10 +247,32 @@ func extractNumberSetFromSQLForAlerting(frame *data.Frame) ([]mathexp.Number, er
}
}
n := mathexp.NewNumber(numericField.Name, labels)
fp := labels.Fingerprint()
counts[fp]++
labelMap[fp] = labels.String()
rows = append(rows, row{value: val, labels: labels})
}
// Check for any duplicates
duplicates := make([]string, 0)
for fp, count := range counts {
if count > 1 {
duplicates = append(duplicates, labelMap[fp])
}
}
if len(duplicates) > 0 {
return nil, makeDuplicateStringColumnError(duplicates)
}
// Build final result
numbers := make([]mathexp.Number, 0, len(rows))
for _, r := range rows {
n := mathexp.NewNumber(numericField.Name, r.labels)
n.Frame.Fields[0].Config = numericField.Config
n.SetValue(&val)
numbers[i] = n
n.SetValue(&r.value)
numbers = append(numbers, n)
}
return numbers, nil