LuciferYang opened a new pull request, #57924:
URL: https://github.com/apache/spark/pull/57924

   ### What changes were proposed in this pull request?
   
   `OptimizeCsvJsonExprs` prunes a `JsonToStructs` schema to the fields being 
selected. Dropping a field stops the parser from converting it, so a malformed 
value there is never detected and the corrupt record column comes back null 
instead of the record text. This PR stops the two JSON branches from pruning in 
that case.
   
   The two branches need different conditions:
   
   - The `GetStructField` branch prunes to exactly one field, so selecting the 
corrupt record column there always drops the rest. It gets the same guard the 
CSV branch added by SPARK-32968 already has.
   - The `CreateNamedStruct` branch keeps every selected field, so it only 
becomes unsafe when the selection is a strict subset of the schema. Guarding on 
"corrupt column is selected" alone would give up the parse-deduplication 
rewrite for an all-fields selection that drops nothing, turning one parse into 
N.
   
   `GetArrayStructFields` needs no guard: an `ArrayType` schema takes 
`JsonToStructsEvaluator`'s `case other =>`, where `corruptFieldIndex` is 
`None`, so corrupt-record semantics do not exist on that path.
   
   ### Why are the changes needed?
   
   The corrupt record column silently returns null for a record that did fail 
to parse. The rule requires `options.isEmpty`, which is the PERMISSIVE default, 
and `spark.sql.optimizer.enableJsonExpressionOptimization` defaults to true, so 
no configuration is needed to hit it:
   
   ```scala
   Seq("""{"a": 1, "b": "bad"}""").toDS()
     .selectExpr("from_json(value, 'a int, b int, _corrupt_record string') as 
p")
     .selectExpr("p._corrupt_record")
   ```
   
   | spark.sql.optimizer.enableJsonExpressionOptimization | result |
   |---|---|
   | true | `null` |
   | false | `{"a": 1, "b": "bad"}` |
   
   The optimized plan shows the schema pruned to the corrupt column alone, 
which leaves `actualSchema` empty so the parser has nothing to convert and 
never raises `BadRecordException`:
   
   ```
   Project [from_json(StructField(_corrupt_record,StringType,true), value#1, 
...)._corrupt_record ...]
   ```
   
   A type mismatch on a dropped field is needed to expose this. The existing 
SPARK-33907 test uses a structurally malformed record, which fails at 
tokenization whatever schema is requested, so it never depended on the pruning; 
that test is now annotated to say the rule no longer fires for it.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes, it fixes the wrong result above. With this PR the corrupt record column 
holds the record text under both settings of the config, matching the 
unoptimized behavior.
   
   ### How was this patch tested?
   
   New tests, plan-level and end-to-end:
   
   - `OptimizeJsonExprsSuite`: two `comparePlans` cases, each with a control. 
One asserts the `GetStructField` rewrite is skipped for the corrupt column 
while a normal field is still pruned; the other asserts the `CreateNamedStruct` 
rewrite still fires when every field is selected and is skipped when the 
selection drops a field.
   - `JsonFunctionsSuite`: two `checkAnswer` cases covering both branches with 
the optimization on and off.
   
   Verified by reverting each guard on the fixed tree: removing the 
`GetStructField` guard fails both new catalyst tests, and weakening 
`prunesCorruptRecord` to "corrupt column selected" fails the `named_struct` 
case. Full `JsonFunctionsSuite` (115) and `OptimizeJsonExprsSuite` + 
`OptimizeCsvExprsSuite` (36) pass.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Opus 5
   


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