GH-50925: [C++] Allow CSV reader to pad rows with missing trailing fields - #50926
GH-50925: [C++] Allow CSV reader to pad rows with missing trailing fields#50926HuaHuaY wants to merge 5 commits into
Conversation
79932d8 to
da6c7ab
Compare
|
I'll temporarily switch to a draft and reorganize my PR. |
da6c7ab to
c181018
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new C++ CSV ParseOptions::pad_short_rows option to accept rows with fewer trailing fields than the expected column count, padding the missing trailing fields as nulls (instead of rejecting the row). This aligns the CSV reader behavior with common “optional trailing column” CSV inputs while keeping the default strict behavior unchanged.
Changes:
- Introduce
ParseOptions::pad_short_rows(defaultfalse) to enable padding of short rows with nulls. - Extend the CSV parser/visitor path to propagate “missing (padded)” cells to converters so they can reliably append nulls.
- Add parser- and reader-level tests covering both string and typed/dictionary conversions.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| cpp/src/arrow/dataset/file_csv.cc | Includes pad_short_rows in CsvFileFormat::Equals so formats with different padding behavior are not considered equal. |
| cpp/src/arrow/csv/options.h | Adds the public ParseOptions::pad_short_rows option and documents its intent. |
| cpp/src/arrow/csv/parser.cc | Implements padding behavior for short rows by appending empty field descriptors and recording missing ranges. |
| cpp/src/arrow/csv/parser.h | Threads a missing flag through VisitColumn/VisitLastRow (backward-compatible visitor signature support). |
| cpp/src/arrow/csv/converter.cc | Ensures padded “missing” values convert to nulls across supported converter paths (primitive + dictionary). |
| cpp/src/arrow/csv/parser_test.cc | Adds unit coverage verifying padding and the missing signal in visitor callbacks. |
| cpp/src/arrow/csv/reader_test.cc | Adds integration coverage for padded short rows for string columns and typed/dictionary columns. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
@pitrou Please take a look. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
Suppressed comments (1)
cpp/src/arrow/csv/parser.h:240
BlockParser::VisitColumn/VisitLastRoware public template APIs in a public header; changing the visitor signature to require an extrabool missingargument is a source-breaking change for downstream callers. Consider keeping backward compatibility by accepting both 3-arg and 4-arg visitors (e.g., usestd::is_invocable_r_v<Status, Visitor, const uint8_t*, uint32_t, bool, bool>/if constexprto dispatch), and document precisely whatmissingmeans (padded field due topad_short_rows, not an empty field).
/// \brief Visit parsed values in a column
///
/// The signature of the visitor is
/// Status(const uint8_t* data, uint32_t size, bool quoted, bool missing)
template <typename Visitor>
Status VisitColumn(int32_t col_index, Visitor&& visit) const {
return parsed_batch().VisitColumn(col_index, first_row_num(),
std::forward<Visitor>(visit));
}
template <typename Visitor>
Status VisitLastRow(Visitor&& visit) const {
return parsed_batch().VisitLastRow(std::forward<Visitor>(visit));
}
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
cpp/src/arrow/dataset/file_csv.cc:196
GetOrderedColumnNames()ignores the newmissingflag fromVisitLastRow(). Ifpad_short_rowsis enabled and earlier parsed rows have more columns than the header row (e.g. due toskip_rows), this will currently append empty strings as column names for missing header fields, potentially creating empty/duplicate column names and confusing downstream errors. Consider failing fast whenmissingis true (or generating names explicitly).
[&](const uint8_t* data, uint32_t size, bool quoted, bool missing) -> Status {
std::string_view view{reinterpret_cast<const char*>(data), size};
column_names.emplace_back(view);
return Status::OK();
}));
f88709f to
f5561bd
Compare
|
Rebase and add one more commit. Not allow to pad header row when using dataset reader. In the situation, the number of columns is not determined by the number of headers in the file, which seems strange. However, changing this would result in behavior inconsistent with the existing code (even though the inconsistency would only arise with files that previously caused errors) and need more modifications. Therefore, I opted for the simple solution of temporarily disabling this newly added flag. |
Wouldn't it be better to return |
I intend for the newly added flag in this situation to still be usable for filling in missing columns in the data; it simply shouldn't fill in the header row of the CSV. In the CSV reader, when the user does not explicitly provide column names, the number of columns is determined by the first row after skipping However, in the dataset reader, |
|
I'm not sure I understand: if I enable |
In this PR, it is ignored when parsing column names from the file, but remains effective when parsing the data. |
Rationale for this change
Some CSV files omit trailing optional fields. The C++ CSV reader currently rejects these short rows, requiring callers to preprocess or discard them.
What changes are included in this PR?
Add an option
pad_short_rowsin CSVstruct ParseOptionsthat pads missing trailing fields with nulls.Are these changes tested?
Yes.
Are there any user-facing changes?
Add an option
pad_short_rowsin CSVstruct ParseOptions.