This is an automated email from the ASF dual-hosted git repository.
yao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new a7990f30b2e2 [SPARK-55755][SQL][TESTS] Handle null ArithmeticException
message on JDK 25
a7990f30b2e2 is described below
commit a7990f30b2e22e30278d3cc09999d2044223c880
Author: Kent Yao <[email protected]>
AuthorDate: Sat Feb 28 23:10:43 2026 +0800
[SPARK-55755][SQL][TESTS] Handle null ArithmeticException message on JDK 25
### What changes were proposed in this pull request?
On JDK 25, `Math.multiplyExact`/`Math.addExact` may throw
`ArithmeticException` without a message (null instead of `"long overflow"`).
This causes `NullPointerException` in tests that check the raw exception
message via `.getMessage.contains(...)`.
This PR:
1. **`MathUtils.withOverflow`**: Provides a fallback message `"Overflow"`
when the raw JDK exception message is null, preventing null propagation into
Spark error conditions (both interpreted and codegen paths).
2. **Test assertions**: Makes raw `ArithmeticException` message checks
null-safe across:
- `DateExpressionsSuite` (line 1825)
- `CatalystTypeConvertersSuite` (line 305)
- `DateTimeUtilsSuite` (line 835)
- `IntervalUtilsSuite` (line 593)
- `TimestampFormatterSuite` (lines 451, 453)
### Why are the changes needed?
The JDK 25 scheduled CI build fails with:
```
java.lang.NullPointerException: Cannot invoke
"String.contains(java.lang.CharSequence)" because
"$org_scalatest_assert_macro_left" is null
at DateExpressionsSuite.scala:1825
```
See:
https://github.com/apache/spark/actions/runs/22513372344/job/65226962993
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Existing tests pass on JDK 17. The `MathUtils.withOverflow` fix ensures
non-null messages regardless of JDK version.
### Was this patch authored or co-authored using generative AI tooling?
Yes, co-authored with GitHub Copilot.
Closes #54553 from yaooqinn/fix-jdk25-long-overflow.
Authored-by: Kent Yao <[email protected]>
Signed-off-by: Kent Yao <[email protected]>
---
.../main/scala/org/apache/spark/sql/catalyst/util/MathUtils.scala | 7 +++++--
.../apache/spark/sql/catalyst/CatalystTypeConvertersSuite.scala | 3 ++-
.../spark/sql/catalyst/expressions/DateExpressionsSuite.scala | 3 ++-
.../org/apache/spark/sql/catalyst/util/DateTimeUtilsSuite.scala | 3 ++-
.../org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala | 3 ++-
.../apache/spark/sql/catalyst/util/TimestampFormatterSuite.scala | 5 +++--
6 files changed, 16 insertions(+), 8 deletions(-)
diff --git
a/sql/api/src/main/scala/org/apache/spark/sql/catalyst/util/MathUtils.scala
b/sql/api/src/main/scala/org/apache/spark/sql/catalyst/util/MathUtils.scala
index b113bccc74df..9f8ee7ae9319 100644
--- a/sql/api/src/main/scala/org/apache/spark/sql/catalyst/util/MathUtils.scala
+++ b/sql/api/src/main/scala/org/apache/spark/sql/catalyst/util/MathUtils.scala
@@ -94,7 +94,9 @@ object MathUtils {
f
} catch {
case e: ArithmeticException =>
- throw ExecutionErrors.arithmeticOverflowError(e.getMessage, hint,
context)
+ // On JDK 25+, Math.*Exact may throw ArithmeticException without a
message
+ val message = if (e.getMessage != null) e.getMessage else "Overflow"
+ throw ExecutionErrors.arithmeticOverflowError(message, hint, context)
}
}
@@ -103,7 +105,8 @@ object MathUtils {
|try {
| $evalCode
|} catch (ArithmeticException e) {
- | throw QueryExecutionErrors.arithmeticOverflowError(e.getMessage(),
"", $context);
+ | String msg = e.getMessage() != null ? e.getMessage() : "Overflow";
+ | throw QueryExecutionErrors.arithmeticOverflowError(msg, "",
$context);
|}
|""".stripMargin
}
diff --git
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/CatalystTypeConvertersSuite.scala
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/CatalystTypeConvertersSuite.scala
index 1b46825b3414..75ca908a941b 100644
---
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/CatalystTypeConvertersSuite.scala
+++
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/CatalystTypeConvertersSuite.scala
@@ -302,7 +302,8 @@ class CatalystTypeConvertersSuite extends SparkFunSuite
with SQLHelper {
val errMsg = intercept[ArithmeticException] {
IntervalUtils.durationToMicros(Duration.ofSeconds(Long.MaxValue,
Long.MaxValue))
}.getMessage
- assert(errMsg.contains("long overflow"))
+ // On JDK 25+, Math.multiplyExact may throw ArithmeticException without a
message
+ assert(errMsg == null || errMsg.contains("long overflow"))
}
test("SPARK-35726: Truncate java.time.Duration by fields of day-time
interval type") {
diff --git
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/DateExpressionsSuite.scala
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/DateExpressionsSuite.scala
index 4e942b8b3e51..dede06bdc4b6 100644
---
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/DateExpressionsSuite.scala
+++
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/DateExpressionsSuite.scala
@@ -1822,7 +1822,8 @@ class DateExpressionsSuite extends SparkFunSuite with
ExpressionEvalHelper {
null)
}.getCause
assert(e.isInstanceOf[ArithmeticException])
- assert(e.getMessage.contains("long overflow"))
+ // On JDK 25+, Math.multiplyExact may throw ArithmeticException
without a message
+ assert(e.getMessage == null || e.getMessage.contains("long overflow"))
checkEvaluation(
TimestampAddInterval(
diff --git
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/DateTimeUtilsSuite.scala
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/DateTimeUtilsSuite.scala
index b5b69a834037..e7f29f547fc4 100644
---
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/DateTimeUtilsSuite.scala
+++
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/DateTimeUtilsSuite.scala
@@ -832,7 +832,8 @@ class DateTimeUtilsSuite extends SparkFunSuite with
Matchers with SQLHelper {
val msg = intercept[ArithmeticException] {
DateTimeUtils.localDateTimeToMicros(dt)
}.getMessage
- assert(msg == "long overflow")
+ // On JDK 25+, Math.multiplyExact may throw ArithmeticException without
a message
+ assert(msg == null || msg == "long overflow")
}
}
diff --git
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala
index a87d599711cf..c8a8a0c1444a 100644
---
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala
+++
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/IntervalUtilsSuite.scala
@@ -590,7 +590,8 @@ class IntervalUtilsSuite extends SparkFunSuite with
SQLHelper {
val errMsg = intercept[ArithmeticException] {
durationToMicros(Duration.ofDays(106751991 + 1))
}.getMessage
- assert(errMsg.contains("long overflow"))
+ // On JDK 25+, Math.multiplyExact may throw ArithmeticException without a
message
+ assert(errMsg == null || errMsg.contains("long overflow"))
}
test("SPARK-34615: period to months") {
diff --git
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/TimestampFormatterSuite.scala
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/TimestampFormatterSuite.scala
index 558d7eda78b4..b1f6fefc2735 100644
---
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/TimestampFormatterSuite.scala
+++
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/TimestampFormatterSuite.scala
@@ -448,9 +448,10 @@ class TimestampFormatterSuite extends
DatetimeFormatterSuite {
assert(formatter.parse("294247") === date(294247))
assert(formatter.parse("-290307") === date(-290307))
val e1 = intercept[ArithmeticException](formatter.parse("294248"))
- assert(e1.getMessage === "long overflow")
+ // On JDK 25+, Math.multiplyExact may throw ArithmeticException without a
message
+ assert(e1.getMessage == null || e1.getMessage === "long overflow")
val e2 = intercept[ArithmeticException](formatter.parse("-290308"))
- assert(e2.getMessage === "long overflow")
+ assert(e2.getMessage == null || e2.getMessage === "long overflow")
}
test("SPARK-36418: default parsing w/o pattern") {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]