Skip to content

fix(writer): three more encoders never reported zone-map MIN/MAX stats - #387

Open
dfa1 wants to merge 4 commits into
mainfrom
fix/zone-map-stats-constant-runend-zigzag
Open

fix(writer): three more encoders never reported zone-map MIN/MAX stats#387
dfa1 wants to merge 4 commits into
mainfrom
fix/zone-map-stats-constant-runend-zigzag

Conversation

@dfa1

@dfa1 dfa1 commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Summary

Same failure mode as #382 (AlpRdEncodingEncoder, already merged): ConstantEncodingEncoder, RunEndEncodingEncoder, and ZigZagEncodingEncoder all hardcoded null, null for zone-map stats regardless of input, silently defeating RowFilter pruning for any column the cascade routed through them. Found via a systematic audit of every writer/src/main/java/io/github/dfa1/vortex/writer/encode/ encoder after fixing #382, grepping for hardcoded null stats on encoders that wrap scalar/comparable data.

Test plan

  • ./mvnw verify green across the whole reactor
  • New unit tests per encoder (Stats nested class in each *EncodingEncoderTest): reports correct min/max, empty-array stats are null, and (RunEnd) an explicit unsigned-comparison regression case
  • Sonar quality gate green prior to this PR (checked before starting)

🤖 Generated with Claude Code

https://claude.ai/code/session_01P4ijFsGW1MHEcGiu26vNzi

encode() built its EncodeResult via EncodeResult.simple(...), which
defaults stats to null regardless of the constant value being encoded
-- for a constant array min == max == that value by construction, no
scan needed, so any column the cascade collapsed to vortex.constant
lost zone-map pruning for free.

Fixes #384.
encode() hardcoded (null, null) regardless of the run values actually
encoded. RunEnd is specifically favored for clustered, low-cardinality
data -- exactly the shape where zone-map pruning otherwise pays off
most -- so this was losing the biggest win for its best-fit workload.

Tracks min/max across every run's value in the loop that already
builds them, with unsigned comparison for U8/U16/U32/U64 (a raw bit
pattern that looks negative signed can be a huge unsigned magnitude).

Fixes #385.
encode() hardcoded (null, null) regardless of the signed input. Stats
must come from the original values, not the zigzag-transformed
output -- the bit-interleaving is not order-preserving (e.g. -1 maps
to 1, 1 maps to 2), so tracking min/max over the transformed output
would have been wrong even if present.

Tracks min/max over the original values in the same per-PType switch
that already computes the zigzag mapping.

Fixes #386.
Same bug, three encoders -- one line naming all three plus their
issue numbers reads better than three near-duplicate paragraphs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant