diff --git a/dataset b/dataset index 7bc333a51e..1cca9ae642 160000 --- a/dataset +++ b/dataset @@ -1 +1 @@ -Subproject commit 7bc333a51e3d85a88f33d576486baa61cfd333e0 +Subproject commit 1cca9ae642991d0c57a19070584f1d9958b812d0 diff --git a/src/processor/operator/persistent/reader/csv/base_csv_reader.cpp b/src/processor/operator/persistent/reader/csv/base_csv_reader.cpp index a581e280c8..b589892614 100644 --- a/src/processor/operator/persistent/reader/csv/base_csv_reader.cpp +++ b/src/processor/operator/persistent/reader/csv/base_csv_reader.cpp @@ -518,6 +518,14 @@ BaseCSVReader::parse_result_t BaseCSVReader::parseCSV(Driver& driver) { return {curRowIdx, numErrors}; } column++; + } else if (column > 0) { + // File ends right after a delimiter with an empty trailing field. + // Without this, a row like "a,b," (no trailing newline) loses its last + // empty field and undercounts columns, causing "expected N, got N-1". + if (!addValue(driver, curRowIdx, column, std::string_view{}, escapePositions)) { + return {curRowIdx, numErrors}; + } + column++; } if (column > 0) { curRowIdx += driver.addRow(curRowIdx, column, diff --git a/test/test_files/csv/issues_trailing_empty_field_eof.test b/test/test_files/csv/issues_trailing_empty_field_eof.test new file mode 100644 index 0000000000..18d27c514a --- /dev/null +++ b/test/test_files/csv/issues_trailing_empty_field_eof.test @@ -0,0 +1,19 @@ +-DATASET CSV empty + +-- + +# Regression test for the fix in ffce93a49c306806a546b3cd368bc50849c87688 +# "fix(csv): handle trailing empty field at EOF without newline" +# +# When a CSV file ends with a row like "a,b," (no trailing newline, last field +# empty), the parser used to drop the empty field, causing "expected N values +# per row, but got N-1". The fix adds an else-if branch in final_state to emit +# the empty value when column > 0. +-CASE TrailingEmptyFieldAtEOF +-STATEMENT CREATE NODE TABLE t(A STRING, B STRING, C STRING, PRIMARY KEY(A)); +---- ok +-STATEMENT COPY t FROM "${LBUG_ROOT_DIRECTORY}/dataset/csv-edge-case-tests/trailing-empty-field-eof.csv"; +---- ok +-STATEMENT MATCH (t:t) RETURN t.*; +---- 1 +a|b|