[MINOR][DOCS] Document CSV read behaviour when multiLine is disabled - #57608
Open
Joorgem wants to merge 1 commit into
Open
[MINOR][DOCS] Document CSV read behaviour when multiLine is disabled#57608Joorgem wants to merge 1 commit into
Joorgem wants to merge 1 commit into
Conversation
The multiLine entry documents only what enabling the option does. This adds what the default costs: a line break inside a quoted value terminates the record, remaining schema fields become null, the rest of the value starts a new record, and both halves are malformed -- so FAILFAST raises, DROPMALFORMED discards both halves and loses the whole source record, and PERMISSIVE keeps both silently unless columnNameOfCorruptRecord is declared. Also notes that the split increases the record count and that an action needing no columns (a bare count()) may surface none of it, because of parser column pruning. Verified against pyspark 3.5.9.
Joorgem
force-pushed
the
docs-csv-multiline-disabled
branch
from
July 28, 2026 18:27
1249062 to
823830b
Compare
szehon-ho
reviewed
Jul 28, 2026
| <td>false</td> | ||
| <td>Allows a row to span multiple lines, by parsing line breaks within quoted values as part of the value itself. CSV built-in functions ignore this option.</td> | ||
| <td>Allows a row to span multiple lines, by parsing line breaks within quoted values as part of the value itself. CSV built-in functions ignore this option.<br> | ||
| When this option is disabled, a line break inside a quoted value terminates the record at that break: the value is truncated, the remaining fields of the schema are set to <code>null</code>, and the rest of the value begins a new record. Both halves are malformed records, so what happens next follows <code>mode</code>: <code>FAILFAST</code> raises an error, <code>DROPMALFORMED</code> discards both halves and therefore loses the whole source record, and <code>PERMISSIVE</code> retains both, without any signal unless the schema declares <code>columnNameOfCorruptRecord</code>. Note also that the split <em>increases</em> the number of records, and that an action requiring no columns (a bare <code>count()</code>, for instance) may surface none of this, because of parser column pruning.</td> |
Member
There was a problem hiding this comment.
Thanks for documenting this — the default-multiLine gotcha is worth calling out. Suggestion on placement: keep the option-specific fact under multiLine, and move the mode / column-pruning surprises next to mode, which already documents corrupt handling and pruning.
multiLine — keep only the split behavior:
<td>Allows a row to span multiple lines, by parsing line breaks within quoted values as part of the value itself. CSV built-in functions ignore this option.<br>
When this option is disabled (the default), a line break inside a quoted value terminates the record at that break: the value is truncated, the remaining fields of the schema are set to <code>null</code>, and the rest of the value begins a new record. Both resulting records are malformed; how they are handled is controlled by <code>mode</code>.</td>mode — append after the existing column-pruning sentence (before the <ul>):
<td>Allows a mode for dealing with corrupt records during parsing. It supports the following case-insensitive modes. Note that Spark tries to parse only required columns in CSV under column pruning. Therefore, corrupt records can be different based on required set of fields. This behavior can be controlled by <code>spark.sql.csv.parser.columnPruning.enabled</code> (enabled by default). In particular, when <code>multiLine</code> is disabled, a quoted value that contains a line break is split into two malformed records, which increases the record count: <code>DROPMALFORMED</code> discards both halves and therefore loses the whole source record, <code>FAILFAST</code> raises an error, and <code>PERMISSIVE</code> retains both without a signal unless the schema declares <code>columnNameOfCorruptRecord</code>. An action that requires no columns (for example a bare <code>count()</code>) may surface none of this because of column pruning.<br>
<ul>
<li><code>PERMISSIVE</code>: when it meets a corrupted record, puts the malformed string into a field configured by <code>columnNameOfCorruptRecord</code>, and sets malformed fields to <code>null</code>. To keep corrupt records, an user can set a string type field named <code>columnNameOfCorruptRecord</code> in an user-defined schema. If a schema does not have the field, it drops corrupt records during parsing. A record with less/more tokens than schema is not a corrupted record to CSV. When it meets a record having fewer tokens than the length of the schema, sets <code>null</code> to extra fields. When the record has more tokens than the length of the schema, it drops extra tokens.</li>
<li><code>DROPMALFORMED</code>: ignores the whole corrupted records. This mode is unsupported in the CSV built-in functions.</li>
<li><code>FAILFAST</code>: throws an exception when it meets corrupted records.</li>
</ul>
</td>That keeps multiLine to what the default does to the record, and puts the DROPMALFORMED / PERMISSIVE / count() caveats with the option that already covers corrupt handling.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
Extends the
multiLineentry in the CSV data source options table to describe what happens when the option is left at its default offalseand a quoted value contains a line break.The entry currently documents only what enabling the option does:
The added sentence states that the record is terminated at the line break, that the remaining schema fields are set to
null, that the rest of the value begins a new record, and how eachmodethen behaves.One table row changed; no other files touched.
Why are the changes needed?
A line break inside a quoted field is valid CSV (RFC 4180 §2.6) and occurs in real published datasets, so a reader can meet this without doing anything unusual. The entry says what
multiLine=trueenables but never what the default costs, and the behaviour is not guessable from it:nullfor the rest, so it can satisfy schema and not-null style checks;PERMISSIVEmode there is no signal at all unless the schema happens to declarecolumnNameOfCorruptRecord;DROPMALFORMEDdiscards both halves, losing the entire source record rather than a bad line;count()reports the inflated number without surfacing a malformed record, because column pruning means no column is parsed.The last two were the surprises worth writing down, and neither is inferable from the current text.
SPARK-21356 was closed as Invalid because "the workaround looks so easy". That is true, and is exactly the argument for documenting the default: the workaround only helps a reader who knows they need it.
Does this PR introduce any user-facing change?
No. Documentation only; no behaviour change.
How was this patch tested?
Documentation-only, so no tests were added. The described behaviour was verified against
pyspark3.5.9 using a three-record file whose second record contains a quoted line break, read with an explicit three-column schema:multiLine=false)2, 'EMPRESA COM', nullplus a fragment'QUEBRA DE LINHA"', 'RJ', nullmultiLine=truemode=PERMISSIVE,collect()mode=DROPMALFORMED,collect()mode=FAILFAST,collect()count()With
columnNameOfCorruptRecorddeclared, both halves are captured as corrupt, with raw text2,"EMPRESA COMandQUEBRA DE LINHA",RJ.git diff --checkis clean.Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 5)