Smallfu666 opened a new pull request, #5357:
URL: https://github.com/apache/datafusion-comet/pull/5357
## Which issue does this PR close?
Closes #5356.
## Rationale for this change
Under ANSI mode, `abs` on an integer minimum raises `ARITHMETIC_OVERFLOW`,
whose template renders
`<message> overflow`. `native/spark-expr/src/math_funcs/abs.rs` was passing
Arrow-style type names
as that message, hard-coded at each arm, so Comet reported `Int64 overflow`
where Spark reports
`long overflow`, and `Int32 overflow` where Spark reports `integer overflow`.
```sql
SET spark.sql.ansi.enabled=true;
SELECT abs(v) FROM t; -- v BIGINT, single row -9223372036854775808
```
Spark: `[ARITHMETIC_OVERFLOW] long overflow.`
Comet before this PR: same error class, `Int64 overflow`.
The message is what the user sees in the exception, and it is what any
assertion on the error
parameters compares against.
## What changes are included in this PR?
The eight `from_type` strings in `abs.rs`, four on the array path through
`ansi_compute_op!` and
four on the scalar path, now carry Spark's name instead of Arrow's:
| Arrow | was | now |
| --- | --- | --- |
| `Int8` | `"Int8"` | `"byte"` |
| `Int16` | `"Int16"` | `"short"` |
| `Int32` | `"Int32"` | `"integer"` |
| `Int64` | `"Int64"` | `"long"` |
The mapping is not uniform across the supported Spark versions, so a three
line comment on
`ansi_compute_op!` records which strings are exact where. Spark's `Abs`
negates through
`MathUtils.negateExact`. For int and long that surfaces the JDK
`ArithmeticException` text, which is
`integer overflow` and `long overflow` on 3.4, 3.5 and 4.x alike. Byte and
short match 4.x only:
3.4 and 3.5 route those two widths to
`QueryExecutionErrors.unaryMinusCauseOverflowError`, raising
`_LEGACY_ERROR_TEMP_2043` (`- <sqlValue> caused overflow.`), a different
error class, so no single
string can satisfy every version. 4.0 sends all four widths through
`MathUtils.negateExact`. I
verified this against the 3.4.3, 3.5.8, 4.0.2 and 4.1.2 jars.
`Decimal128` and `Decimal256` are deliberately left alone. Those guards fire
only at `i128::MIN` and
`i256::MIN`, which no Spark decimal reaches at its maximum precision of 38,
and decimal overflow
goes through a different Spark error class. That belongs in its own change.
## How are these changes tested?
**`abs_ansi.sql`.** The fixture already ran `abs(v)` over a column of each
width at its minimum, but
every assertion was `expect_error(overflow)`, which `"Int64 overflow"`
satisfies exactly as happily
as `"long overflow"`. It could not fail on this bug. The int and long cases
now assert the full
message, `expect_error(integer overflow)` and `expect_error(long overflow)`.
Byte and short stay on the loose pattern, and the fixture says why in a
comment: `ExpectError`
asserts the pattern against Spark's message as well as Comet's, and on 3.4
and 3.5 Spark genuinely
words those two differently.
`ExpectError` runs both engines through `checkSparkAnswerMaybeThrows` and
requires both to throw, so
the column cases exercise the Comet path rather than a constant fold.
Negative control at the Spark level, production reverted and the fixture
kept:
`org.apache.comet.CometSqlFileTestSuite` on Spark 3.5 / Scala 2.12 goes from
**444 run, 444
succeeded** to **444 run, 443 succeeded, 1 failed**, the failure being
`expressions/math/abs_ansi.sql:57`, `SELECT abs(v) FROM ansi_test_abs_int`,
`does not contain
'integer overflow'`. Spark is identical between the two runs, so that
failure is the Comet side of
the assertion.
**Rust.** The ANSI branches had no error assertions at all, so this adds two
tests:
- `test_ansi_abs_min_uses_spark_type_names` downcasts to
`SparkError::ArithmeticOverflow` and
asserts `from_type` for all four widths on both the array and the scalar
path. Asserting the
variant and the field rather than a substring of the rendered string.
- `test_ansi_abs_just_inside_boundary_succeeds` checks `MIN + 1` for each
width still returns `MAX`,
so the guard is not over-broad.
Negative control on the unpatched production code with these tests kept:
**18 passed, 1 failed**,
the failure being `assertion left == right failed, left: "Int8", right:
"byte"`. Note it stops at
the first case in the table, so what is proven red on `main` is the byte
case in Rust and the int
case at the Spark level.
Also run on this branch: the full `datafusion-comet-spark-expr` lib suite,
`cargo fmt --all --
--check`, and `cargo clippy -p datafusion-comet-spark-expr --all-targets --
-D warnings`.
## Note for reviewers
TINYINT and SMALLINT have no Spark-level regression test here, only the Rust
one, for the version
reason above. If you would rather see them covered, the fixture would need
to gate the assertion on
the Spark version, which felt like more machinery than the case is worth.
--
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]