-
Notifications
You must be signed in to change notification settings - Fork 116
Read multi-line CSV values that cross a block in ArrowCursor #1045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -327,6 +327,9 @@ def _read_csv(self) -> Table: | |
| ignore_empty_lines=False, | ||
| double_quote=True, | ||
| escape_char=False, | ||
| # A quoted value can contain a newline, so the reader must not split | ||
| # blocks inside quotes. | ||
| newlines_in_values=True, | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Independent review (relayed): Codex CLI 0.160.0, model Reviewer coverage: Arrow result-set init, Verdict: FINDINGS, none of them in this diff. No regression was found in the Arrow change, and the new test reaches the parser and crosses block boundaries.
Author verification: confirmed offline. On a 9.6 MB CSV of 8,000 two-line values, No change to this PR from the independent review. |
||
| ) | ||
| else: | ||
| return pa.Table.from_pydict({}) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,18 @@ def test_binary_null_vs_empty(self, arrow_cursor): | |
| ] | ||
| assert [row[3] for row in rows] == ["", "", "NULL"] | ||
|
|
||
| def test_multiline_values_across_blocks(self, arrow_cursor): | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Self-review round two (claims, compatibility, operations): base Claims checked:
Existing callers: no signature or default changes; results that did not cross a block parse identically (the existing Arrow suite passes); a result that used to raise Result: CLEAN after the wording correction. Async and aio Arrow tests were not run locally; AWS CI runs them when the PR is Ready. |
||
| # The 50 two-line values of 301 bytes span several 1024-byte blocks. | ||
| arrow_cursor.execute( | ||
| """ | ||
| SELECT array_join(repeat('x', 150), '') || chr(10) || array_join(repeat('y', 150), '') | ||
| AS v | ||
| FROM UNNEST(sequence(1, 50)) AS t(i) | ||
| """, | ||
| block_size=1024, | ||
| ) | ||
| assert arrow_cursor.fetchall() == [("x" * 150 + "\n" + "y" * 150,)] * 50 | ||
|
|
||
| def test_binary_single_null(self, arrow_cursor): | ||
| arrow_cursor.execute("SELECT CAST(NULL AS VARBINARY) AS value") | ||
| assert arrow_cursor.fetchall() == [(None,)] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Self-review round one (implementation behavior): base
28ec68d9f70b5bc2fb447f6a4fb745ee0a467683, headaef05e4a36ec49af94cf685c1e51b638a2b6a597.Covered: the
.csvbranch ofAthenaArrowResultSet._read_csv()and every Arrow reader of it (ArrowCursor,AsyncArrowCursor,AioArrowCursor); the.txtbranch (tab-separated,quote_char=False, unchanged); UNLOAD/Parquet and managed (GetQueryResults) paths, which do not use these options; the interaction withignore_empty_lines=Falsefrom #1031 (empty lines are single-column NULL rows);block_sizeplumbing fromexecute(); other CSV readers in the package (only this module usespyarrow.csv.ParseOptions, while pandas, Polars, and S3FS use their own quote-aware readers);newlines_in_valuesavailability (present well before thepyarrow>=22floor); the new test.Result: CLEAN.
block_size=64, 200 empty lines interleaved with 200 two-line values read as 400 rows, so Keep NULL rows of single-column CSV results in ArrowCursor #1031's NULL rows survive the quote-aware chunker.block_size=1024(about 15 blocks) and asserts every row. With the fix reverted, it fails withCSV parser got out of sync with chunker.tests/pyathena/arrow/test_cursor.py56 passed.