voonhous commented on issue #19442:
URL: https://github.com/apache/hudi/issues/19442#issuecomment-6165989504

   **Leaf type map for `Spark4VariantShreddingProvider`** (master `61dde86`, 
from code reading; not run)
   
   - **Write:** `HoodieAvroWriteSupport` shreds a variant into the 
`typed_value` leaf declared by the Avro schema (`avroTypeToScalarType`, then 
`convertScalarToAvro`).
   - **Read:** `HoodieVariantReconstruction` rebuilds the variant from a base 
file. The leaf's Avro type comes from the footer converter, then the same 
`avroTypeToScalarType` and the `AvroVariantRow` getters feed Spark's 
`ShreddingUtils.rebuild`.
   
   ### Write: Avro `typed_value` type, then ScalarType, then the value handed 
to the Avro writer
   
   ```mermaid
   flowchart LR
       WOK["boolean, int, long, float, double, string, bytes<br/>decimal on 
bytes or fixed, date<br/>timestamp-micros, local-timestamp-micros<br/>uuid on 
string"] --> WOKS["matching ScalarType"] --> WOKR["OK"]
       WF["fixed, no logical type"] --> WFS["BinaryType"] --> WFV["byte[] 
wrapped as ByteBuffer"] --> WFR["ClassCastException:<br/>ByteBuffer is not 
GenericFixed<br/>size never checked"]
       WU["uuid on fixed(16)"] --> WUS["UuidType"] --> WUV["String from 
UUID.toString()"] --> WUR["UnresolvedUnionException"]
       WT["time-millis on int<br/>time-micros on long"] --> 
WTS["IntegralType<br/>no time branch"] --> WTV["Integer or Long"] --> 
WTR["writes, but variant integers<br/>land in a TIME column"]
       WD["timestamp-millis, local-timestamp-millis<br/>enum, map"] --> 
WDS["null: not shredded"] --> WDR["value stays in the residual<br/>by design"]
   
       classDef ok fill:#bbf7d0,stroke:#15803d,color:#111827
       classDef bad fill:#fecaca,stroke:#b91c1c,color:#111827
       classDef wrong fill:#fde68a,stroke:#b45309,color:#111827
       classDef skip fill:#e5e7eb,stroke:#4b5563,color:#111827
       class WOK,WOKS,WOKR ok
       class WF,WFS,WFV,WFR,WU,WUS,WUV,WUR bad
       class WT,WTS,WTV,WTR wrong
       class WD,WDS,WDR skip
   ```
   
   ### Read: parquet `typed_value` type, then Avro type from the footer 
converter, then ScalarType, then the rebuilt value
   
   ```mermaid
   flowchart LR
       ROK["boolean, int32, int64, float, double<br/>string, binary, 
DATE<br/>DECIMAL on BINARY or FLBA, FLBA needs PR 20324<br/>TIMESTAMP(MICROS), 
UUID on FLBA(16)"] --> ROKS["matching ScalarType"] --> ROKR["OK"]
       RF["FLBA, no annotation"] --> RFA["fixed"] --> RFS["BinaryType"] --> 
RFR["getBinary casts to ByteBuffer:<br/>ClassCastException on GenericFixed"]
       RD["DECIMAL on INT32 or INT64"] --> RDA["int or long<br/>converter drops 
DECIMAL"] --> RDS["IntegralType"] --> RDR["silent wrong value:<br/>unscaled 
integer, 1.50 becomes 150"]
       RT["TIME(MILLIS) or TIME(MICROS)"] --> RTA["time-millis or time-micros"] 
--> RTS["IntegralType"] --> RTR["time rebuilt as an integer"]
       RN["TIMESTAMP(NANOS)"] --> RNA["long<br/>converter drops it"] --> 
RNS["IntegralType"] --> RNR["timestamp rebuilt as an integer"]
       RM["TIMESTAMP(MILLIS)"] --> RMA["timestamp-millis"] --> RMS["null: no 
ScalarType"] --> RMR["NPE in Spark rebuild<br/>when typed_value is non-null"]
   
       classDef ok fill:#bbf7d0,stroke:#15803d,color:#111827
       classDef bad fill:#fecaca,stroke:#b91c1c,color:#111827
       classDef wrong fill:#fde68a,stroke:#b45309,color:#111827
       class ROK,ROKS,ROKR ok
       class RF,RFA,RFS,RFR,RD,RDA,RDS,RDR,RM,RMA,RMS,RMR bad
       class RT,RTA,RTS,RTR,RN,RNA,RNS,RNR wrong
   ```
   
   Green: correct. Red: fails or returns a wrong value. Amber: no error, but 
the leaf's type is lost. Grey: not shredded, by design.
   
   | Leaf | Direction | Outcome | Reachable from |
   |---|---|---|---|
   | `fixed`, no logical type | write | ClassCastException, no size check | 
Hand-declared Avro schema only |
   | uuid on `fixed(16)` | write | UnresolvedUnionException | Hand-declared 
Avro schema only |
   | FLBA, no annotation | read | ClassCastException | Files written by other 
engines |
   | DECIMAL on INT32 / INT64 | read | Silent wrong value (unscaled integer) | 
Files written by other engines; Hudi writes decimals as FLBA |
   | TIME (millis / micros) | write and read | Stored and rebuilt as integers | 
Hand-declared Avro schema; other engines' files |
   | TIMESTAMP(NANOS) | read | Rebuilt as an integer | Files written by other 
engines |
   | TIMESTAMP(MILLIS) | read | NPE in `ShreddingUtils.rebuild` | Files written 
by other engines |
   
   Notes:
   - The first three rows are this issue's report; the rest turned up while 
mapping. Only the DECIMAL on INT32 / INT64 row returns a wrong value without an 
error.
   - The read-side uuid failure in the original report (`GenericFixed` in 
`getUuid`) is not reachable through files: the footer converter maps FLBA(16) 
UUID to an Avro string, and parquet-avro's `FieldUUIDConverter` reads it as one.
   - Declining plain `fixed` and uuid on `fixed` at write time covers the first 
two rows only. For DECIMAL on INT and NANOS, the converter has already dropped 
the annotation, so the provider cannot see it. TIME keeps its Avro logical 
type, but Spark's `VariantSchema` has no time scalar to map it to.
   


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