sunchao commented on code in PR #4987:
URL: https://github.com/apache/datafusion-comet/pull/4987#discussion_r4315609821
##########
spark/src/main/scala/org/apache/spark/sql/comet/CometWindowExec.scala:
##########
@@ -393,30 +393,30 @@ object CometWindowExec extends
CometOperatorSerde[WindowExec] {
}
}
- // Comet's native window planner ships RANGE frame offsets as
- // ScalarValue::Int64, which the DECIMAL comparator can't handle: Spark
- // decimal arithmetic widens precision on +/-, so the computed boundary
- // (e.g. Decimal(11,0)) doesn't match the current value's precision
- // (e.g. Decimal(10,0)) and the comparator fails with "Uncomparable
- // values". Fall back for DECIMAL until the native side normalizes
- // precision. DATE is now handled natively by wrapping the offset as
- // IntervalDayTime in the planner. UNBOUNDED / CURRENT ROW bounds don't
- // evaluate the offending arithmetic and stay native regardless.
+ // DataFusion computes a RANGE frame bound as `current +/- offset` and
treats
+ // a bound that overflows as the edge of the partition, which also takes in
+ // NULL keys sorted at that edge. Spark's bound never overflows that way,
so
+ // fall back for the offsets that can overflow. UNBOUNDED / CURRENT ROW
+ // bounds skip the arithmetic and stay native.
//
// For DATE, Spark computes the bound with DateAdd, an Int addition that
- // wraps silently on overflow, while DataFusion treats an overflowing bound
- // as the partition edge. Over dates in Spark's supported range the two
only
- // disagree when the offset is large enough to wrap, so fall back for those
- // offsets. https://github.com/apache/datafusion-comet/issues/5022
+ // wraps silently on overflow. Over dates in Spark's supported range the
two
+ // only disagree when the offset is large enough to wrap, so fall back for
+ // those offsets.
+ //
+ // For DECIMAL, Spark's DecimalAddNoOverflowCheck keeps the exact bound,
+ // while DataFusion adds in Decimal128 and overflows past i128.
+ // https://github.com/apache/datafusion-comet/issues/5022
f match {
case SpecifiedWindowFrame(RangeFrame, lb, ub)
if !lb.isInstanceOf[SpecialFrameBoundary] ||
!ub.isInstanceOf[SpecialFrameBoundary] =>
windowExpr.windowSpec.orderSpec.headOption.map(_.dataType) match {
- case Some(_: DecimalType) =>
+ case Some(dt: DecimalType) if !Seq(lb,
ub).forall(isDecimalRangeOffsetSafe(_, dt)) =>
Review Comment:
[P2] [P2] Preserve Spark's descending decimal-offset negation
Could this fallback also account for offsets whose magnitude changes when
Spark negates them for descending order? With `d DECIMAL(35,0)` containing
`[N,0]`, where `N = 10000000000000000000000000000000001`, `COUNT(*) OVER (ORDER
BY d DESC RANGE BETWEEN CURRENT ROW AND N FOLLOWING)` returns `[1,1]` on Spark
4.1.3 under both ANSI settings. Spark's `UnaryMinus(offset)` rounds to
`-10000000000000000000000000000000000`, leaving the first row's boundary at
`1`. This guard returns true, and `rangeBoundLiteral` preserves the positive
offset exactly, so the native frame subtracts `N`, reaches `0`, and returns
`[2,1]`. The previous blanket fallback preserved Spark's result. Please retain
fallback for affected descending offsets or serialize Spark's effective offset,
with a regression containing rows at the differing boundary.
Evidence: Reproduction: create `t` with `SELECT CAST(str AS DECIMAL(35,0))
AS d FROM VALUES ('10000000000000000000000000000000001'), ('0') AS v(str)`,
then run `SELECT d, COUNT(*) OVER (ORDER BY d DESC RANGE BETWEEN CURRENT ROW
AND 10000000000000000000000000000000001 FOLLOWING) AS c FROM t ORDER BY d
DESC`. Spark 4.1.3 produced counts `[1,1]` with ANSI true and false. The
compiled exact-head `isDecimalRangeOffsetSafe` returned true and the serialized
`d.abs` retained all 35 digits. The lockfile-matching DataFusion 55.2.0/Arrow
59.3.0 `WindowFrameContext`, using `CurrentRow` and the exact decimal
`Following` scalar, produced `[2,1]`. Also reproduced with `DECIMAL(35,34)` and
offset `1.0000000000000000000000000000000001`. Spark 3.5.9 returned `[2,1]`,
confirming the version-dependent behavior. Harnesses and logs are under
`/tmp/comet4987-83a6-review/`.
--
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]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]