Skip to content

Commit 7c398a9

Browse files
fix: SQLPatternMatcher duration (#315)
1 parent 04b4615 commit 7c398a9

2 files changed

Lines changed: 100 additions & 3 deletions

File tree

‎asap-common/dependencies/rs/sql_utilities/src/ast_matching/sqlparser_test.rs‎

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,4 +646,101 @@ mod tests {
646646
"SELECT AVG(value) FROM cpu_usage WHERE time BETWEEN DATEADD(s, -10, NOW()) AND NOW() GROUP BY L1, L2 ORDER BY L1"
647647
).is_none());
648648
}
649+
650+
// ── scrape_interval > 1s regression tests (issue #201) ───────────────────
651+
652+
fn check_query_with_interval(
653+
sql: &str,
654+
scrape_interval: f64,
655+
expected_types: Vec<QueryType>,
656+
expected_error: Option<QueryError>,
657+
) {
658+
let schema = create_test_schema();
659+
let matcher = SQLPatternMatcher::new(schema, scrape_interval);
660+
let query_data =
661+
parse_sql_query(sql).unwrap_or_else(|| panic!("Failed to parse query: {}", sql));
662+
let result = matcher.query_info_to_pattern(&query_data);
663+
assert_eq!(result.query_type, expected_types);
664+
assert_eq!(result.error, expected_error);
665+
}
666+
667+
/// scraped_intervals = 15/15 = 1.0; bug fires 1.0 < 15.0 → false positive error
668+
#[test]
669+
fn test_bug_201_single_interval_spatial_query_not_rejected() {
670+
check_query_with_interval(
671+
"SELECT AVG(value) FROM cpu_usage \
672+
WHERE time BETWEEN DATEADD(s, -15, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
673+
GROUP BY L1, L2, L3, L4",
674+
15.0,
675+
vec![QueryType::Spatial],
676+
None,
677+
);
678+
}
679+
680+
/// scraped_intervals = 30/15 = 2.0; bug fires 2.0 < 15.0 → false positive error
681+
#[test]
682+
fn test_bug_201_two_interval_temporal_query_not_rejected() {
683+
check_query_with_interval(
684+
"SELECT SUM(value) FROM cpu_usage \
685+
WHERE time BETWEEN DATEADD(s, -30, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
686+
GROUP BY L1, L2, L3, L4",
687+
15.0,
688+
vec![QueryType::TemporalGeneric],
689+
None,
690+
);
691+
}
692+
693+
/// scraped_intervals = 30/15 = 2.0 with QUANTILE agg → TemporalQuantile
694+
#[test]
695+
fn test_bug_201_temporal_quantile_not_rejected() {
696+
check_query_with_interval(
697+
"SELECT QUANTILE(0.95, value) FROM cpu_usage \
698+
WHERE time BETWEEN DATEADD(s, -30, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
699+
GROUP BY L1, L2, L3, L4",
700+
15.0,
701+
vec![QueryType::TemporalQuantile],
702+
None,
703+
);
704+
}
705+
706+
/// scraped_intervals = 30/15 = 2.0 with subset of labels → SpatioTemporal
707+
#[test]
708+
fn test_bug_201_spatiotemporal_not_rejected() {
709+
check_query_with_interval(
710+
"SELECT SUM(value) FROM cpu_usage \
711+
WHERE time BETWEEN DATEADD(s, -30, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
712+
GROUP BY L1",
713+
15.0,
714+
vec![QueryType::SpatioTemporal],
715+
None,
716+
);
717+
}
718+
719+
/// Spatial-of-temporal: outer has UNUSED time (not checked), inner scraped_intervals = 30/15 = 2.0
720+
#[test]
721+
fn test_bug_201_spatial_of_temporal_not_rejected() {
722+
check_query_with_interval(
723+
"SELECT SUM(result) FROM \
724+
(SELECT SUM(value) AS result FROM cpu_usage \
725+
WHERE time BETWEEN DATEADD(s, -30, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
726+
GROUP BY L1, L2, L3, L4) \
727+
GROUP BY L1",
728+
15.0,
729+
vec![QueryType::Spatial, QueryType::TemporalGeneric],
730+
None,
731+
);
732+
}
733+
734+
/// scraped_intervals = 14/15 = 0.93 < 1.0 → should still be rejected (guard still works)
735+
#[test]
736+
fn test_bug_201_sub_interval_query_still_rejected() {
737+
check_query_with_interval(
738+
"SELECT AVG(value) FROM cpu_usage \
739+
WHERE time BETWEEN DATEADD(s, -14, '2025-10-01 00:00:00') AND '2025-10-01 00:00:00' \
740+
GROUP BY L1, L2, L3, L4",
741+
15.0,
742+
vec![],
743+
Some(QueryError::SpatialDurationSmall),
744+
);
745+
}
649746
}

‎asap-common/dependencies/rs/sql_utilities/src/ast_matching/sqlpattern_matcher.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ impl SQLPatternMatcher {
188188
let scrape_duration = time_info.get_duration();
189189
scraped_intervals = scrape_duration / self.scrape_interval;
190190

191-
if scraped_intervals < self.scrape_interval {
191+
if scraped_intervals < 1.0 {
192192
println!("Returned QueryError::SpatialDurationSmall");
193193

194194
return Err((
@@ -244,15 +244,15 @@ impl SQLPatternMatcher {
244244
// Last query
245245
// let time_info = TimeInfo::new("time".to_string(), *start, *scrape_duration);
246246

247-
if (scrape_duration - self.scrape_interval).abs() < f64::EPSILON {
247+
if (scrape_duration - 1.0).abs() < f64::EPSILON {
248248
sql_query.add_subquery(
249249
QueryType::Spatial,
250250
aggregation_info.clone(),
251251
metric.clone(),
252252
labels.clone(),
253253
time_info.clone(),
254254
);
255-
} else if *scrape_duration > self.scrape_interval {
255+
} else if *scrape_duration > 1.0 {
256256
// Check if labels match all metadata columns
257257
let has_all_labels = self
258258
.schema

0 commit comments

Comments
 (0)