Skip to content

fix(writer): write a nullable timestamp with nulls as datetimeparts - #635

Merged
dfa1 merged 1 commit into
mainfrom
fix/datetimeparts-nullable
Nov 1, 2026
Merged

dfa1 merged 1 commit into
mainfrom
fix/datetimeparts-nullable

Conversation

@dfa1

@dfa1 dfa1 commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Follow-up to #627 (review finding on #630).

Rust's split_temporal keeps a nullable timestamp's validity on the days child, so a column holding nulls is still vortex.datetimeparts. DateTimePartsEncodingEncoder declined any NullableData, so a chunk with a null fell back to vortex.ext over a masked i64, and since #627 one null in a repartitioned Parquet-import chunk switched it.

Change (DateTimePartsEncodingEncoder)

  • accepts NullableData over long[] timestamp storage: validity on the days child, seconds/subseconds non-nullable
  • an all-valid validity is dropped (Rust's AllValid writes no bitmap); an all-null chunk is left to vortex.ext's null constant
  • min/max bounds skip invalid slots' placeholders
  • the days child takes the column's nullability whatever shape the storage arrives in, as Rust's does

Side effect: every timestamp column's zone-stats table now goes datetimeparts too (ZoneAccumulator hands min/max as NullableData; Rust's TemporalScheme always splits timestamps). TimestampFilterInteropIntegrationTest#timestampColumnsAreStoredAsPartsAndAsFlatLongs checked the whole file and now checks the data column it meant.

Tests

  • DateTimePartsEncodingEncoderTest$Nullable: validity placement, bounds over valid rows, all-valid, all-null.
  • NullableTimestampInteropIntegrationTest: against vortex-jni, the data column's root encoding and validity placement match for four null shapes and the Parquet import path; the cases with nulls fail without the change.
  • Full routine integration suite: 3216 passing.

The full encoding trees still differ from Rust in the days child's cascade (RLE vs FoR) and sequence vs datetimeparts, with or without nulls: #634.

Reviewed independently (vortex-reviewer agent): approved; its should-fix items (test naming, imports, a test that didn't check validity, stale comments) are addressed in this commit.

🤖 Generated with Claude Code

https://claude.ai/code/session_011fRbYryTxfcu5j2CXwkSzd

Rust's split_temporal keeps a nullable timestamp's validity on the days
child, so a column holding nulls is still vortex.datetimeparts. The Java
encoder declined any NullableData, so a chunk with a null fell back to
vortex.ext over a masked i64, and since #627 made the Parquet import hand
nullable timestamps over as NullableData, one null in a repartitioned chunk
switched it.

DateTimePartsEncodingEncoder now accepts NullableData over long[] storage:
the validity goes on the days child (seconds and subseconds stay
non-nullable), an all-valid validity is dropped as Rust's AllValid writes no
bitmap, an all-null chunk is left to vortex.ext's null constant, and the
min/max bounds skip the invalid slots' placeholders. The days child takes
the column's nullability whatever shape the storage arrives in, as Rust's
does (same bytes, a nullable dtype).

The zone-stats table of every timestamp column, nullable or not, now goes
datetimeparts too: ZoneAccumulator hands its min/max columns over as
NullableData, and Rust's TemporalScheme always splits timestamps.
TimestampFilterInteropIntegrationTest checked the whole file for the
encoding and now checks the data column it meant.

The full encoding trees still differ from Rust in the days child's cascade
and in sequence vs datetimeparts, with or without nulls (#634).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011fRbYryTxfcu5j2CXwkSzd
@dfa1
dfa1 merged commit ff3f65e into main Nov 1, 2026
6 checks passed
@dfa1
dfa1 deleted the fix/datetimeparts-nullable branch November 1, 2026 20:12
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.

1 participant