Skip to content

fix(cubesql): don't abort on date filters beyond the nanosecond range - #11475

Open
igorlukanin wants to merge 8 commits into
masterfrom
igor/core-732-sql-api-planner-panics-on-date-filters-beyond-2262-04-11-i64
Open

fix(cubesql): don't abort on date filters beyond the nanosecond range#11475
igorlukanin wants to merge 8 commits into
masterfrom
igor/core-732-sql-api-planner-panics-on-date-filters-beyond-2262-04-11-i64

Conversation

@igorlukanin

Copy link
Copy Markdown
Member

Issue

A date filter with an upper bound past 2262-04-11 aborted the SQL API query planner. The client saw a dropped connection or its own timeout rather than an error.

thread 'tokio-runtime-worker' panicked at chrono/src/lib.rs:717:17:
  invalid or out-of-range datetime
Rewrite Error: Unexpected panic. Reason: invalid or out-of-range datetime

9999-12-31 is a widespread "no end date" sentinel in warehouse schemas, and it is the natural way to write a one-sided range in a tool that requires two bounds, so this is reachable from ordinary models.

Root cause

An unchecked i64 multiplication in the Date32Timestamp(Nanosecond) coercion.

date '2262-04-12' is Date32 106752. Converting it to nanoseconds computes 106752 × 86_400_000_000_000 = 9_223_372_800_000_000_000, which exceeds i64::MAX by 763_145_224_193. 2262-04-11 is 106751 and fits with 86.4 s to spare — exactly where the reported boundary sits. The representable window is symmetric at ±106_751 days: 1677-09-22 to 2262-04-11.

The multiply that overflows is arrow's multiply kernel, which is a plain math_op(left, right, |a, b| a * b). With no checked_mul the two build profiles fail differently from one cause:

  • debug traps — attempt to multiply with overflow
  • release wraps to -9_223_371_273_709_551_616, whose secs/nsecs split is then rejected by chrono's infallible NaiveDateTime::from_timestamp — the message in the report

It fires in PlanNormalize, which runs before the egg rewriter:

evaluate_expr_stacked → DataFusion ConstEvaluatorCastExpr::evaluate → arrow cast_with_optionsmultiply.

Note the literal arrives as CAST(CAST(Utf8("2262-04-12") AS Date32) AS Timestamp(Nanosecond, None)) — it is still a string at that point and only becomes a Date32 when the cast is evaluated, which is the evaluation that overflows.

Fix

A representability guard in evaluate_expr_stacked that declines to evaluate an expression carrying a date/time literal outside the nanosecond window. Because the literal is a string there, the guard parses it against the type it is cast to rather than waiting for a typed value.

Returning an error rather than the expression unevaluated is deliberate: left in the plan, the un-evaluated cast reaches the rewriter and overflows there instead, so declining silently only moves the panic.

Also fixes the same unchecked multiply in the date_to_timestamp UDF, which produced a garbage instant instead of an error. The other two 86_400_000_000_000 sites in the crate divide by the constant and cannot overflow.

Result

The affected queries now succeed, with the out-of-range date passed through verbatim — the Cube REST API takes ISO strings and never needs the nanosecond timestamp.

Filter Before After
<= date '2262-04-12' panic beforeOrOnDate = 2262-04-12T00:00:00.000Z
<= date '9999-12-31' panic beforeOrOnDate = 9999-12-31T00:00:00.000Z
BETWEEN date '2020-01-01' AND date '9999-12-31' panic range pushed down, both bounds intact
<= date '2262-04-11' worked unchanged

Tests

  • test_filter_date_beyond_nanosecond_range_is_pushed_down — 2262-04-12 and 9999-12-31 push down with the date intact
  • test_filter_date_at_nanosecond_range_boundary_is_pushed_down — 2262-04-11 still pushes down, so the guard does not over-reject
  • test_filter_between_date_beyond_nanosecond_range — the BETWEEN path, which normalizes bounds separately and propagates errors
  • test_date32_representable_boundaries — ±106_751 accepted; ±106_752 and i32::MIN/MAX rejected
  • test_string_literal_judged_through_its_date_cast — string-through-cast resolution, and that a non-temporal cast target is left alone

