Skip to content

sql.rs: query-requirements derivation duplicated across 3 independent implementations #519

Open

Description

@milindsrivastava1997

SQL's query-requirements derivation (statistic mapping, grouping labels, data range) exists as three separate, non-shared implementations that happen to agree today but have no mechanism keeping them in sync:

  1. asap-query-engine's main path (build_spatiotemporal_context, asap-query-engine/src/engines/simple_engine/sql.rs) derives query_output_labels, statistic_to_compute, and timestamps directly from SQLQueryData/SQLQuery, without going through QueryRequirements at all.
  2. asap-query-engine's capability-matching fallback path calls build_query_requirements_sql, a private SimpleEngine method used only there.
  3. asap-planner-rs's SQLSingleQueryProcessor::get_streaming_aggregation_configs (asap-planner-rs/src/planner/sql.rs) has its own from-scratch get_sql_treatment_type/get_sql_statistics, sharing no code with either function above.

Concretely: parse_single_statistic (query-engine, via AggregationOperator::to_statistics()) and get_sql_statistics (planner-rs, a hand-written match name.to_uppercase()) encode the same name→Vec<Statistic> mapping as two separately-maintained match statements. get_sql_treatment_type (planner-rs: "MIN"|"MAX" => Exact, _ => Approximate) happens to agree with what Statistic::is_approximate() would say for every statistic SQL can produce, but is a separate hand-written check, not a call to that method.

This is the same shape of problem #508 fixed for PromQL, which now has one canonical build_query_requirements_promql shared across all 4 of its own call sites (query-engine's main + fallback paths, planner's SingleQueryProcessor + AQE extractor). For SQL it's three-way, and unlike PromQL there's no cross-crate-shared function to converge onto yet — build_query_requirements_sql is private to asap-query-engine, not exported via asap_types the way PromQL's equivalent is.

Activity

  1. milindsrivastava1997 commented on Jul 10, 2026

    @milindsrivastava1997
    ContributorAuthor

    Can PromQL and SQL be unified here?

    Partially — the underlying business logic can be shared, but the parsing/detection layer genuinely can't be, for a few structural reasons:

    • Detection mechanisms differ structurally, not just in code style. PromQL's topk is a dedicated AST node (topk(k, expr)) with k sitting right there in the aggregation token. SQL's topk is inferred — detect_sql_topk reverse-engineers it from ORDER BY <agg> DESC LIMIT k shape-matching, a heuristic reconstruction, not a direct read. The extraction step can't be shared; the source ASTs don't correspond.
    • PromQL's collapsability problem doesn't exist in SQL at all. The non-collapsable spatial-of-temporal issue (promql.rs: decouple from QueryPatternType #508, e.g. sum(min_over_time(x))) is about nested aggregation-of-function. SQL sidesteps this entirely by rejecting nested queries outright ("Nested SQL queries (n=%d) are not supported"). A shared "is this combination valid" check would carry dead weight on the SQL side.
    • spatial_filter is PromQL-only (label matchers baked into {job="api"} selector syntax) — SQL folds the equivalent into GROUP BY/WHERE differently, with no analogous string to normalize.

    What should be shared but currently isn't: the pure logic once you already have "a statistic name, a set of labels, a duration, a metric" in hand — the name→Vec<Statistic> mapping (avg→[Sum,Count] expansion), Statistic::is_approximate()-based treatment typing, and label-routing arithmetic (all_labels.difference(&grouping_labels)). None of that cares which language produced the inputs.

    Recommendation: a small trait (something like MatchedQuery { fn metric(&self) -> String; fn statistic_name(&self) -> String; fn grouping_labels(&self) -> Vec<String>; fn data_range_ms(&self, interval_ms: u64) -> u64; fn topk_info(&self) -> Option<TopkInfo>; }) implemented once for PromQLMatchResult and once for SQLQuery, with one generic build_query_requirements<T: MatchedQuery> doing the actual derivation. That gives SQL the same "one canonical implementation" guarantee #508 gave PromQL, without forcing SQL's fundamentally different AST shape through PromQL's token-bag abstraction (or vice versa).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions