-
Notifications
You must be signed in to change notification settings - Fork 373
test: cover slice over expression-produced non-null element arrays (#... - #5839
test: cover slice over expression-produced non-null element arrays (#... #5839sam-1112 wants to merge 1 commit into
Conversation
@sunchao
sunchao
left a comment
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.
Correctness
Prior behavior and regression coverage
The planner fix for #5743 is already present through #5766. This PR adds coverage and changes no production behavior. The earlier local-table test covers non-null element fields arriving at a scan boundary. These new queries produce their arrays after reading primitive columns from Parquet, covering the path that scan normalization cannot protect.
The column-dependent split, sequence and concat compositions cannot be folded away. Each uses checkSparkAnswerAndOperator, which compares against Spark and checks the Comet operator plan without exclusions. Source tracing confirms that the outer slice uses the native kernel. By default, split and array-valued concat use Spark codegen through the JVM dispatcher inside that pipeline. The integral sequence(1, n) case meets the native argument restrictions. A fallback Spark projection would remain visible to the operator check.
The maintained Spark 3.5 and 4.0 implementations preserve the input array's element nullability in slice. Positive starts are one-based, negative starts count from the end, zero starts and negative lengths error, and empty or out-of-range slices return empty arrays. Null arguments return a null array. The new cases exercise valid positive bounds and the non-null element field. The empty string row produces [""], not an empty array. Existing Rust and SQL tests cover empty arrays, null arguments, negative and out-of-range starts, zero lengths and invalid bounds.
The Rust addition checks the complete inner field. In the locked Arrow version, datatype equality includes the field name, nullability and metadata, so the assertion detects losing any of them. Existing builders retain their previous nullable item field. I found no actionable P1/P2 issue in either test addition or the relevant base interaction.
Validation and limits
Reviewed head 2c24d6375c13ae27306ebdbff7eacb5572976bf8 against base 8e489ea514c09f0a6cc7c04bc6d8735b6b097456. Local validation consisted of source, schema-contract and diff checks. I did not execute Rust or JVM tests. The reported debug/release Spark 4.1.3 runs and Rust test results are author evidence, not independently reproduced results. At 05:33 UTC on September 11, CI and three other workflows required approval and had no jobs. Only the labeling check had succeeded. No synthetic-merge test result is credited. Maintained Spark 3.4 and 4.1 sources were unavailable.
Performance
There is no production-path change or new performance claim requiring a benchmark. The JVM test creates one three-row Parquet fixture and runs three Spark/Comet comparisons. The nested withParquetTable(DataFrame, ...) call only registers a temporary view, so it does not write the fixture again. The Rust check uses one short list and adds negligible setup relative to the existing suite.
Design
The JVM cases exercise the planner-to-kernel contract, while the Rust test pins the kernel's field-preservation responsibility. That division fits a regression already fixed in the planner. Retaining the existing scan-boundary test separately makes the two origins of non-null element fields clear. No configuration or fallback behavior is changed.
Abstraction & complexity
The only helper extraction accepts a custom field while retaining the existing builder as a wrapper with its original defaults. It avoids duplicating offsets, values and validity construction for the new case. The Scala addition reuses the existing fixture and comparison helpers, with no new test framework or production abstraction.
sam-1112
commented
Sep 11, 2026
Thanks for the detailed review and approval!
Which issue does this PR close?
Closes #5743.
Rationale for this change
slicecrashed when its input array had a non-nullable element field. Spark declares expressions such assplitandsequenceasArrayType(..., containsNull = false), so they can produce a non-nullable child field inside the native plan, after the scan boundary.This differs from #4789, where the non-nullable field entered through
CometLocalTableScanExecand could be normalized at that boundary. The reproducer for #5743 uses a native Parquet scan; its non-nullable field is produced later by an expression, so the #4789 fix does not cover it.The planner fix is already present on
mainthrough #5766:CometSliceno longer serializes an explicit return type. Native planning therefore usesSparkArraySlice.return_field_from_args, whose return field follows the actual input list field.This PR adds the missing regression coverage for that path.
What changes are included in this PR?
No production-code changes.
slice(split(...))slice(sequence(...))slice(concat(split(...), array(...)))checkSparkAnswerAndOperator, verifying both Spark-compatible results and native execution.slice_listpreserves the input list's inner field, including its name, nullability, and metadata.How are these changes tested?
cargo test -p datafusion-comet-spark-expr array_slicemake core./mvnw test -Dtest=none -Dsuites="org.apache.comet.CometArrayExpressionSuite slice over expression-produced non-null element arrays"./mvnw test -Dtest=none -Dsuites="org.apache.comet.CometArrayExpressionSuite"make release./mvnw test -Prelease -Dtest=none -Dsuites="org.apache.comet.CometArrayExpressionSuite slice over expression-produced non-null element arrays"The targeted JVM test was run with the default Spark 4.1.3 profile, matching the original reproduction environment. Both debug and release builds were exercised because #5743 failed at different validation points in those configurations.