780 cubesql lib tests green. Both halves of the guard were mutation-checked: disabling the range check and disabling the string-through-cast resolution each turn the integration tests red with the original overflow.

@igorlukanin
igorlukanin requested a review from a team as a code owner August 5, 2026 00:02
@github-actions github-actions Bot added the rust Pull requests that update Rust code label Aug 5, 2026
@claude

claude Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 3m 18s —— View job


Review complete — solid fix for the reported panic; 3 medium, 2 low. Main concern: the guard declines more than the overflow requires, silently degrading the string-literal filter form.

Full review
  • Read the diff (git diff origin/master...HEAD)
  • Review the plan_normalize.rs representability guard
  • Review the date_to_timestamp UDF checked_mul change
  • Trace all evaluate_expr / evaluate_expr_stacked call sites for over-rejection
  • Review test coverage
  • Post inline comments and summary

What's good

The diagnosis is excellent and the writeup is unusually precise — the ±106_751-day symmetry, the debug-traps/release-wraps split from one unchecked *, and the observation that the literal is still Utf8 at PlanNormalize time are all correct and non-obvious. Choosing to error rather than silently return the expression unevaluated is the right call and the rationale is in the code, not just the PR body.

The date_to_timestamp UDF change (common.rs) is clean: checked_mulok_or_else.transpose()collect::<Result<_>>()? is idiomatic, preserves nulls, and replaces a garbage instant with a real error. No issues there.

test_date32_representable_boundaries and test_string_literal_judged_through_its_date_cast are good unit tests — they pin both the boundary and the string-through-cast resolution, and the mutation check described in the PR is the right way to validate a guard.

Findings

# Severity Where Issue
1 Medium plan_normalize.rs:1650 Guard covers Date32/Date64/all Timestamp units; only Timestamp(Nanosecond) overflows. Silently degrades WHERE dim_date0 <= '9999-12-31' (string form) at line 1459, where the new Err is .ok()-swallowed
2 Medium plan_normalize.rs:1724 _ => () is fail-open — Expr::Case, AggregateFunction, WindowFunction, Like, GetIndexedField, Sort, InSubquery aren't traversed, so a literal hidden in a CASE arm still reaches the overflowing cast
3 Medium test_filters.rs:401 test_filter_between_date_beyond_nanosecond_range accepts both Ok and Err — it asserts only "did not panic" and cannot regress
4 Low plan_normalize.rs:1670 No short-circuit; full re-traversal per enclosing evaluate_* call on a path where this file otherwise tracks traversal cost and stack depth carefully
5 Low plan_normalize.rs:1732 Error embeds the whole expression (can be a 512-deep OR); wording is date-only but the guard also fires on timestamp scalars

Finding 1 is the one I'd want addressed before merge — it's the only one that changes behavior for a query that works today, and it does so quietly rather than with the new error message.

Scope note (not a blocker)

The guard sits at one call site. As the PR body acknowledges, the overflow lives in arrow's multiply kernel and is reachable from the egg rewriter too; guarding evaluate_expr_stacked fixes the reported path but leaves the kernel unchecked for any other caller. Reasonable to defer, but worth a CORE- follow-up so the next path that hits it isn't diagnosed from scratch.

Security / performance

No security surface — no user input reaches a new sink, and the change strictly narrows what gets evaluated. Performance impact is the extra traversal in finding 4; negligible for typical expressions.

Not verified

I did not compile or run the Rust test suite (a cold cubesql build exceeds the time available in this job). Findings 1–3 are from reading the call graph — in particular finding 1 traces binary_expr_normalizecast_string_literal_expr (line 1459) → evaluate_expr(...).ok(), and your own unit test assert!(!cast_to_date("9999-12-31")) against DataType::Date32 confirms the guard returns false for that cast target. Worth confirming with an actual WHERE dim_date0 <= '9999-12-31' test case.

· branch `igor/core-732-sql-api-planner-panics-on-date-filters-beyond-2262-04-11-i64`

