Skip to content

Guard the DecimalByteParts nullability cast rule - #10746

Closed
connortsui20 wants to merge 1 commit into
developfrom
ct/dbp-nullability-cast
Closed

connortsui20 wants to merge 1 commit into
developfrom
ct/dbp-nullability-cast

Conversation

@connortsui20

@connortsui20 connortsui20 commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Summary

The DecimalByteParts cast rule pushed every nullability cast into its most significant part (MSP), including casts to non-nullable that it could not prove safe. The cast-rule contract on Validity::cast_nullability says that a CastReduce rule, which runs in the optimizer without execution, must decline when Validity::trivially_cast_nullability cannot decide, and that a CastKernel handles the cast at execution. No wrong result is visible today, because the null check still runs when the MSP cast executes, but the rule relied on every MSP encoding keeping that check.

Changes

The rule now declines when trivially_cast_nullability returns None. A new CastKernel checks the validity with cast_nullability and then rebuilds the array over the cast MSP, reusing the lower parts. Casts that change the precision or the scale stay unsupported.

When the MSP has a validity array, a cast to non-nullable now stays a lazy Cast over the DecimalByteParts array until execution, instead of becoming a DecimalByteParts array in the optimizer. The MSP's own cast kernel checks the validity a second time, which for a primitive MSP is a lookup of the cached minimum.

The cast tests now use a session that registers the crate, so they reach the new kernel. Seven other encodings push nullability casts the same way, tracked in #10750.

🤖 Generated with Claude Code

The DecimalByteParts cast rule cast the most significant part for every
target nullability, even when `Validity::trivially_cast_nullability`
could not prove the cast safe. The rule now declines in that case, and a
new `CastKernel` handles it at execution with `cast_nullability`. Casts
that change the precision or the scale stay unsupported.

The cast tests now use a session that registers the crate, so they reach
the new kernel.

Signed-off-by: Connor Tsui <[email protected]>
@codspeed

codspeed Bot commented Oct 23, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 1.68%

4 warnings, 1 note

⚠️ Walltime results may be unreliable

Some benchmarks used the Walltime instrument outside CodSpeed Macro Runners, which can make the results inconsistent.

Learn more about Macro Runners

See affected benchmarks

⚠️ Unable to measure the execution of 2 benchmarks

These benchmarks measured no execution time, so their results are not comparable and count as unchanged. This usually happens when the compiler removes the code under test.

Prevent compiler optimizations

See affected benchmarks

⚠️ 21 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

⚠️ Base and head ran on different runner types

Some benchmarks with significant performance changes were compared across different runner types, so the changes might not come from the code. Run base and head on the same runner type, or use CodSpeed Macro Runners for more stable results.

Learn more about Macro Runners

Open the report in CodSpeed to investigate

ℹ️ 40 benchmarks have no flamegraph

The flamegraph wasn't generated: the symbols of the profiling trace could not be resolved, because no information about the language frames was collected.

See affected benchmarks

⚡ 3 improved benchmarks
❌ 6 regressed benchmarks
✅ 2399 untouched benchmarks
⏩ 12 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ CPU Simulation test_scan_filter_to_arrow_array[int_float] 3.5 ms 4.2 ms -16.39%
❌ Walltime starts_with_avx512[8, VarBin] 39.5 µs 45.8 µs -13.62%
❌ Walltime starts_with_avx2[64, VarBin] 54.1 µs 62.6 µs -13.58%
❌ CPU Simulation test_repeated_scan_filter[int_float] 3.4 ms 3.9 ms -12.89%
❌ CPU Simulation test_repeated_scan_filter[int] 2.4 ms 2.7 ms -10.22%
❌ CPU Simulation test_scan_filter_to_arrow_array[int] 2.5 ms 2.8 ms -10.11%
⚡ CPU Simulation bench_compare_primitive[(10000, 32)] 97 µs 72.9 µs +33.09%
⚡ CPU Simulation chunked_dict_primitive_canonical_into[f64, (1000, 1000, 10)] 191.7 µs 151.6 µs +26.44%
⚡ Walltime starts_with_avx2[8, VarBin] 46.9 µs 40.3 µs +16.29%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing ct/dbp-nullability-cast (87589b7) with develop (3974ee0)

Open in CodSpeed

Footnotes

  1. 12 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@connortsui20
connortsui20 marked this pull request as ready for review October 23, 2026 20:55
robert3005
robert3005 previously approved these changes Oct 25, 2026
@connortsui20
connortsui20 dismissed robert3005’s stale review October 25, 2026 23:46

some other thoughts

@connortsui20

Copy link
Copy Markdown
Member Author

im wondering if we should just solve #10750 more directly? i dont know if this is the correct general fix

@robert3005

Copy link
Copy Markdown
Contributor

I have been auditing them in the past. If you have an idea how to fix it make a pr

@robert3005

Copy link
Copy Markdown
Contributor

we should also just merge this since it fixes a bug

@connortsui20

Copy link
Copy Markdown
Member Author

Actually I think this is not a bug, we still get the same result no matter what because the pushed down cast fails regardless. I think this is a question of implementation / who should handle this generally

@connortsui20

Copy link
Copy Markdown
Member Author

ok we talked offline, even though this change is technically fine, it doesnt really do that much (it is not actually a bug) and we should just make sure everything similar to this is handled in the same way.

@connortsui20
connortsui20 deleted the ct/dbp-nullability-cast branch October 26, 2026 14:00

Copy link
Copy Markdown
Member Author

Follow-up: #10798 documents this on CastReduce. A rule that builds a new Validity keeps the trivially_cast_nullability guard and a CastKernel. A rule that pushes the cast into the children that hold its validity relies on the casts of those children, as the DecimalByteParts rule on develop already does.


Generated by Claude Code

connortsui20 added a commit that referenced this pull request Oct 26, 2026
## Summary

- Closes #10750
- Replaces #10746

The docs on `Validity::cast_nullability` read as if every `CastReduce`
rule that removes nullability must call
`Validity::trivially_cast_nullability` and pair with a `CastKernel`.
Most push-down rules (FoR, ALP, ALP-RD, ZigZag, RLE, RunEnd,
DateTimeParts, DecimalByteParts, Chunked, Sparse, Extension) instead
cast the child that holds their validity, and the cast of that child
already fails on nulls, so no result is wrong. Guarding each rule, as
#10746 does for DecimalByteParts, adds a kernel per encoding and delays
the rewrite until execution without changing any result.

The guard in #10746 comes from the closed #10230, where a canonical
decimal held a lazy child that a cast to canonical did not execute, by
way of the FX2 notes in #10633. `develop` keeps one buffer per decimal,
so that reason no longer applies.

## Changes

`CastReduce` now owns the contract and documents both forms of rule. A
rule that builds a new `Validity` keeps the guard and the kernel, and a
rule that pushes the cast into its children needs neither when the nulls
of those children are exactly the null rows of the array. `Dict` is the
documented exception, because its values can hold nulls that no code
references. No new tests are needed: every push-down encoding listed
above already runs `test_cast_conformance` on a partially valid array,
and that suite asserts that the cast to non-nullable fails.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01V1YHcosAAKufkyKPorUC2n)_
@connortsui20 connortsui20 mentioned this pull request Oct 26, 2026
20 of 34 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants