Skip to content

fix: scan nested struct columns as full-range chunk sources (#207)#219

Merged
dfa1 merged 2 commits into
mainfrom
fix/207-nested-struct
Jul 6, 2026
Merged

fix: scan nested struct columns as full-range chunk sources (#207)#219
dfa1 merged 2 commits into
mainfrom
fix/207-nested-struct

Conversation

@dfa1

@dfa1 dfa1 commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Fixes #207, found by the Raincloud conformance suite (#205) on countries-of-the-world.

Root cause: ScanIterator.collectFlats recognized flat/dict/zoned/chunked layouts but not struct, so a top-level column that is itself a struct collected zero chunk leaves and chunk planning rejected the 0-vs-N mismatch.

Fix (mirrors the Rust StructReader: field children decode over the parent's full row range; a nested struct is never chunked independently):

  • collectFlats treats a nested struct layout as a single full-range chunk source;
  • new StructLayoutDecoder (registered in LayoutRegistry.registerDefaults()) reassembles a StructArray via ctx.decodeChild, applying struct-level validity to fields when nullable;
  • ScanIterator.sliceArray slices StructArray per chunk by recursively slicing each field.

Zone-map pruning and filtered scans keep recognizing built-in layouts only (documented SPI scope) — nested struct columns plan conservatively.

Validation: 5 new tests (StructLayoutDecoderTest + registry default); reader suite green; full integration verify green (no scan regressions). countries-of-the-world now scans and selects correctly; its CSV export stops at a separate, newly-split gap — CsvExporter has no StructArray rendering — filed as #217 and the matrix entry reclassified gap:207 → gap:217. Conformance suite 21/21.

Closes #207

🤖 Generated with Claude Code

dfa1 and others added 2 commits July 6, 2026 22:34
`countries-of-the-world` (vortex-data 0.69.0) has a top-level struct column
`data` that is itself a `vortex.struct` layout. Scan threw
`VortexException: scan: column 'data' has 0 flats but the widest column has 1`
from `ScanIterator.buildChunks`; `schema`/`count`/`inspect` were unaffected.

Root cause: `ScanIterator.collectFlats` recognized flat, dict, zoned, and
chunked layouts but not struct. A nested struct column's top layout is
`vortex.struct`, so it collected zero leaves and chunk planning saw a
0-vs-N width it refused.

Fix: treat a nested `vortex.struct` layout as a single full-range chunk
source (like a dict leaf) rather than descending into its per-field
children — those children are separate physical columns, not row chunks,
and span the same row range as the parent. This mirrors the Rust reference
(`vortex-layout/src/layouts/struct_/reader.rs`: `StructReader` decodes all
field children over the parent's full range and inserts a leading `Bool`
validity child only when the struct dtype is nullable). Decode routes
through the layout registry's new `StructLayoutDecoder`, which reassembles
a `StructArray` from the field children (masking each field with the
struct-level validity when present). `sliceArray` gains a `StructArray`
arm so the shared full-range struct column slices per chunk.

Evidence on the real file: `count` = 262, `select region country_code`
renders correct values, and the #207 chunk-planning exception is gone —
the scan decodes the struct column into a `StructArray`. CSV export of the
struct column itself is still unsupported (a separate rendering limitation,
not chunk planning): `CsvExporter.cellValue` throws its clear
`unsupported array type: StructArray`.

Closes #207

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The #207 scan fix unblocks decode; the remaining export failure is CSV
rendering of StructArray columns, tracked separately as #217.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dfa1 dfa1 force-pushed the fix/207-nested-struct branch from 841495a to 53e7c0e Compare July 6, 2026 20:35
@dfa1 dfa1 merged commit 0646243 into main Jul 6, 2026
6 checks passed
@dfa1 dfa1 deleted the fix/207-nested-struct branch July 7, 2026 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ScanIterator: nested struct column fails chunk planning ("0 flats" vs widest column)

1 participant