Comment thread rust/cubesql/cubesql/src/compile/engine/df/optimizers/plan_normalize.rs Outdated
Comment thread rust/cubesql/cubesql/src/compile/test/test_filters.rs Outdated
Comment thread rust/cubesql/cubesql/src/compile/engine/df/optimizers/plan_normalize.rs Outdated
Comment thread rust/cubesql/cubesql/src/compile/engine/df/optimizers/plan_normalize.rs Outdated
@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.50000% with 91 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.48%. Comparing base (a6fbbb4) to head (cf43810).
⚠️ Report is 8 commits behind head on master.

Files with missing lines Patch % Lines
...src/compile/engine/df/optimizers/plan_normalize.rs 79.84% 53 Missing ⚠️
...t/cubesql/cubesql/src/compile/engine/df/wrapper.rs 0.00% 21 Missing ⚠️
...t/cubesql/cubesql/src/compile/engine/udf/common.rs 0.00% 11 Missing ⚠️
...t/cubesql/cubesql/src/compile/test/test_filters.rs 97.33% 6 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master   #11475       +/-   ##
===========================================
+ Coverage   59.10%   79.48%   +20.38%     
===========================================
  Files         223      480      +257     
  Lines       17891    99359    +81468     
  Branches     3636     3636               
===========================================
+ Hits        10575    78980    +68405     
- Misses       6795    19859    +13064     
+ Partials      521      520        -1     
Flag Coverage Δ
cube-backend 59.22% <ø> (+0.12%) ⬆️
cubesql 83.95% <82.50%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@claude

claude Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 4m 40s —— View job


Re-review of the new commits — prior 5 findings all addressed; 2 new medium, 1 low. Main concerns: the Err is swallowed plan-wide by unwrap_or, and the Date64 substitution isn't renderable by the wrapper.

Full review
  • Read the updated diff (git diff cc61845...HEAD)
  • Check which prior findings the new commits address
  • Review the new parse_string_literal_as normalization path
  • Trace the Err propagation out of PlanNormalize
  • Review new tests
  • Resolve stale threads, post new findings

Prior findings — all five addressed

Prior Status
Guard wider than the overflow / string form silently un-normalized Fixed differently and better than suggested: cast_string_literal_expr now handles Date32/Date64/all Timestamp targets itself, so the string form never reaches the overflowing kernel, and test_filter_string_date_beyond_nanosecond_range_is_pushed_down pins it
_ => () fail-open walk Fixed — the match is now exhaustive with no catch-all, all container variants enumerated, and test_unrepresentable_literal_found_inside_containers covers CASE/BETWEEN/aggregate/within_group/Sort/alias
BETWEEN test accepted Ok or Err Fixed — now asserts the exact time_dimensions dateRange
No short-circuit in the walk Fixed — find_map short-circuits on the first hit
Error message renders the whole expression Fixed — renders only the offending literal

All five threads resolved. The exhaustiveness comment on find_unrepresentable_datetime_literal ("a newly added Expr variant must fail to compile here instead of silently becoming a hiding place") is exactly the right reasoning to leave in the code.

New findings

# Severity Where Issue
1 Medium plan_normalize.rs:1803 The Err is discarded by optimizer.optimize(…).unwrap_or(optimized_plan) in query_engine.rs:164, so it reverts the whole plan to un-normalized rather than one cast. Never surfaces to the user; and one out-of-range date disables unrelated normalizations in the same query (e.g. the DATE - DATEDATEDIFF rewrite, which exists to avoid INTERVAL on non-Postgres dialects)
2 Medium plan_normalize.rs:1492 The Timestamp(Nanosecond)Date64 fallback changes the literal's type. wrapper.rs has the Date64 arm commented out (line 2986) and falls to Can't generate SQL for literal (line 3074), so the filter breaks SQL generation whenever it's rendered by the wrapper instead of pushed down as a member. Also: Date64 → Timestamp(ns) is the same unchecked millis * 1_000_000 (the guard itself rejects this scalar), and a string with a time component yields a non-day-aligned Date64, which Arrow forbids
3 Low plan_normalize.rs:1469 Epoch recomputed per call with a ? on an infallible from_ymd_opt; and the Date32 arm now accepts strings the Arrow kernel rejected, silently dropping any time component — undocumented and untested

Finding 1 is worth resolving because it partly undercuts the design note in the code: test_filter_date_beyond_nanosecond_range_is_pushed_down passes precisely because the error is swallowed and the original single-cast expression reaches the rewriter unharmed — which is evidence that declining the coercion locally (as the cast_string_literal_expr fallthrough at line 1531 already does) works, rather than "only moving the panic".

Testing

The four integration tests plus three unit tests are a good spread, and the new string-form test closes the gap flagged last round. Two paths still uncovered:

  • SQL generation through CubeScanWrapper for a Date64-substituted bound (finding 2) — the only place the current fallback is known to break.
  • The error message itself. Nothing today can observe it (finding 1), so assert!(matches!(…)) on a plan error would either pin the behavior or reveal it's unreachable.

Security / performance

No security surface. The guard walk now short-circuits; parse_string_literal_as checks the target type before parsing. No concerns.

Not verified

I did not compile or run the Rust suite — a cold cubesql build exceeds this job's budget. Findings 1 and 2 are from reading the call graph: finding 1 traces binary_expr_normalize's (Timestamp, Date32) arm → evaluate_expr → guard → ?query_engine.rs:164 .unwrap_or; finding 2 traces the returned ScalarValue::Date64 into wrapper.rs:2986/3074. Both are worth confirming with a wrapper-path test rather than taken on my reading alone.

· branch `igor/core-732-sql-api-planner-panics-on-date-filters-beyond-2262-04-11-i64`

Comment thread rust/cubesql/cubesql/src/compile/engine/df/optimizers/plan_normalize.rs Outdated
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 3m 15s —— View job


Re-review of 98f33ca — both prior findings addressed; 1 medium, 1 low. Main concern: the BETWEEN and IN coercion sites still Err out of the rule.

Full review
  • Read the diff since the last review (git diff 2cf3336..HEAD)
  • Check which prior findings the new commit addresses
  • Review the local-decline change in binary_expr_normalize
  • Review the wrapper.rs Date64 arm
  • Review the new test
  • Post findings (all 8 prior threads already resolved — nothing stale to close)

Prior findings — both addressed

