SEPURI-SAI-KRISHNA opened a new issue, #12968:
URL: https://github.com/apache/seatunnel/issues/12968

   ### Search before asking
   
   - [x] I searched the open and closed issues and pull requests and found no 
report of this. Queries included `arrow struct null`, `arrow map null`, 
`StructConverter null`, `MapConverter null`, `arrow converter null`, `doris 
struct null`, `starrocks struct null` and `ROW type null arrow`, on both the 
issue search and the separate pull request search. #11219 touches 
`StructConverter` and `MapConverter` but only changes their SPI registration.
   
   ### What happened
   
   `ArrowToSeatunnelRowReader` dispatches a column by its SeaTunnel `SqlType`: 
`MAP` goes to `MapConverter`, `ROW` to `StructConverter`, `ARRAY` to the list 
converters. Those three cases call the three argument `convert(rowIndex, 
fieldVector, genericsConverters)` overload, which carries the element type 
converters.
   
   Two of the five complex converters do not check the Arrow validity bit in 
that overload:
   
   - **`StructConverter`**: the overload calls 
`fieldVector.getObject(rowIndex)` and then `entrySet()` on the result. For a 
null cell `getObject` returns null, so the read ends with a 
`NullPointerException`. One null struct cell costs the whole split, not one 
value.
   - **`MapConverter`**: the overload positions a `UnionMapReader` and loops on 
`reader.next()`, which yields nothing for a null cell, so the method returns an 
empty `HashMap`. A column that holds no map and a column that holds an empty 
map become the same value.
   
   The three list converters all guard this case and return `null`. The 
inconsistency has been there since the Arrow reader was added in #8137, and 
that single commit introduced all five:
   
   | Converter | two argument overload | generics overload |
   |---|---|---|
   | `ListConverter` | guards null | **guards null** |
   | `LargeListConverter` | guards null | **guards null** |
   | `FixedSizeListConverter` | guards null | **guards null** |
   | `StructConverter` | guards null | **no guard** |
   | `MapConverter` | guards null | **no guard** |
   
   `git log -S'isNull'` on the two files shows no guard was ever added to the 
generics overload and later removed, so this is an oversight rather than a 
deliberate choice.
   
   **Who is affected.** `ArrowToSeatunnelRowReader` has exactly two consumers 
in `src/main`: `DorisValueReader` and `StarRocksBeReadClient`. So a nullable 
`STRUCT` column in a Doris or StarRocks source fails the read, and a nullable 
`MAP` column silently reads as an empty map.
   
   **Why no test caught it.** `ArrowToSeatunnelRowReaderTest` has no 
`STRUCT`/`ROW` column at all. Its `MAP` column is declared in the schema holder 
but never populated: no `MapVector` is ever constructed, the `writeKeyAndValue` 
helper is dead code, `mapData` is never written to, and the assertion is a `// 
todo check map` noting that "The java api has problems building MapVectors,and 
there are no examples on the official website" (apache/arrow#44664). 
`DorisMultiReadIT` declares 14 nullable `MAP` columns, but builds its maps once 
outside the row loop and inserts the same non-null single entry maps into all 
100 rows, so no null map ever reaches the converter.
   
   ### SeaTunnel Version
   
   Reproduced on `dev` at `14a27ac26a0a71b56722f86cdf8ec2779094ceaf`.
   
   ### SeaTunnel Config
   
   The user-facing shape is a Doris or StarRocks source over a table with a 
nullable complex column, for example:
   
   ```hocon
   source {
     Doris {
       fenodes = "doris:8030"
       username = "root"
       password = ""
       database = "test"
       table = "events"
       # events has a nullable `profile STRUCT<age:INT>` and a nullable `labels 
MAP<INT,INT>`
     }
   }
   ```
   
   I did not run a live Doris cluster. The reproduction below instead drives 
the same production code path directly through `ArrowToSeatunnelRowReader`'s 
byte array constructor, which is the constructor both sources use, so no 
connector or container is required to observe either defect.
   
   ### Running Command
   
   A single record batch Arrow stream with an `id` column plus one nullable 
complex column, read through the production constructor. With a test of that 
shape placed in `connector-common`:
   
   ```shell
   JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./mvnw test \
     -pl seatunnel-connectors-v2/connector-common \
     -Dtest=ArrowToSeatunnelRowReaderNullCellTest -Dskip.spotless=true
   ```
   
   Because the stream holds a single batch, neither failure can be attributed 
to a record batch boundary.
   
   ### Error Exception
   
   The `ROW` column aborts the read:
   
   ```
   java.lang.NullPointerException: Cannot invoke "java.util.Map.entrySet()" 
because "valueMap" is null
   ```
   
   `valueMap` followed by `entrySet()` occurs in exactly one place in the 
repository, `StructConverter.java:43`, so the message identifies the site on 
its own.
   
   The `MAP` column does not throw, it returns the wrong value:
   
   ```
   org.opentest4j.AssertionFailedError: a null map cell must read as null, not 
as an empty map ==> expected: <null> but was: <{}>
   ```
   
   **Expected**: both read back as `null`, as the list converters already do, 
while a cell holding a genuinely empty map keeps reading as an empty map so 
that absent and empty stay distinct.
   
   ### Zeta or Flink or Spark Version
   
   Not engine specific. The defect is in `connector-common`, below the engine, 
on the source read path.
   
   ### Java or Scala Version
   
   `openjdk version "17.0.20.1" 2026-08-18`, OpenJDK 64-Bit Server VM build 
`17.0.20.1+1-1-24.04-Ubuntu`, with Apache Maven 3.8.4.
   
   ### Screenshots
   
   _No response_
   
   ### Are you willing to submit PR?
   
   - [x] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [x] I agree to follow this project's [Code of 
Conduct](https://www.apache.org/foundation/policies/conduct)
   


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