andygrove opened a new issue, #7032:
URL: https://github.com/apache/datafusion-comet/issues/7032

   ### Describe the bug
   
   When a Parquet BINARY column without the UTF8 annotation is read as STRING, 
which a read schema that declares `string` or 
`spark.sql.parquet.binaryAsString=true` does, the native Parquet scan returns 
NULL for any nested value that is not valid UTF-8. Spark returns the bytes 
unchanged. Nothing fails, so the NULLs are silent. Top-level values take a 
different path that skips UTF-8 validation entirely.
   
   - **Nested values** (a struct field, list element or map value) are 
converted by `parquet_convert_array_impl`, which falls back to Arrow's 
`cast_with_options` with `PARQUET_OPTIONS` 
(`native/core/src/parquet/parquet_support.rs` lines 74-79 and 333-336). Those 
options set `safe: true`, so a value that is not valid UTF-8 becomes NULL.
   - **Top-level values** are decoded by arrow-rs straight into a `Utf8` array. 
arrow-rs validates UTF-8 only for columns annotated UTF8 (`parquet` 59.3.0 
`arrow/array_reader/byte_array.rs` line 192), so in a release build the invalid 
bytes reach a `Utf8` array unchecked, the unsound state #4764 describes. A 
debug build panics instead, in `OffsetBuffer::into_array`, which validates only 
under `debug_assertions` (`arrow/buffer/offset_buffer.rs` line 141).
   
   ### Steps to reproduce
   
   In a `CometTestBase` suite:
   
   ```scala
   spark.sql("SELECT X'41FF42' AS t, named_struct('b', X'41FF42') AS s, 
array(X'41FF42') AS l")
     .coalesce(1).write.parquet(path)
   spark.read.schema("t string, s struct<b:string>, l 
array<string>").parquet(path)
     .selectExpr("hex(s.b)", "hex(l[0])", "s.b IS NULL")
     .collect()
   ```
   
   On `main` at 66c63bd307, the same on Spark 3.4.3, 3.5.9 and 4.1.3:
   
   | Query | Spark | Comet native scan |
   | --- | --- | --- |
   | `hex(s.b), hex(l[0]), s.b IS NULL` | `[41FF42,41FF42,false]` | 
`[null,null,true]` |
   
   ### Expected behavior
   
   The native scan does not turn a nested value into NULL because its bytes are 
not valid UTF-8, and the top-level path does not admit invalid UTF-8 into a 
`Utf8` array. #4764 proposes decoding at the ingress boundary with 
`decode_utf8_spark_lossy`, the decoder `CAST(binary AS string)` and native 
shuffle already share, which would cover both paths.
   
   ### Additional context
   
   Found in a nested-type audit of the native scans. This is another ingress 
point for the policy #4764 tracks. #4121 covers UTF8-annotated STRING columns, 
which the native reader rejects with `encountered non UTF-8 data`. The 
BINARY-read-as-STRING path is not covered there.
   


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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to