Prior Status
Err swallowed by unwrap_or, reverting the whole plan Fixed at the binary-comparison site: the (Timestamp, Date32) / (Date32, Timestamp) arms now check find_unrepresentable_datetime_literal on the built cast and return the un-coerced comparison instead of calling evaluate_expr. test_out_of_range_bound_keeps_other_normalizations pins it by asserting DATEDIFF(day, survives alongside an out-of-range bound — a good test, because it fails for the right reason (rule-wide revert) rather than on the filter itself
Date64 not renderable by the wrapper Fixed — wrapper.rs:2987 renders it via generate_sql_for_timestamp!(… timestamp_millis_opt …) instead of falling to Can't generate SQL for literal
Date64 vs TimestampMillisecond choice The added comment settles it: scalar_to_native_datetime (rules/filters.rs:4715) converts only `TimestampNanosecond
Epoch recomputed per call / undocumented parse_date_str leniency Fixed — EPOCH_DAYS_FROM_CE const (719_163 is right) and a doc paragraph on the accepted-strings and dropped-time-component behavior

The comment above the coercion arms explaining why the decline is side-local (and what an Err would cost) is the kind of note that keeps a future refactor from quietly undoing this.

New findings

# Severity Where Issue
1 Medium plan_normalize.rs:1602, :1663 The IN-list and BETWEEN-bound coercions still pass the ns cast to evaluate_expr_stacked, so the guard's Err still propagates out and unwrap_or still discards the whole normalized plan. test_filter_between_date_beyond_nanosecond_range can't see it — the un-normalized plan pushes down fine, which is precisely the blind spot the new <= test was written for
2 Low wrapper.rs:2987 New arm has no test — every Date64 assertion in the PR goes through find_cube_scan().request, none through find_cube_scan_wrapped_sql, so the one path the Date64 substitution was known to break stays uncovered. Also timestamp_millis_opt(..).unwrap() panics beyond chrono's range (unreachable from parse_string_literal_as, but it replaces a graceful error for any other producer)

Finding 1 is the same class as last round's finding 1, one call site over: extending the new test's loop to the BETWEEN / IN forms and mirroring the decline at both sites would close it.

Security / performance

No security surface. Perf note: the declined path clones the operand and traverses it once for the guard, then evaluate_expr re-traverses inside evaluate_expr_stacked. Both are bounded by the expression already being walked and negligible next to const evaluation.

Not verified

I did not compile or run the Rust suite — a cold cubesql build exceeds this job's budget. Finding 1 is from reading the call graph: between_expr_normalizenormalize_bound (bound type Date32Timestamp(ns) → cast built) → evaluate_expr_stacked → guard → ?, with no local decline between them. Swapping the predicate in test_out_of_range_bound_keeps_other_normalizations to the BETWEEN form is the cheap way to confirm or refute it.

· branch `igor/core-732-sql-api-planner-panics-on-date-filters-beyond-2262-04-11-i64`

Comment thread rust/cubesql/cubesql/src/compile/engine/df/wrapper.rs Outdated
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Re-reviewing 7beebb6

  • Read the diff since the last review (git diff 98f33ca..HEAD)
  • Verify the IN-list / BETWEEN local decline
  • Review the new test coverage
  • Check remaining unresolved threads for staleness
  • Post findings

View job run · branch igor/core-732-sql-api-planner-panics-on-date-filters-beyond-2262-04-11-i64

@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 3m 7s —— View job


Re-review of 7beebb6 + 13de27e — both prior findings addressed; 1 low, no blockers. All escape paths out of the rule are now guarded.

Full review
  • Read the diff since the last review (git diff 98f33ca..HEAD)
  • Verify the IN-list / BETWEEN local decline
  • Verify the Date64 unrenderable-literal error
  • Review the new test coverage
  • Check remaining unresolved threads for staleness (all 10 already resolved — nothing to close)
  • Post findings

Prior findings — both addressed

Prior Status
IN-list and BETWEEN coercions still Err out of the rule Fixed. in_list_expr_normalize:1602 and normalize_bound:1669 now check find_unrepresentable_datetime_literal on the built cast and return the un-coerced element/bound. The let Expr::Cast { expr: bound, .. } = casted else { unreachable!(…) } unwrap is fine — the Expr::Cast is constructed three lines above. test_out_of_range_bound_keeps_other_normalizations now loops over <=, BETWEEN and IN, so all three declines are pinned against the plan-wide revert
timestamp_millis_opt(..).unwrap() panics for an extreme Date64 Fixed. The arm is written out instead of using generate_sql_for_timestamp! and returns DataFusionError::Internal on a non-Single LocalResult. The comment says exactly why the macro was bypassed, which is the part that keeps someone from "simplifying" it back

I re-checked the escape surface: evaluate_expr/evaluate_expr_stacked is now reached from four places — the two binary arms (guarded, 1395/1406), the IN closure (guarded), normalize_bound (guarded), and cast_string_literal_expr:1463, which is .ok()-swallowed by construction. So the guard's Err no longer has a path to query_engine.rs's .unwrap_or(plan), and the plan-wide revert is closed. The find_unrepresentable_datetime_literal guard inside evaluate_expr_stacked remains as the backstop, which is the right layering.

New finding

# Severity Where Issue
1 Low test_filters.rs:479 The IN form is the one of the three declines with no assertion that the filter itself pushes down — the loop only checks DATEDIFF(day, survives, which holds even if the IN filter were dropped. It leaves a mixed-type list (one Timestamp(ns) literal, one un-evaluated CAST(Utf8 AS Date32)), and a failed pushdown leaves that comparison on the DataFusion side where Date32Timestamp(ns) coercion is the same unchecked multiply. Reading make_constant_in_list and scalar_to_scalar_value_string says it works; it's just not pinned

Re-affirmed, not re-posted

The Date64 arm in wrapper.rs:2987 still has no test through find_cube_scan_wrapped_sql. The new wrapped-SQL assertions in test_out_of_range_bound_keeps_other_normalizations all use date '…' literals, which decline to Date32, so no Date64 reaches the wrapper in any test. That thread is resolved and it's a coverage gap rather than a defect, so I haven't reopened it — noting it only so the state is explicit.

Security / performance

No security surface. The two new declines each clone the operand and traverse it once for the guard before evaluate_expr_stacked re-traverses; bounded by an expression already being walked, negligible next to const evaluation.

Not verified

I did not compile or run the Rust suite — a cold cubesql build exceeds this job's budget, and there is no cached target/ on this runner. Two things I'd normally confirm by compiling: that chrono::LocalResult::Single resolves through the MappedLocalTime alias in chrono 0.4.39 (it should — type-alias enum variants are stable, and the alias isn't #[deprecated]), and finding 1, which is inference from analysis.rs:1148 and rules/filters.rs:4698 rather than a run.

· branch `igor/core-732-sql-api-planner-panics-on-date-filters-beyond-2262-04-11-i64`

Comment thread rust/cubesql/cubesql/src/compile/test/test_filters.rs
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 1m 6s —— View job


Re-review of cf43810 — the last open finding is closed. No new issues; nothing blocking.

Full review
  • Read the diff since the last review (git diff 13de27e..HEAD)
  • Verify the new IN-list pushdown test actually exercises the decline
  • Re-check the three decline sites and the guard backstop
  • Check existing review threads for staleness (all 11 already resolved — nothing to close)
  • Post findings

Prior finding — addressed

Prior Status
The IN decline had no assertion that the filter itself survives pushdown Fixed. test_filter_in_list_date_beyond_nanosecond_range_is_pushed_down (test_filters.rs:520) pins the structured filter — member MultiTypeCube.dim_date0, operator equals, both ISO values — so the heterogeneous list is now proven to convert rather than inferred from reading make_constant_in_list / scalar_to_scalar_value_string. That was the one of the three declines resting on inference, and it's the one where a failed pushdown would have left a Date32 vs Timestamp(ns) comparison on the DataFusion side, i.e. back at the same unchecked multiply

I re-checked that the test hits the intended path rather than passing incidentally: in in_list_expr_normalize (plan_normalize.rs:1583-1609) the tested expr is Timestamp(ns), each element normalizes to CAST(Utf8 AS Date32) so list_expr_type is Date32 and the cast is built — then date '2020-01-01' folds through evaluate_expr_stacked while date '9999-12-31' trips find_unrepresentable_datetime_literal and returns un-coerced. So the assertion is over exactly the mixed-type list the doc comment describes, and it should go red if the decline is reverted (overflow) or if the element is dropped (values shrinks). The doc comment stating that outcome above the test is the right place for it.

Final state of the change

Three coercion sites decline locally (binary_expr_normalize at 1395/1406, in_list_expr_normalize at 1602, normalize_bound at 1669), the guard inside evaluate_expr_stacked remains as the backstop for shapes that can't drop the cast, and the only remaining caller that can see its Err is cast_string_literal_expr:1463, which is .ok()-swallowed by construction. So no path reaches query_engine.rs's .unwrap_or(plan). Each of the three declines has a pushdown test plus a control arm in test_out_of_range_bound_keeps_other_normalizations asserting DATEDIFF(day, survives alongside the out-of-range bound.

Coverage note (re-affirmed, not re-posted)

The Date64 arm in wrapper.rs:2987 still has no test through find_cube_scan_wrapped_sql — every Date64 assertion goes through find_cube_scan().request. That thread is resolved, and the reason given (every shape tried either matched the bound as a member or parameterized it to $1, so the test passed with the arm removed and was dropped rather than kept as an unfalsifiable assertion) is the right call — an untested arm justified by reachability, stated plainly, beats a test that proves nothing. Noting it only so the state stays explicit.

Security / performance

No change from last round. No security surface; the added test is test-only.

Not verified

I did not compile or run the Rust suite — a cold cubesql build exceeds this job's budget and there's no cached target/ on this runner. The expected equals operator and the two ISO values in the new assertion are the one thing I'd normally confirm by running; they're consistent with how scalar_to_scalar_value_string renders Date32/TimestampNanosecond, and CI will settle it either way.

· branch `igor/core-732-sql-api-planner-panics-on-date-filters-beyond-2262-04-11-i64`

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

Labels

rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant