LuciferYang opened a new pull request, #9626:
URL: https://github.com/apache/paimon/pull/9626

   ### Purpose
   
   close #9625
   
   `ZIndexer`'s DECIMAL branch fed `Decimal.toUnscaledBytes()`, a minimal 
two's-complement array, into the fixed 8-byte z-value buffer:
   
   ```java
   ZOrderByteUtils.byteTruncateOrFill(((Decimal) o).toUnscaledBytes(), 
PRIMITIVE_BUFFER_SIZE, reuse)
   ```
   
   `byteTruncateOrFill` left-aligns and zero-pads, and z-values are compared 
unsigned, so the encoding is not order-preserving. On DECIMAL(20,2), `-1.00` 
becomes `9C 00 ...` (156 unsigned) and `1.00` becomes `64 00 ...` (100), 
putting the negative above the positive; `100.00` becomes `27 10 00 ...` and 
lands below `1.00` because it is longer; and `0.00` becomes eight zero bytes, 
which is exactly the `NULL_BYTES` sentinel.
   
   Decimals now go through the same sign-flipped fixed-width transform as the 
other numeric types, `ZOrderByteUtils.longToOrderedBytes`, on the unscaled 
value. Scale is fixed per column, so ordering by unscaled value is ordering by 
numeric value.
   
   Unscaled values wider than a long are clamped into `[Long.MIN_VALUE + 1, 
Long.MAX_VALUE]` instead of being narrowed, which keeps the mapping 
non-decreasing: the extremes collapse onto each other rather than wrapping 
around and sorting below small values. `Long.MIN_VALUE` itself is left out of 
the range because `longToOrderedBytes` maps it to eight zero bytes, which is 
the null sentinel.
   
   This only changes the sort key used while clustering, so nothing on disk 
changes format and no data is rewritten differently beyond the intended layout.
   
   ### Tests
   
   `TestZOrderByteUtil.testZIndexerDecimalOrdering` builds a two-column 
DECIMAL(20,2) `ZIndexer` and compares whole interleaved z-values unsigned: 
`(-1.00, 0.00)` must sort below `(0.00, 1.00)`, and the all-null row must sort 
below both, which pins zero apart from the sentinel. Two more rows cover the 
clamp: an unscaled value too wide for a long sorts above the small positives, 
its negative counterpart sorts below the small negatives, and both stay above 
the null sentinel.
   
   Against the unfixed indexer the first comparison already fails, since 
`-1.00` encodes above `0.00`.
   
   `mvn -pl paimon-common -Dtest=TestZOrderByteUtil test` on JDK 8: 15 tests, 0 
failures. `spotless:check` and `checkstyle:check` on paimon-common are clean.
   
   Not included: `HilbertIndexer` encodes decimals as 
`toBigDecimal().longValue()`, dropping the fraction, so every magnitude below 1 
collapses to one key. Same area, different bug, and it deserves its own change.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to