Repository navigation
fix: all-null chunks for every column type - #595
Merged
Merged
Conversation
…ray as null A null-scalar vortex.constant (Rust's and now our writer's all-null chunk) read as a NullArray for a decimal column, so consumers that unwrap a MaskedArray failed on it. It now gets a zero placeholder in Rust's value width for its precision (1 to 32 bytes) under an all-false validity, like the other primitive types. A type with no placeholder (list, fixed-size list, struct, map, variant, uuid's fixed-size-list storage) stays a NullArray instead of throwing, as a placeholder lookup on those would. Filters treated a NullArray as a non-nullable array: IS NULL selected none of its rows (an all-null uuid chunk read as having no null). The compute kernels learn where nulls are from one place, NumericColumns.validityOf, which now gives a NullArray an all-false validity; Values.isNullAt reads through it, so filters, aggregates and group-by all see every row of a NullArray as null. ConstantEncodingDecoderTest decodes a null constant for every ptype, bool, utf8, binary, decimal, date/time/timestamp/custom extensions, and the NullArray fallbacks; ComputeTest checks each predicate on a NullArray against the per-row oracle. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rust's compressor checks for all-null before an extension's own scheme, so an all-null date, time, timestamp or uuid chunk is one null-scalar vortex.constant carrying the extension dtype. Java wrapped that constant in vortex.ext. ExtEncodingEncoder now returns the null constant itself when the storage is all invalid and the write compresses, sharing the all-null test with MaskedEncodingEncoder. NullSparseRunEndInteropIntegrationTest now writes an all-null column of 16 types through vortex-jni and Java (every integer width signed and unsigned, F32, F64, bool, utf8, binary, decimal, date, time, timestamp), requires the same data encodings, and checks both readers see every row of both files as null. ExtEncodingEncoderTest covers each well-known extension and a custom one, on both the terminal and the cascade path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ull round trip MaskedEncodingEncoderTest encodes an all-null chunk for every value carrier (each primitive array, F16 bits, boolean, String and UTF-8 bytes, binary, decimal) and requires one null constant that reads back all null; an uncompressed write, a single valid row (first, middle, last), an all-valid and an empty chunk keep the mask. AllNullColumnRoundTripTest writes 18 column types through VortexWriter in three shapes (all null, null then values, values then null; 10,000-row batches, so chunks keep their own null shape across 8,192-row zones) and checks every row's nullness, IS NULL / IS NOT NULL counts through zone pruning, and a comparison every value passes, which an all-null chunk must not add to. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rust's DecimalType::smallest_decimal_value_type (the 1/2/4/8/16/32-byte integer a precision fits) was written out four times: Repartitioner's decimalBytes, DecimalEncodingEncoder's valuesType and byteWidth (and the storageWidth wrapper ZoneMapStats called), and the null-constant decimal placeholder in ConstantEncodingDecoder. It now lives once on the dtype, in core, where both the writer and the reader see it; the encoder derives the metadata's values type as the width's log2. The precision-boundary test moves to DTypeDecimalTest. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
dfa1
force-pushed
the
test/all-null-every-type
branch
from
October 23, 2026 19:57
1020a37 to
fe7551a
Compare
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.
Follow-up to #594, covering every column type.
NullArrayinstead of throwing, and filters now treat aNullArrayas null (IS NULL selected none of an all-null uuid chunk's rows).vortex.constantcarrying the extension dtype, as Rust writes it, not wrapped invortex.ext.VortexWriter/VortexReader(nullness per row, IS NULL / IS NOT NULL through zone pruning, comparisons).vortex-jni parity: the same all-null column of 16 types written by both writers has the same data encodings, and both readers see every row as null.
SQL smoke (jdbc:vortex: over a file with every type all-null plus mixed null/value chunks): count, min, max, IS NULL and comparisons all correct.
🤖 Generated with Claude Code