voonhous opened a new issue, #19825:
URL: https://github.com/apache/hudi/issues/19825

   ### Bug Description
   
   `HoodieSchemaUtils.hasDecimalField` (`hasDecimalWithCondition` before 
#19809) handles a union by recursing on `schema.getNonNullType()`:
   
   ```java
   case UNION:
     return hasDecimalWithCondition(schema.getNonNullType(), condition);   // 
HoodieSchemaUtils.java:799-800 on master
   ```
   
   `HoodieSchema.getNonNullType()` returns `this` for a union that has no null 
branch (`HoodieSchema.java:1397-1399`), and a union with one null branch and 
two or more non-null branches is reduced to exactly that shape 
(`HoodieSchema.java:1413`, `createUnion(nonNullTypes)`). So any schema 
containing a field typed `["null","string","int"]` (or `["string","int"]`) 
recurses until `StackOverflowError`.
   
   Reachable from `SourceFormatAdapter.java:261`, which evaluates 
`HoodieSchemaUtils.hasDecimalField(sourceSchema)` for every JSON source 
whenever field-name sanitizing is off, i.e. any Hudi Streamer job with a JSON 
source whose provided Avro schema carries a multi-branch union. 
`HoodieSchemaRepair.hasTimestampMillisField` (`HoodieSchemaRepair.java:249`) 
has the identical arm; its caller 
`HoodieFileGroupReaderBasedFileFormat.scala:102` receives Spark-derived 
schemas, which cannot carry complex unions, so it is latent there.
   
   Present since #17600 (`399af74b369f`) introduced the HoodieSchema version. 
Not a regression from #19809, which keeps the arm unchanged.
   
   Minimal reproduction:
   
   ```java
   HoodieSchema schema = HoodieSchema.createRecord("r", null, null, 
Collections.singletonList(
       HoodieSchemaField.of("u", HoodieSchema.createUnion(
           HoodieSchema.create(HoodieSchemaType.NULL),
           HoodieSchema.create(HoodieSchemaType.STRING),
           HoodieSchema.create(HoodieSchemaType.INT)))));
   HoodieSchemaUtils.hasDecimalField(schema);   // StackOverflowError
   ```
   
   Fix direction: iterate the branches instead of collapsing them, the shape 
`HoodieSchema#containsBlobType` (`HoodieSchema.java:1427`) already uses: `case 
UNION: return 
schema.getTypes().stream().anyMatch(HoodieSchemaUtils::hasDecimalField);`, same 
edit in `HoodieSchemaRepair.hasTimestampMillisField`, plus a multi-branch union 
case in `TestHoodieSchemaUtils#testHasDecimalField` and 
`TestHoodieSchemaRepair`.
   
   ### Environment
   
   - Hudi master (`c59987a024cd`), any engine; Hudi Streamer with a JSON source 
is the reachable path
   
   ### Logs and Stack Trace
   
   ```
   java.lang.StackOverflowError
     at 
org.apache.hudi.common.schema.HoodieSchema.getNonNullType(HoodieSchema.java:1391)
     at 
org.apache.hudi.common.schema.HoodieSchemaUtils.hasDecimalWithCondition(HoodieSchemaUtils.java:800)
     at 
org.apache.hudi.common.schema.HoodieSchemaUtils.hasDecimalWithCondition(HoodieSchemaUtils.java:800)
     ...
   ```
   


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