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

   ### What changes were proposed in this pull request?
   
   Both the CSV and JSON data source option tables describe `PERMISSIVE` mode 
with a
   character-identical pair of sentences:
   
   > **To keep corrupt records**, an user can set a string type field named
   > `columnNameOfCorruptRecord` in an user-defined schema. **If a schema does 
not have
   > the field, it drops corrupt records during parsing.**
   
   Neither is correct for either data source. `columnNameOfCorruptRecord` does 
not
   control whether a corrupt record is kept — it is always kept, with its 
malformed
   fields set to `null`. The field controls whether the *malformed string 
itself* is
   available.
   
   This PR replaces both sentences in both files:
   
   > To capture the malformed string, an user can set a string type field named
   > `columnNameOfCorruptRecord` in an user-defined schema. If a schema does 
not have the
   > field, the corrupt record is still retained with its malformed fields set 
to `null`,
   > but the malformed string is not available.
   
   Both sentences move together on purpose. Correcting only the second one 
would leave
   the paragraph contradicting itself, since the first assigns retention to the 
field
   while the second would deny retention without it.
   
   ### Why are the changes needed?
   
   The sentence is the one a reader consults when deciding whether they need
   `columnNameOfCorruptRecord`, and it points them the wrong way. Read 
literally, a
   schema *without* the field is the safe choice, because bad records disappear 
rather
   than entering the result. The truth is the opposite: without the field, 
malformed
   records are still there, indistinguishable from records that were genuinely 
null in
   the source, and there is no signal that anything was wrong.
   
   That matters most in exactly the situation the docs are meant to protect: a
   pipeline whose schema does not declare the field will silently admit partial
   records, and no error, count or mode setting reveals it.
   
   ### Does this PR introduce _any_ user-facing change?
   
   No. Documentation only; no behaviour change. The behaviour being documented 
is
   already asserted by the test suite on `master` (see below), so this corrects 
the
   description rather than describing anything new.
   
   ### How was this patch tested?
   
   Documentation-only change, so no tests were added. No new verification is 
needed
   either: **`master`'s own test suite already asserts the corrected behaviour, 
in both
   data sources.**
   
   **CSV** — `CSVSuite`'s `SPARK-18699 put malformed records in a
   'columnNameOfCorruptRecord' field` reads `test-data/value-malformed.csv`, 
whose two
   records are `0,2013-111_11 12:13:14` (an unparseable date) and 
`1,1983-08-04`. With
   schema `a INT, b DATE` and **no** `columnNameOfCorruptRecord` field it 
asserts:
   
   ```scala
   checkAnswer(df1, Row(0, null) :: Row(1, java.sql.Date.valueOf("1983-08-04")) 
:: Nil)
   ```
   
   Two rows. The corrupt record is kept with the unparseable field nulled. Were 
the
   documented sentence accurate, this assertion would expect one row.
   
   **JSON** — `JsonSuite` is even more direct. The test is named
   `Corrupt records: PERMISSIVE mode, without designated column for malformed 
records`,
   reads the `corruptRecords` fixture with a three-column user-defined schema 
and no
   corrupt-record column, and asserts five rows — four of them entirely null — 
under
   Spark's own comment:
   
   ```scala
           // Corrupted records are replaced with null
           Row(null, null, null),
   ```
   
   Nothing is dropped in either data source, on `master`, by the project's own
   assertions.
   
   **Corroborated by direct measurement** across four kinds of bad record on
   `pyspark` 3.5.9 — three source records per case, `PERMISSIVE`, user-defined 
schema
   `a INT, b STRING`:
   
   | format | bad record | rows without the field | rows with the field | 
flagged corrupt |
   |---|---|---|---|---|
   | JSON | not parseable as JSON at all | 3 | 3 | 1 |
   | JSON | valid JSON, wrong type for schema | 3 | 3 | 1 |
   | CSV | wrong type for schema | 3 | 3 | 1 |
   | CSV | unterminated quote | 3 | 3 | 0 |
   
   The counts are identical either way in every case — nothing is dropped. 
Declaring
   the field adds the ability to see the record, not the decision to keep it.
   
   The JSON rows are worth calling out, since JSON is the data source where the
   sentence would be most defensible: a whole JSON record genuinely can be
   unparseable, and it is still retained.
   
   Reproduction script: `docs/evidence/c4_repro_json_vs_csv_drop.py` in the 
authoring
   repo (not part of this patch). Note that this measurement was taken on 
3.5.9, not on
   `master` — it is corroboration, and the two `master` test assertions above 
are the
   load-bearing evidence.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Code (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