Conversation
0b26695 to
e5aa8d7
Compare
The I have concerns about how much else is in here. The decimal precision restriction on native shuffle Changing The removed TODO points at #3079 and says wider decimals need Either way, could you say what this costs? A before and after on a query that groups by a This PR contains #5421 verbatim That is already being discussed on the other thread so I will not repeat it, except to note that the diff here is harder to review because of it. Once the ordering is settled, rebasing so this PR shows only its own changes would help a lot.
The check is The relaxed ANSI condition in The guard changes from Non-local return in The new block uses Splitting Counting them up, this PR contains: the float |
|
Updated in 6dca7f116. I worked through the review points and added the wide-decimal routing benchmark, carried the directional buffer policy from #5421, and corrected the grouped-AVG explanation. The updated description includes current validation and measured costs, with earlier validation clearly identified as historical.
The current optimized native build, full Spark 4.1.3 JVM reactor/style checks, and all 47 focused Scala tests pass. The full historical cross-version suite was not rerun for this follow-up. CI on the pushed revision is still separate from these local results. |
|
Updated in ae98cef70. I resolved the main-branch conflict with a history-preserving merge of The merged branch has a fresh default-release native build, a full Spark 4.1.3 JVM reactor/style pass, and 55 passing focused Scala tests, including the 18 AVG interoperability query combinations and upstream's new RSS/JNI/protocol coverage. An additional untimed wide-decimal run matches all 10,000 Spark results and verifies both expected shuffle/aggregate routes. Each run's loaded native library was checked against the merged build. The description now distinguishes this validation from the earlier |
|
Fixed the grouped decimal AVG evaluation-order issue in 728c55e8d. Grouped decimal The guard applies to every decimal precision and to the whole affected aggregate operator, including colocated aggregates, even without LIMIT. This intentionally gives up native aggregation for those ANSI queries. Grouped The full Spark 4.1.3 JVM reactor passed 139 tests (107 aggregate, 31 planner, and the AVG SQL fixture), with the loaded native library verified against the unchanged native tree. Both new LIMIT regressions fail against the unchanged planner and pass with the fix, with AQE off/on. Consumed-overflow and native-control checks also pass, as do Spotless, Scalastyle, and CI's syntactic Scalafix check. CI for the new commit is pending. |
|
Fixed both re-review findings in 97f605ede. The six affected TPC-DS plan expectations were regenerated with the supported harness. They now preserve the intended grouped ANSI decimal AVG fallback on Spark 4.x; the shared and Spark 3.x expectations are unchanged. The operator guide also explains that the guard applies when AVG still has a DECIMAL input after Spark optimization, including other functions in the same aggregate operator and queries without LIMIT. Validation passed all 129 plan checks on each of Spark 3.4.3, 3.5.9, 4.0.4, 4.1.3, and 4.2.0 with generation disabled (645 total). Current JVM classes and the actual loaded native library were verified. No implementation or native code changed; no new native build or performance result is claimed. The PR description has been updated, and the new hosted CI run is pending. |
|
Corrected the generated AVG note in 754a1df66 to say that grouped ANSI fallback applies when the input remains This changes only the documentation reason; aggregate admission and native code are unchanged. Full reactor compilation, Spotless, and fresh GenerateDocs output checks passed. The generated Average page now includes the qualification. |
754a1df to
f51e3e4
Compare
andygrove
left a comment
There was a problem hiding this comment.
Following up on my earlier question about aggregateSupportLevel only covering the ungrouped case. The answer in operators.scala went further than I expected. Grouped ANSI decimal AVG now falls back at every precision, and because ANSI is the default on Spark 4.x that removes the whole aggregate operator from Comet for a very common shape. The six regenerated Spark 4.x TPC-DS plans contain eighteen aggregate operators reverting to Spark, and q1, q18, q30, q65, q81 and q18a are all rooted at TakeOrderedAndProject, which consumes the entire aggregate output. The lazy-LIMIT argument does not apply to any of them, so the guard is paying a real cost in exactly the cases where Spark would raise the same error. The benchmark in the description is legacy mode, so the cost of this particular fallback is not measured anywhere, and Unsupported leaves users no way to opt back in.
Could the guard be narrowed? Two things I would like your read on. AvgDecimalGroupsAccumulator::merge_batch in avg_decimal.rs around line 592 raises the ANSI overflow error while it is still consuming input, before any group is emitted. If that deferred to evaluate, the remaining divergence from Spark would be batch granularity rather than whole-input granularity. Could the operator check also look at whether a limit can actually truncate this aggregate's output, instead of firing unconditionally? If neither is practical, could the fallback sit behind a config so a user who does not care about the LIMIT case can keep native aggregation?
Separately, in AvgDecimalAccumulator the is_empty field looks like it no longer does anything. Its only reader is the has_overflow expression at avg_decimal.rs line 382, and after this change I cannot construct a state where sum is None while is_not_null is true and count is greater than zero, because every path that clears sum also clears is_not_null. The flag has also stopped meaning what the comment above line 347 says, since merging a batch of empty partials with non-null zero counts now sets it to false. Is it still load bearing, or can it go?
The accumulator work itself reads well. The state round trip for decimal, the zeroed-null-count case and the precision boundary at 27 versus 28 are all pinned by tests in both ANSI modes, which was the part I was most worried about last time.
b4a8d7b to
df88a82
Compare
edb4ec2 to
45800b3
Compare
|
Rebased onto current main in Thanks, Andy. I addressed the accumulator and configuration points:
The default remains conservative. Deferring errors helps prefix emission, but native finalization can still evaluate an unconsumed group within a batch. I agree that queries which consume every group pay for a fallback they do not need. A top-level Added The previous hosted run passed 1,273 Rust tests and 862 Spark 4.1 execution tests. Its six failing jobs hit the same redundant string-interpolation prefix in the benchmark; I removed it. Those results cover the previous synthetic merge. The new revision needs its own hosted CI results. Full-reactor Spark 4.0.4 test compilation, syntactic Scalafix 0.14.6, Rust formatting, Spotless, Scalastyle, and whitespace checks pass locally. |
08605e8 to
bb3ffeb
Compare
andygrove
left a comment
There was a problem hiding this comment.
Two things before I can read this as an AVG fix.
The copy of #5421 in here predates its review. supportsNativePartialToSparkFinal still defaults to supportsSparkPartialToNativeFinal(fn), which is the inherited default that #5421 replaced with nine explicit per-function opt-ins in 6c14796f5 after @comphead raised it, and revertUnsafePartialAggregates is the version from before the unrepaired-producer diagnostic in 4b5f1704d. Merging as it stands would put both decisions back. Could you rebase onto #5421's head? operators.scala conflicts with main now as well.
The shuffle routing change is a separate fix riding along. CometShuffleExchangeExec.supportedShuffleType goes from case _: DecimalType => true with a TODO pointing at #3079 to d.precision <= 18, which resolves a hashing-compatibility question that has nothing to do with AVG, and your own numbers put it at 137 ms to 501.5 ms in native mode. Could it go in its own PR? That would let the routing change be benchmarked, reviewed and reverted independently of the accumulator work.
On the grouped ANSI decimal AVG guard, moving to Incompatible helps, but I do not think the trade has changed. This is the same divergence #5533 is about, which is that Comet evaluates a batch eagerly where Spark evaluates lazily and stops at a LIMIT, and over there the open question is whether to document the class or special-case the planner. Here we are picking the expensive side of it for a shape that is the default on Spark 4.x. All six regenerated TPC-DS plans are rooted at TakeOrderedAndProject, which consumes every group, so none of them benefits from the fallback and all of them pay for it. Would documenting this under "Known result-value divergences" in compatibility/index.md and keeping Compatible() be the better call? If the fallback stays, the opt-in deserves a line saying it is operator-wide, since spark.comet.operator.HashAggregateExec.allowIncompatible=true also accepts anything else that operator marks incompatible later.
The new expanding-frame guard in CometWindowExec only inspects Average. Spark's AggregateProcessor writes the window buffer into a SpecificInternalRow, which does not check decimal overflow the way UnsafeRowWriter does, so an expanding-frame decimal SUM has the same sticky-overflow divergence you are guarding AVG against. Should that be in the same match, or tracked alongside the decimal SUM point I left on #5421?
Last, this regenerates golden plans for the -spark4_0 and -spark3_5 tiers and the base tier, but only Spark 4.1 ran. Could you add run-all-spark-profiles?
The accumulator work itself reads well now. AvgAccumulator emitting (0.0, count) matches Literal.default(sumDataType) exactly, the scalar is_empty field is gone, and deferring the grouped merge overflow to evaluate is the right shape.
|
On the window question above, I filed the decimal SUM divergence as #6002, which covers the ever-expanding frame alongside the ungrouped aggregate and |
d6936a7 to
c59caf6
Compare
|
Thanks, Andy. Rebased onto main
Local Spark 4.1.3 validation passed full-reactor test compilation, Spotless, Scalastyle, Rust formatting, all 37 planner tests, and all 129 TPC-DS plan checks with generation disabled. The planner checks use a verified main CI library for initialization and do not execute the changed native AVG implementation. The configured local registry still lacks locked DataFusion 55.1.0, so fresh native AVG execution and cross-profile results are pending default-profile CI and additional-profile CI. Separately, #6005 passed seven focused execution tests, nine affected plan checks, and benchmark result validation using a verified CI library whose native source tree matches that branch exactly. |
|
Andy, I simplified the AVG patch further in 42a6bad39. This supersedes the grouped ANSI policy in my previous reply: grouped AVG now remains The scalar decimal accumulator also uses one update loop, and the test coverage is consolidated around distinct failures: empty partials crossing engines in both directions, sticky overflow, grouped state round trips with a zeroed null-count payload, and the 27/28 precision boundary. The grouped columnar-shuffle test includes overflowing, valid, and all-null groups and checks legacy, TRY, and ANSI behavior. The reviewed #5421 prerequisite remains intact, wide-decimal shuffle remains separate in #6005, and the window guard stays AVG-only with decimal SUM documented under #6002. Beyond the prerequisite on the same main baseline, the patch is now +571/-216, down from +1475/-224. No benchmark or golden-file changes remain here. Full-reactor Spark 4.1.3 test compilation, formatting/style checks, all 37 planner tests, and all 129 TPC-DS plan checks pass. The planning checks use a verified main native library only for initialization. Current-head CI has |
andygrove
left a comment
There was a problem hiding this comment.
The compatibility argument reads well now, and I checked it against Average.scala rather than taking it on trust. UnsafeRow.setDecimal nulling the field when changePrecision fails is what makes the grouped case genuinely equivalent to Comet, and doProduceWithoutKeys keeping the buffer in Decimal mutable state is what makes the ungrouped case genuinely different. Deferring the grouped merge error to evaluate and dropping count > 0 from the ANSI check are both right. I had not appreciated that the second is a fix rather than a relaxation, since the old guard would have swallowed the error after a columnar shuffle zeroed the count payload.
Three things I would still like before this goes in.
The docs do not say the ungrouped fallback takes the whole operator with it. The new Aggregation section in docs/source/user-guide/latest/compatibility/operators.md reads as if only the average falls back, but your own change to final decimal avg shows SELECT MIN(a), MAX(a), COUNT(a), SUM(a), AVG(a) FROM $table dropping from 2 native aggregates to 0. A single wide-decimal AVG costs a user native execution for every aggregate sharing that operator. Could the section say so? That seems like the thing a reader of that page would most want to know.
The fixture that justifies the ungrouped fallback never asserts the value that justifies it. Every case in high-precision global decimal AVG and TRY_AVG fall back to Spark uses checkSparkAnswerAndNumOfAggregates(..., 0), and once the aggregate has fallen back Comet is Spark, so the answer comparison cannot fail. That pins the fallback without pinning the reason for it. Would you add a checkAnswer on the AVG(v38) cases asserting 0.6 at the result scale? I worked through DecimalDivideWithOverflowCheck and I believe Spark does return 0.6 where native returns NULL, but that is the entire justification for the guard and nothing in the suite records it. The repartition(2, col("ord")) case is the better one to pin, since it does not depend on the exchange being elided by coalesce(1).
The grouped overflow round trip only runs over columnar shuffle. grouped decimal AVG preserves overflow across columnar shuffle pins CometColumnarShuffle, which is the harder case and the right one to have. But spark.comet.shuffle.mode defaults to auto and prefers native, and the grouping key there is an int, so the default path for that shape is the one not covered. Could the test loop over jvm and native? Removing the partial_counts.null_count() handling leaves the sum's null bit as the only thing carrying overflow across the exchange, so it would be good to have both writers on record.
Ordering note rather than a finding. This still carries #5421 in full, now at 4b5f1704d, so the merge order still matters and #5421 needs to land first.
42a6bad to
71a1a1d
Compare
|
Thanks, Andy. Addressed the three points in 7e9026df4:
#5421 has merged, and the rebase removed it from this PR's diff. This follow-up changes two files. Both affected tests pass on Spark 4.1.3 / JDK 17 with the current-source native library; full-reactor compilation, Spotless, Scalastyle, and whitespace checks pass. Current-head CI is running with all Spark profiles and Spark 4.1 SQL tests enabled. |
sunchao
left a comment
There was a problem hiding this comment.
Summary
- Prior state and problem: Empty native AVG partials could poison Spark’s final sum. Decimal overflow could be lost during updates, merging or shuffle.
- Design approach: Initialize sums to zero, preserve sticky decimal overflow, defer grouped ANSI errors until evaluation, and keep incompatible global/window decimal averages in Spark.
- Correctness / compatibility analysis: Compared Spark’s AVG expressions, decimal arithmetic, UnsafeRow buffers, generated aggregation and window processing across Spark 3.4.3, 3.5.9, 4.0.4, 4.1.3 and 4.2.0. The changes correctly distinguish empty input from overflow. Reviewed mixed execution, DISTINCT, precision boundaries and both shuffle writers.
- Key design decisions: Nondecimal AVG explicitly permits native partials before Spark final aggregation. Decimal buffers remain excluded from mixed execution. Grouped ANSI AVG retains the documented batch/LIMIT error-timing difference.
- Implementation sketch: Rust accumulator changes simplify scalar state by removing redundant flags. Scala admission checks reuse the existing compatibility policy. Regression tests cover state round trips, explicit decimal results and actual shuffle-writer selection.
- Behavioral changes worth calling out: Global and expanding-window decimal AVG/TRY_AVG fall back at input precision 28 and above. The aggregate fallback also moves sibling aggregates to Spark, reducing native coverage as documented. Performance was assessed structurally, without benchmark measurements.
- Suggested improvements: None meeting the requested P1/P2 bar. Previous review requests are addressed. No introduced P1/P2 issues found within this review, and no unresolved existing P1/P2 blockers remain.
Reviewed all 11 changed files across both commits at 7e9026df4968111be023dbe72610bc4e3df9ba0e, relative to dd68a531c413c287c1f5fbe12ade4edb488900e5. The PR remains open and non-draft. Read repository guidance and all existing reviews/discussion. Routed skills: review-comet-pr, review-comet-expression-pr, and review-comet-shuffle-pr.
Exact-head CI: run 35946785166 passed. GitHub reports 48 successful and 14 skipped checks, with none failed or pending. Logs confirm 1,627 Rust tests and 992 Spark 4.1 execution tests passed, including the new AVG regressions. Comet suites across Spark 3.4–4.2, Spark 4.1 SQL suites, and TPC-H/TPC-DS verification passed.
Local validation: All four focused AVG Rust tests passed using cargo test --locked --offline -p datafusion-comet-spark-expr agg_funcs::avg --lib. Whitespace checks passed and the working tree remains clean. JVM integration suites were not rerun locally. CI skipped macOS, Iceberg and upstream Spark SQL suites outside 4.1.
andygrove
left a comment
There was a problem hiding this comment.
Everything from my last review is in, and I checked each piece by removing what it pins. With the ungrouped guard turned off, the new checkAnswer calls fail for AVG(v38), TRY_AVG(v38), the COUNT(DISTINCT ord) case and the repartition(2, col("ord")) case, so the fixture now records why the fallback exists. With main merged in, CometAggregateSuite, CometWindowExecSuite, CometExecRuleSuite and CometCelebornShufflePlanningSuite all pass locally on 4.1 and 3.5. CI at this head ran the [exec] bucket, plan-stability suites included, on every profile from 3.4 to 4.2.
There are two things left, both inline. One is a single extra fixture row so the native shuffle leg actually depends on the null bit that carries overflow across the exchange. The other is new since my last review. #6041 now declines grouped maximum-precision SUM under ObjectHashAggregateExec, and doing the same for AVG would close #5509 in two lines. I'm happy to approve once those are in.
| SQLConf.SHUFFLE_PARTITIONS.key -> "2", | ||
| CometConf.COMET_SHUFFLE_ENABLED.key -> "true") { | ||
| withTempDir { dir => | ||
| Seq((1, 0, "0.6"), (1, 0, "0.6"), (2, 2, "0.1"), (2, 2, "0.2"), (3, 4, null)) |
There was a problem hiding this comment.
Could group 1 get a third row, (1, 0, "-0.6")? As written, the native leg passes even with the partial_sums.is_null(idx) check removed from AvgDecimalGroupsAccumulator::merge_batch. Native shuffle keeps the payload of the null sum, which here is the overflowed 1.2, so the final merge overflows again without needing the null bit. Only the JVM leg's ANSI case catches that mutation. With the extra row the payload comes back to 0.6, and the native leg fails under the same mutation. Unmutated, the test still passes on both legs with the same expected results, because Spark's UnsafeRow buffer has already latched group 1 to null by then.
| }) | ||
|
|
||
| protected def aggregateSupportLevel(op: BaseAggregateExec): SupportLevel = { | ||
| val unsupportedAverage = op.groupingExpressions.isEmpty && |
There was a problem hiding this comment.
Grouped max-precision AVG under ObjectHashAggregateExec still diverges, which is #5509. With main merged in, SELECT g, AVG(v), sort_array(collect_list(ord)) FROM t GROUP BY g over DECIMAL(38,38) values 0.6, 0.6, -0.4 returns NULL natively, or ARITHMETIC_OVERFLOW under ANSI, where Spark returns 0.26666666666666666666666666666666666667. The SUM version of the same query falls back and matches, because #6041 declines it in CometObjectHashAggregateExec.getSupportLevel, and its comment there already says decimal AVG has the same gap. Extending this check to ObjectHashAggregateExec with grouping keys fixed both ANSI modes for me, and all of CometAggregateSuite still passed. A hasMaxPrecisionDecimalAvg next to hasMaxPrecisionDecimalSum might be the tidiest way to write it. Could this PR decline that case too and close #5509? If you'd rather keep it separate, could #5509 go in the known result-value divergences list in compatibility/index.md, since it returns NULL without an error in legacy mode?
sunchao
left a comment
There was a problem hiding this comment.
Summary
- Prior state and problem: Empty native AVG partials exported
(NULL, 0), which could poison Spark’s final sum. Decimal overflow could lose its invalid-state marker. - Design approach: Initialize empty sums to zero, preserve sticky decimal overflow, defer grouped ANSI errors until evaluation, and restrict incompatible global/window aggregation.
- Correctness / compatibility analysis: Compared Spark’s AVG, decimal arithmetic, generated aggregation and row-buffer semantics across Spark 3.4.3, 3.5.9, 4.0.4, 4.1.3 and 4.2.0. No introduced P1/P2 issues found within this review.
- Key design decisions: Nondecimal AVG buffers can cross engines in both directions. Decimal buffers remain excluded. Grouped ANSI AVG retains the documented batch/LIMIT error-timing difference.
- Implementation sketch: Scalar state becomes simpler by removing redundant flags. Grouped state preserves overflow through shuffle. Existing planner compatibility checks enforce fallback without a new configuration or abstraction.
- Behavioral changes worth calling out: Global and expanding-window decimal AVG/TRY_AVG fall back at input precision 28 and above. Global fallback also moves sibling aggregates to Spark. This reduces native coverage as documented. Performance was assessed structurally, without benchmark measurements.
- Suggested improvements: No additional P1/P2 findings. The existing ObjectHash AVG thread remains unresolved. For grouped
DECIMAL(38,38)values0.6, 0.6, -0.4alongsidecollect_list, Spark returns0.26666666666666666666666666666666666667, while native execution returns NULL or an ANSI overflow. Spark’s object buffer and native overflow latching substantiate this concern. It predates this PR, is tracked by #5509, and is not duplicated as a new finding.
Reviewed all 11 changed files across both commits at 7e9026df4968111be023dbe72610bc4e3df9ba0e, relative to dd68a531c413c287c1f5fbe12ade4edb488900e5. Confirmed non-draft status and read existing reviews, comments and threads. Routed skills: review-comet-pr, review-comet-expression-pr, review-comet-shuffle-pr.
Exact-head CI: run 35946785166 passed. GitHub reports 48 successful and 14 skipped checks, with none failed or pending. Logs confirm 1,627 Rust tests and 992 Spark 4.1 execution tests passed, including the AVG regressions. All supported Comet Spark profiles, Spark 4.1 SQL suites and TPC-H/TPC-DS verification passed.
Local validation: All four tests passed with cargo test --locked --offline -p datafusion-comet-spark-expr agg_funcs::avg --lib. Whitespace checks passed and the working tree is clean. JVM integration tests were not rerun locally. CI skipped macOS, Iceberg and upstream Spark SQL suites outside 4.1.
|
This is a light fully automated review since there are so many PRs open.
|
sunchao
left a comment
There was a problem hiding this comment.
Summary
- Prior state and problem: Empty native AVG partials exported
(NULL, 0), which could poison Spark’s final sum. Decimal overflow state could be lost during updates, merging or shuffle. - Design approach: Initialize empty sums to zero, preserve sticky decimal overflow, defer grouped ANSI errors until evaluation, and restrict incompatible global/window aggregation.
- Correctness / compatibility analysis: Compared Spark’s AVG, decimal division, aggregation buffers and window processing across Spark 3.4.3, 3.5.9, 4.0.4, 4.1.3 and 4.2.0. Reviewed empty/all-null input, mixed execution, DISTINCT, precision boundaries and both shuffle writers. No introduced P1/P2 issues found within this review.
- Key design decisions: Nondecimal AVG buffers can cross engines in both directions. Decimal buffers remain excluded. Grouped ANSI AVG retains the documented batch/LIMIT error-timing difference.
- Implementation sketch: Scalar decimal state removes redundant flags and uses
Some(0)for empty input andNonefor overflow. Grouped state retains its overflow bitmap. Planner guards reuse existing compatibility checks without adding configuration or another abstraction. - Behavioral changes worth calling out: Global and expanding-window decimal AVG/TRY_AVG fall back at input precision 28 and above. Global fallback also moves sibling aggregates to Spark. This reduces native coverage as documented. Performance was assessed structurally, without benchmark measurements.
- Suggested improvements: No new P1/P2 findings. Existing correctness concerns remain unresolved: the ObjectHash AVG thread, tracked by #5509, and the decimal division/ANSI comment. Disposable native probes reproduced both concerns using the base and head accumulator implementations. For grouped
DECIMAL(38,38)values0.6, 0.6, -0.4, native returns NULL or an ANSI overflow where Spark’s object buffer permits a valid average. ForDECIMAL(38,18), two9000000000000000values incorrectly produce NULL during native scaling. A single100000000000000000also returns NULL instead of Spark’s ANSI range error. These are existing blockers, not duplicated new findings.
Reviewed all 11 changed files across both commits at 7e9026df4968111be023dbe72610bc4e3df9ba0e, relative to dd68a531c413c287c1f5fbe12ade4edb488900e5. Confirmed non-draft status and read existing reviews, issue comments, inline comments and threads. Routed skills: review-comet-pr, review-comet-expression-pr, review-comet-shuffle-pr.
Exact-head CI: run 35946785166 passed, with 48 successful and 14 skipped checks and none failed or pending. Logs confirm 1,627 Rust tests and 992 Spark 4.1 execution tests passed, including the AVG regressions. All supported Comet Spark profiles, Spark 4.1 SQL suites and TPC-H/TPC-DS verification passed.
Local validation: All four focused AVG Rust tests passed. Base/head probes confirmed the existing concerns. Disposable changes were removed, restored-head tests passed again, and whitespace checks and working-tree checks were clean. JVM integration suites were not rerun locally. CI skipped macOS, Iceberg and upstream Spark SQL suites outside 4.1.
Which issue does this PR close?
Closes #5418. Builds on the now-merged #5421. Wide-decimal shuffle routing and its benchmark are separate in #6005.
Rationale for this change
An empty native AVG partial exports
(NULL, 0), while Spark expects(0, 0). When Spark merges that buffer with a nonempty partition, the null sum can erase the result. Decimal AVG must also distinguish empty input from overflow and keep overflow sticky through merging and shuffle.What changes are included in this PR?
Some(0)for empty input andNonefor overflow.LIMIT.Rebased onto main
dd68a531c. The prerequisite is no longer included in this PR's diff: 11 files, +581/-216, with no benchmark or golden-file changes. Main's newer decimal SUM behavior and compatibility guards are preserved.How are these changes tested?
Focused Rust and Scala regressions cover empty buffers crossing engines in both directions, sticky scalar overflow, grouped state round trips and deferred errors, JVM and native shuffle, DISTINCT, and the global/window precision boundary. The global AVG fixture asserts explicit expected results, including
0.6at scale 38 after repartitioning. The grouped overflow fixture asserts the actual partial-buffer shuffle writer in each mode, covering legacy AVG, ANSI TRY_AVG, ANSI errors, valid groups, and all-null groups.The follow-up at
7e9026df4changes only documentation and the two existing regression tests. Current-source native compilation, Spark 4.1.3 / JDK 17 full-reactor test compilation, Spotless, Scalastyle, whitespace checks, and both affected tests pass. The loaded JNI library checksum matches the current-source build. Current-head CI is running.Rebased-head CI at 71a1a1d80 passed native build/Rust tests, the Comet suites on Spark 3.4/3.5/4.0/4.1/4.2, TPC-H/TPC-DS result verification, and Spark 4.1 SQL tests. Those results precede this docs/test follow-up. The PR retains
run-all-spark-profilesandrun-spark-4.1-tests.