Skip to content

Aggregate nested columns under nullable parents with a definedness mask - #10961

Open
robert3005 wants to merge 1 commit into
developfrom
rk/aggregate-demand-mask
Open

robert3005 wants to merge 1 commit into
developfrom
rk/aggregate-demand-mask

Conversation

@robert3005

@robert3005 robert3005 commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Struct fields are stored unmasked, so aggregates over them saw values under null struct rows. Each chunk of a sequential write stream now carries a definedness mask, false in the rows an ancestor nulls out, and DynAccumulator gains accumulate_defined to aggregate the logical column without masking first.

Aggregates give definedness meaning through AggregateFnVTable::try_accumulate_defined. By default undefined rows read as null, which requires the same partial dtype for a nullable input as for the non-nullable one; a test asserts this for every built-in aggregate that keeps the default. Combined aggregates hand the definedness to their children, and UncompressedSizeInBytes measures the stored batch, which definedness does not change.

The struct writer intersects the definedness with its validity for each field, the list writer drops the elements of null and undefined lists so every element written is defined, and re-chunking writers carry the mask with the rows. Zone maps and file statistics are now written for children of nullable structs, and the fuzzer generates nullable structs.

fixes #9205

@robert3005 robert3005 added changelog/feature A new feature changelog/fix A bug fix and removed changelog/feature A new feature labels Oct 29, 2026
@robert3005
robert3005 force-pushed the rk/aggregate-demand-mask branch from 113bdd2 to 47befaf Compare October 29, 2026 14:03
@codspeed

codspeed Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

1 warning

⚠️ 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

⚡ 2 improved benchmarks
❌ 1 regressed benchmark
✅ 1814 untouched benchmarks
🆕 6 new benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ CPU Simulation random_i8[0.01] 105.5 µs 120.1 µs -12.15%
⚡ CPU Simulation encode_primitives[f32, (2000, 2)] 211.5 µs 180.8 µs +16.99%
⚡ CPU Simulation max_f64 316.2 µs 283.3 µs +11.62%
🆕 CPU Simulation defined[null_count] N/A 89.7 µs N/A
🆕 CPU Simulation defined[sum] N/A 615.8 µs N/A
🆕 CPU Simulation list_elements_definedness_by_validity[0.5] N/A 843.4 µs N/A
🆕 CPU Simulation list_elements_definedness_by_validity[0.99] N/A 97 µs N/A
🆕 CPU Simulation nullable[null_count] N/A 45.2 µs N/A
🆕 CPU Simulation nullable[sum] N/A 579 µs N/A

Tip

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


Comparing rk/aggregate-demand-mask (2ea5835) with develop (2609154)

Open in CodSpeed

@robert3005
robert3005 force-pushed the rk/aggregate-demand-mask branch 5 times, most recently from a603eae to c25fb66 Compare November 2, 2026 17:06
@robert3005 robert3005 changed the title Aggregate nested columns under nullable parents with a demand mask Aggregate nested columns under nullable parents with a definedness mask Nov 2, 2026
Struct fields are stored unmasked, so aggregates over them saw values under
null struct rows. Each chunk of a sequential write stream now carries a
definedness mask, false in the rows an ancestor nulls out, and DynAccumulator
gains accumulate_defined to aggregate the logical column without masking
first.

Aggregates give definedness meaning through
AggregateFnVTable::try_accumulate_defined. By default undefined rows read as
null, which requires the same partial dtype for a nullable input as for the
non-nullable one, and a test asserts this for every built-in aggregate that
keeps the default. Combined aggregates hand the definedness to their children,
and UncompressedSizeInBytes measures the stored batch, which definedness does
not change.

The struct writer intersects the definedness with its validity for each
field, the list writer drops the elements of null and undefined lists so every
element written is defined, and re-chunking writers carry the mask with the
rows. Zone maps, in either layout, and file statistics are now written for children
of nullable structs, and the fuzzer generates nullable structs.

Signed-off-by: Robert Kruszewski <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01X1HnweRGxeDWgQwXXM6f5s
@robert3005
robert3005 force-pushed the rk/aggregate-demand-mask branch from c25fb66 to 2ea5835 Compare November 5, 2026 13:28

This branch has not been deployed

No deployments
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.

Children of nullable Struct may have null values propagated to zone maps

1 participant