eugenegujing opened a new pull request, #6947:
URL: https://github.com/apache/texera/pull/6947

   ### What changes were proposed in this PR?
   
   CSV/JSONL scan sources infer each column's type from only the first 
`INFER_READ_LIMIT` (=100) rows. When a later row held a value that did not 
parse as the inferred type, the execs caught the error, mapped the row to 
`null`/`None`, and filtered it out — silently dropping the entire row with no 
error, warning, count, or log. Every downstream count, aggregate, and join then 
ran on a silently truncated dataset. The bug is the silence, not the rejection.
   
   Following the consensus in discussion #6324 (skip + surface, rather than the 
fail-fast approach originally proposed in #6323), a scan now still skips the 
unparsable row — the run completes and existing workflows keep working — but 
each skipped row is surfaced to the user as a console warning naming the row 
number, offending value, column, and expected type, for example:
   
   > WARNING: skipped row 150 — value '55.5' in column 'age' cannot be read as 
INTEGER. Column types were inferred from the first 100 rows of the file, and 
this value does not match.
   
   Changes:
   
   - Add `ScanRowParseError`, which builds the per-row warning by re-parsing 
the failing row's fields to identify the offending column, with a generic 
fallback message when no single column can be identified (e.g. a malformed JSON 
line).
   - Add `SkippedRowReporter`, shared by all scan variants: it reports the 
first 100 skipped rows individually and then appends a single summary line 
carrying the true total, so a heavily malformed file cannot flood the console 
or exhaust memory.
   - Record-and-skip in `CSVScanSourceOpExec`, `JSONLScanSourceOpExec`, 
`ParallelCSVScanSourceOpExec`, and `CSVOldScanSourceOpExec`. The legitimate 
null paths (an empty cell parsed to null, a blank/all-null line, an exhausted 
block) are untouched and are not reported. Row numbers: CSV reuses its existing 
counter, JSONL and csvOld gain absolute line/data-row numbers, and ParallelCSV 
reports none because it is byte-partitioned across workers.
   - Add `OperatorExecutor.getWarnings` (defaults to empty), a generic 
non-fatal warning channel that any executor can opt into.
   - Emit the warnings at `FinalizeExecutor` in `DataProcessor` as PRINT 
console messages via the new `ErrorUtils.mkPrintConsoleMessage`. The titles 
keep the `WARNING: ` prefix the UI keys on, and, unlike the executor exception 
path, this does not pause the run.
   
   Inference logic is unchanged (the 100-row sampling is untouched). Scala only 
— no UI change.
   
   Behavior-change note for reviewers: workflows that previously ran to 
completion while silently discarding malformed rows now still complete, but 
they surface a console warning for each skipped row (capped at 100 detailed 
entries plus a summary). One case worth calling out: a csvOld scan over a file 
with an empty cell in a numeric column previously dropped that row silently and 
will now report it — this is exactly the silent loss this PR exists to surface, 
not a regression.
   
   ### Any related issues, documentation, discussions?
   
   Closes #6279. Design discussion: #6324. This supersedes the fail-fast 
approach in #6323, which will be closed in favor of this PR.
   
   ### How was this PR tested?
   
   Scan-operator unit tests (skip-and-report naming row/value/column/type, the 
100-detail cap with its summary line, empty-cell and blank-line non-reporting, 
and the malformed-JSON fallback):
   
   ```
   sbt "WorkflowOperator/testOnly \
     org.apache.texera.amber.operator.source.scan.csv.CSVScanSourceOpExecSpec \
     
org.apache.texera.amber.operator.source.scan.json.JSONLScanSourceOpExecSpec \
     
org.apache.texera.amber.operator.source.scan.csv.ParallelCSVScanSourceOpExecSpec
 \
     
org.apache.texera.amber.operator.source.scan.csvOld.CSVOldScanSourceOpExecSpec"
   ```
   
   Engine-side emission path (`DataProcessorSpec`): a new test asserts the 
warnings reach the coordinator as PRINT console messages at finalize and that 
the run is not paused.
   
   Full local gate (lint + format + backend unit tests):
   
   ```
   sbt "scalafixAll --check"   # pass
   sbt scalafmtCheckAll        # pass
   AMBER_TEST_FILTER=skip-integration sbt WorkflowExecutionService/test   # 
1197 succeeded, 0 failed
   sbt WorkflowOperator/test WorkflowCore/test WorkflowCompilingService/test   
# 1760 / 581 / 11 succeeded, 0 failed
   ```
   
   Manual, in the Texera UI, over CSV and JSONL datasets derived from a real 
403-row file whose `age` column is inferred as INTEGER: verified a single bad 
row (skipped, one warning naming row/value/column/type), many bad rows (100 
detailed warnings plus a summary line), the clean file (all rows, no warning), 
an empty cell (kept as a null row, no warning), and a malformed JSONL line 
(skipped, generic fallback warning). In every case the scan completed instead 
of failing.
   
   ### Was this PR authored or co-authored using generative AI tooling?
   
   Co-authored by: Claude Code (Fable 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]

Reply via email to