Repository navigation
feat: ASAPPlanner now relies on DataFusion 54.1 - #614
Merged
Merged
Conversation
zzylol
reviewed
Oct 5, 2026
zzylol
approved these changes
Oct 5, 2026
zzylol
added a commit
that referenced
this pull request
Oct 7, 2026
Port DF 54's API changes (Expr::Literal metadata, Cast/TryCast field, ScalarUDFImpl return_field_from_args/invoke_with_args, catalog path, dialect name) and the planner behaviour changes (SELECT * keeps its projection, GenericDialect parses aggregate FILTER) from main's crates/frontend-sql/src/sql onto the unified copy and its tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zzylol
added a commit
that referenced
this pull request
Oct 7, 2026
…'s version DataFusion 54 requires chrono ^0.4.44, so the runtime crate's exact =0.4.39 pin no longer resolves; keep 0.4.39 as the minimum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zzylol
added a commit
that referenced
this pull request
Oct 12, 2026
…'s version DataFusion 54 requires chrono ^0.4.44, so the runtime crate's exact =0.4.39 pin no longer resolves; keep 0.4.39 as the minimum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 tasks
zzylol
added a commit
that referenced
this pull request
Oct 12, 2026
* feat: lower SQL through unified operators and scalars * fix: integrate with #614 (DataFusion 54) in the unified SQL lowering Port DF 54's API changes (Expr::Literal metadata, Cast/TryCast field, ScalarUDFImpl return_field_from_args/invoke_with_args, catalog path, dialect name) and the planner behaviour changes (SELECT * keeps its projection, GenericDialect parses aggregate FILTER) from main's crates/frontend-sql/src/sql onto the unified copy and its tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style: apply cargo fmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(sql): fold numeric casts of literals as DataFusion does Type coercion turns a literal compared with a column of another type into a cast: `latency < 100` on a DOUBLE column became `latency < CAST(100 AS DOUBLE)`, which summary coverage cannot read as a constant. Fold a cast of a literal to an integer or float type with DataFusion's `ScalarValue::cast_to`, the evaluation its constant folding uses; the predicate lowers as `latency < 100.0`. A cast that fails to evaluate is kept. DataFusion's whole SimplifyExpressions rule is not run: it also folds timestamp casts into timestamp literals, which the IR cannot write yet, and rewrites REGEXP_LIKE into the `~` operator (#650). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW * fix(sql): address #539 review findings - Column resolution: a qualified reference falls back to the bare name only when exactly one column has it, so `ORDER BY b.k` after a join no longer binds `a.k`; an ambiguous name is an error. A bare name must be unique too. - Reducer arguments keep their qualifier, so `SUM(b.x)` over a join reads `b.x`, not `a.x`. - `WITHIN GROUP (ORDER BY x DESC)` percentiles use `1 - q`, as DataFusion. - `CAST(NULL AS ...)` is not folded, so a typed NULL keeps its type. - Non-literal `LIMIT`/`OFFSET` expressions are rejected instead of dropped. - A cast in a reducer argument that can change values or the result type (`SUM(CAST(i AS DOUBLE))`) is computed as a derived column; only widening casts that leave the result unchanged read the bare column. - Window `FILTER`, `DISTINCT` and `IGNORE NULLS` are rejected. - `LIKE ... ESCAPE` is rejected. - DataFusion 54: an integer cast to `Decimal128(_, 0)` (how DataFusion compares unsigned with signed integers, e.g. `ROW_NUMBER() ... <= 5`) is dropped after type coercion; any other decimal cast, such as a user's `CAST(1.5 AS DECIMAL(10, 0))`, is rejected. Type coercion runs after the duration check, so a temporal subtraction inside a CASE branch is still reported as an unsupported duration. - A reducer argument is read from the bare column only when the cast is directly over a column: coercion wraps `avg(CAST(f AS BIGINT))` as `CAST(CAST(f AS Int64) AS Float64)`, and the inner cast truncates. - A CAST / TRY_CAST of a non-literal to INT, SMALLINT, TINYINT or REAL is rejected: the canonical types are 64-bit, so its range check or 32-bit rounding would be lost. - `CAST(x AS VARCHAR)` (DataFusion 54's `Utf8View`) lowers to Utf8. - A `Concat` column is nullable if any child's is, so a ROLLUP / CUBE / GROUPING SETS key is nullable in the combined output. The last five were found by running 573 queries through DataFusion and through this lowering. Each has a regression test in unified_sql_lowering.rs that fails without the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
zzylol
added a commit
that referenced
this pull request
Oct 12, 2026
…'s version DataFusion 54 requires chrono ^0.4.44, so the runtime crate's exact =0.4.39 pin no longer resolves; keep 0.4.39 as the minimum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zzylol
added a commit
that referenced
this pull request
Oct 12, 2026
…'s version DataFusion 54 requires chrono ^0.4.44, so the runtime crate's exact =0.4.39 pin no longer resolves; keep 0.4.39 as the minimum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zzylol
added a commit
that referenced
this pull request
Oct 12, 2026
…#541) * feat(ir): restore execution timing assignment for physical plans The logical export is phase-free. Physical planning still needs the lifecycle timing expansion; bring it back unchanged except for carrying coverage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(ir): export timed plans as PhysicalASAPDAG The logical export carries no execution timing. Physical planning output needs it: reuse the logical payloads and node ids, and add each node's and edge's data state plus window compatibility, as the earlier post-ASAP export did. Coverage is carried through. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runtime): compile unified operator and scalar graphs * feat(ir): give physical ASAP DAGs one root per batch query Match the logical export: a batch is one DAG whose roots are its queries, with shared sub-DAGs exported once. The runtime compiles all roots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: integrate with #614 (DataFusion 54): let chrono resolve to DF 54's version DataFusion 54 requires chrono ^0.4.44, so the runtime crate's exact =0.4.39 pin no longer resolves; keep 0.4.39 as the minimum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(runtime): read Operator<NodeId> payloads from the physical ASAP DAG Follow #537: the physical DAG now carries each node's operator as Operator<NodeId> (from ir::flat) instead of the removed wire mirror types. The runtime matches Operator::NonASAP / Operator::ASAP directly, and restore() rebuilds the in-memory DAG with map_children instead of a field-by-field conversion. Node ids are plain usize. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(ir): follow derived summary coverage in timing and physical export Coverage is derived from the node (#646), so timed copies no longer carry it and PhysicalASAPDAGNode drops its coverage field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW * fix(runtime): address #541 review findings - timing: a SummaryAgg the lifecycle assignment recomputes at query time now forces the SummaryAgg consuming it to query time (`forces_query_time` reads the assignment), instead of failing with EvaluationUnderMaintenance. - physical export: `PhysicalASAPDAG::validate` requires each node's incoming edges to be exactly its operator's inputs with their roles, so swapped Left/Right edges cannot reorder `a - b` (EdgeRoleMismatch). - physical export: a DAG that fails validation (an empty batch, a hand-timed plan) is an `InvalidPhysicalDAG` error instead of a panic. - precompute: only a TimeRange over (a TimeShift over) a time series Scan takes the raw-sample input contract, as before the port; a table range needs a stored population. - compile: an input binding below a node the PromQL fallback evaluates is an error; the fallback reads raw series slots, so it was silently ignored. A binding below another bound input is still superseded by it, as in `cut`. - compile: drop the scalar-literal binary branch; nothing filled its map. - PromQL fallback: clamp's `NOT (max < min)` is now the IR `Filter` #540 emits; the fallback runs a filter on scalars alone, and the pointwise projection no longer filters on its own. - tests: `raw_series_contract_is_explicit` asserts that a consumed bare selector is instant selection (its comment said the opposite) and that a binding below the fallback is rejected; new `unified_precompute` test. - PromQL fallback: unary minus drops the metric name like every other pointwise projection, following #540 and the Prometheus 3.15 baseline (#511); pointwise_projection_names_and_dynamic_parameters expects it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW * refactor(runtime): remove the PromQL fallback evaluator ASAPPlanner generates candidates and computes their cost, or says why a query has none. Executing what the native operators cannot run belongs to the deployment runtime (ASAPQuery backend), not to the Planner. Remove unified_physical_planner::promql_fallback and its tests, and the fallback paths in compile: raw-series input slots, the fallback lowering and the below-fallback binding check. A node without a native lowering now fails compilation with Error::Invalid. Reject Planner node IDs above u32::MAX, which could collide with helper IDs, and error instead of debug-asserting when a node needs more than 2^16 helpers. Document that forces_query_time also forces an unaligned per-series PromQL BinaryOp to query time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #611.
Why
asap-frontend-sql, the only crate that uses DataFusion, was on 43. Newer versions plan more SQL, and the longer we wait, the bigger the upgrade.What
DataFusion 43 → 54.1 (arrow 53 → 58, sqlparser 0.51 → 0.62).
Most of the diff is mechanical API migration. DataFusion 54 also changed five behaviors we depend on:
SELECT *is expanded at planning timeProject. SQL top-k recognition (MaintainedPopulationStrategy) expectedLimit { Sort { Scan } }, so it now skips an identity projection underSortCollectionandDiagnosticSqlErrorunwraps them, so callers still getDataFusion(Plan(..))GenericDialectsupports aggregateFILTERGenericWithAggregateFilterwrapper (dialect.rs) is removedmap(...)is reserved by DataFusion;map()is rejectedmapis planned asasap_map_constructand renamed back tomapduring loweringdate - datereturns Int64 days instead of aDurationBefore / after
Two
bgp_jan2024_workloadqueries now lower:… / greatest(countIf(…), 1)Invalid function 'greatest'IN (SELECT … ORDER BY count(*) DESC LIMIT 5)UnsupportedFeatureSQL top-k with an explicit, in-order column list (
SELECT latency, job … ORDER BY latency DESC LIMIT 5) is now recognized. Before, onlySELECT *was.Tests
sql_loweringtests no longer expectSELECT *to elide theProject.IN (subquery)is rejected by DataFusion first, so the test's expected message changed.quantile_cont, a new alias ofpercentile_cont, is added toKNOWN_UNMAPPED_NATIVE_FUNCTIONS.cargo test --workspace: 1570 passed. Clippy is clean.