linliu-code opened a new issue, #19899:
URL: https://github.com/apache/hudi/issues/19899

   `HoodieAvroRecord.doGetOrderingValue` returns the payload's ordering value 
unconditionally. A
   payload built through `HoodieRecordUtils.loadPayload(String, 
GenericRecord)`, the overload used
   whenever a record is created without an explicit ordering value, defaults to
   `OrderingValues.getDefault()`, which is `Integer` 0.
   
   Its sibling `HoodieAvroIndexedRecord.doGetOrderingValue` instead reads the 
ordering fields off the
   record, so the two Avro record representations disagree on both the ordering 
value and its type for
   the same input.
   
   When such a record reaches the merge path, its `Integer` 0 is compared 
against the base record's
   ordering value read from storage, which is typed by the ordering field. For 
any ordering column
   that is not an `int`, this throws:
   
   ```
   java.lang.ClassCastException: class java.lang.Long cannot be cast to class 
java.lang.Integer
     at java.base/java.lang.Integer.compareTo(Integer.java:71)
     at 
org.apache.hudi.common.table.read.BufferedRecordMergerFactory.shouldKeepNewerRecord(BufferedRecordMergerFactory.java:515)
     at 
org.apache.hudi.common.table.read.BufferedRecordMergerFactory$EventTimeRecordMerger.finalMerge(BufferedRecordMergerFactory.java:194)
     at 
org.apache.hudi.common.table.read.buffer.FileGroupRecordBuffer.hasNextBaseRecord(FileGroupRecordBuffer.java:242)
     at 
org.apache.hudi.io.FileGroupReaderBasedMergeHandle.doMerge(FileGroupReaderBasedMergeHandle.java:274)
   ```
   
   **How to reproduce.** A copy on write table with a `bigint` precombine 
field, updated through a
   prepped Spark SQL write (`UPDATE` / `MERGE INTO`, which set 
`_hoodie.spark.sql.writes.prepped`).
   Those writes leave `shouldCombine` false, so `HoodieCreateRecordUtils` takes 
the
   `createHoodieRecord` overload that carries no ordering value. Every updated 
row fails.
   
   The same is reachable outside the prepped path: `HoodieCreateRecordUtils` 
computes the ordering
   value with `getNestedFieldVal(..., false, ...)`, which returns `null` for a 
null field value, and
   `loadPayload(clazz, record, null)` then falls through to the same defaulting 
constructor.
   
   `HoodieAvroIndexedRecord` is unaffected because it derives the value from 
the record.
   


-- 
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