This is an automated email from the ASF dual-hosted git repository.

MaxGekk 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 4e5de2c0518d [SPARK-57577][SQL] Surface timestamp constructor overflow 
as Spark error condition
4e5de2c0518d is described below

commit 4e5de2c0518d68fc73410338768a29ec075738c8
Author: Mitchell <[email protected]>
AuthorDate: Thu Jul 2 12:25:46 2026 +0200

    [SPARK-57577][SQL] Surface timestamp constructor overflow as Spark error 
condition
    
    ### What changes were proposed in this pull request?
    
    This PR routes timestamp constructor overflow through `DATETIME_OVERFLOW` 
instead of raw `ArithmeticException` for overflowing `timestamp_seconds` and 
`timestamp_millis` inputs.
    
    It adds a shared `QueryExecutionErrors` helper for timestamp constructor 
overflow, uses it from interpreted and code-generated expression paths, and 
keeps the existing non-overflow decimal rounding behavior unchanged. 
`timestamp_micros` already accepts microseconds directly and has no 
unit-scaling overflow path, so this PR preserves its existing max/min input 
behavior.
    
    ### Why are the changes needed?
    
    The existing overflow paths can surface raw Java arithmetic errors such as 
`long overflow` or `Overflow`, which do not carry a Spark error condition or 
SQLSTATE. These timestamp constructor overflow cases should report a Spark 
error condition, consistent with other datetime overflow handling.
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. Overflowing `timestamp_seconds` and `timestamp_millis` inputs now fail 
with `DATETIME_OVERFLOW` / SQLSTATE `22008` instead of a raw 
`ArithmeticException`.
    
    ### How was this patch tested?
    
    ```
    ./build/sbt "catalyst/testOnly 
org.apache.spark.sql.catalyst.expressions.DateExpressionsSuite -- -z 
TIMESTAMP_SECONDS -z TIMESTAMP_MILLIS -z TIMESTAMP_MICROS"
    ./build/sbt "sql/testOnly 
org.apache.spark.sql.errors.QueryExecutionErrorsSuite -- -z constructors"
    ./build/sbt "sql/testOnly org.apache.spark.sql.SQLQueryTestSuite -- -z 
timestamp.sql -z timestamp-ansi.sql -z datetime-legacy.sql"
    ```
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: OpenAI Codex
    
    Closes #56906 from 
michaelmitchell-bit/SPARK-57577-timestamp-function-overflow.
    
    Authored-by: Mitchell <[email protected]>
    Signed-off-by: Max Gekk <[email protected]>
---
 .../catalyst/expressions/datetimeExpressions.scala | 102 +++++++++++++++++++--
 .../spark/sql/errors/QueryExecutionErrors.scala    |  13 +++
 .../expressions/DateExpressionsSuite.scala         |  23 +++--
 .../sql-tests/results/datetime-legacy.sql.out      |  40 ++++++--
 .../sql-tests/results/nonansi/timestamp.sql.out    |  40 ++++++--
 .../resources/sql-tests/results/timestamp.sql.out  |  40 ++++++--
 .../results/timestampNTZ/timestamp-ansi.sql.out    |  40 ++++++--
 .../results/timestampNTZ/timestamp.sql.out         |  40 ++++++--
 .../sql/errors/QueryExecutionErrorsSuite.scala     |  22 +++++
 9 files changed, 306 insertions(+), 54 deletions(-)

diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
index 0e557d1be9d8..e7c6a1091861 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
@@ -629,19 +629,36 @@ abstract class IntegralToTimestampBase extends 
UnaryExpression
 
   protected def upScaleFactor: Long
 
+  protected def inputUnit: String
+
   override def inputTypes: Seq[AbstractDataType] = Seq(IntegralType)
 
   override def dataType: DataType = TimestampType
 
   override def nullSafeEval(input: Any): Any = {
-    Math.multiplyExact(input.asInstanceOf[Number].longValue(), upScaleFactor)
+    try {
+      Math.multiplyExact(input.asInstanceOf[Number].longValue(), upScaleFactor)
+    } catch {
+      case _: ArithmeticException =>
+        throw QueryExecutionErrors.timestampConstructorOverflowError(
+          input, child.dataType, inputUnit)
+    }
   }
 
   override protected def doGenCode(ctx: CodegenContext, ev: ExprCode): 
ExprCode = {
     if (upScaleFactor == 1) {
       defineCodeGen(ctx, ev, c => c)
     } else {
-      defineCodeGen(ctx, ev, c => s"java.lang.Math.multiplyExact($c, 
${upScaleFactor}L)")
+      val dataType = ctx.addReferenceObj("dataType", child.dataType, 
classOf[DataType].getName)
+      val errors = QueryExecutionErrors.getClass.getName.stripSuffix("$")
+      nullSafeCodeGen(ctx, ev, c =>
+        s"""
+           |try {
+           |  ${ev.value} = java.lang.Math.multiplyExact($c, 
${upScaleFactor}L);
+           |} catch (java.lang.ArithmeticException e) {
+           |  throw $errors.timestampConstructorOverflowError($c, $dataType, 
"$inputUnit");
+           |}
+           |""".stripMargin)
     }
   }
 }
@@ -675,10 +692,11 @@ case class SecondsToTimestamp(child: Expression) extends 
UnaryExpression
   @transient
   private lazy val evalFunc: Any => Any = child.dataType match {
     case _: IntegralType => input =>
-      Math.multiplyExact(input.asInstanceOf[Number].longValue(), 
MICROS_PER_SECOND)
+      withOverflowError(input) {
+        Math.multiplyExact(input.asInstanceOf[Number].longValue(), 
MICROS_PER_SECOND)
+      }
     case _: DecimalType => input =>
-      val operand = new java.math.BigDecimal(MICROS_PER_SECOND)
-      
input.asInstanceOf[Decimal].toJavaBigDecimal.multiply(operand).longValueExact()
+      decimalToMicros(input.asInstanceOf[Decimal])
     case _: FloatType => input =>
       val f = input.asInstanceOf[Float]
       if (f.isNaN || f.isInfinite) null else (f.toDouble * 
MICROS_PER_SECOND).toLong
@@ -687,14 +705,64 @@ case class SecondsToTimestamp(child: Expression) extends 
UnaryExpression
       if (d.isNaN || d.isInfinite) null else (d * MICROS_PER_SECOND).toLong
   }
 
+  private def withOverflowError(input: Any)(f: => Long): Long = {
+    try {
+      f
+    } catch {
+      case _: ArithmeticException =>
+        throw QueryExecutionErrors.timestampConstructorOverflowError(
+          input, child.dataType, "seconds")
+    }
+  }
+
+  private def decimalToMicros(input: Decimal): Long = {
+    val operand = new java.math.BigDecimal(MICROS_PER_SECOND)
+    val micros = input.toJavaBigDecimal.multiply(operand)
+    try {
+      micros.longValueExact()
+    } catch {
+      case e: ArithmeticException if isOutsideLongRange(micros) =>
+        throw QueryExecutionErrors.timestampConstructorOverflowError(
+          input, child.dataType, "seconds")
+      case e: ArithmeticException =>
+        throw e
+    }
+  }
+
+  private def isOutsideLongRange(value: java.math.BigDecimal): Boolean = {
+    value.compareTo(java.math.BigDecimal.valueOf(Long.MinValue)) < 0 ||
+      value.compareTo(java.math.BigDecimal.valueOf(Long.MaxValue)) > 0
+  }
+
   override def nullSafeEval(input: Any): Any = evalFunc(input)
 
   override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = 
child.dataType match {
     case _: IntegralType =>
-      defineCodeGen(ctx, ev, c => s"java.lang.Math.multiplyExact($c, 
${MICROS_PER_SECOND}L)")
+      timestampSecondsCodeGen(ctx, ev) { c =>
+        s"${ev.value} = java.lang.Math.multiplyExact($c, 
${MICROS_PER_SECOND}L);"
+      }
     case _: DecimalType =>
       val operand = s"new java.math.BigDecimal($MICROS_PER_SECOND)"
-      defineCodeGen(ctx, ev, c => 
s"$c.toJavaBigDecimal().multiply($operand).longValueExact()")
+      val dataType = ctx.addReferenceObj("dataType", child.dataType, 
classOf[DataType].getName)
+      val minLong = ctx.addReferenceObj("minLong",
+        java.math.BigDecimal.valueOf(Long.MinValue), 
classOf[java.math.BigDecimal].getName)
+      val maxLong = ctx.addReferenceObj("maxLong",
+        java.math.BigDecimal.valueOf(Long.MaxValue), 
classOf[java.math.BigDecimal].getName)
+      val errors = QueryExecutionErrors.getClass.getName.stripSuffix("$")
+      nullSafeCodeGen(ctx, ev, c => {
+        val micros = ctx.freshName("micros")
+        s"""
+           |java.math.BigDecimal $micros = 
$c.toJavaBigDecimal().multiply($operand);
+           |try {
+           |  ${ev.value} = $micros.longValueExact();
+           |} catch (java.lang.ArithmeticException e) {
+           |  if ($micros.compareTo($minLong) < 0 || 
$micros.compareTo($maxLong) > 0) {
+           |    throw $errors.timestampConstructorOverflowError($c, $dataType, 
"seconds");
+           |  }
+           |  throw e;
+           |}
+           |""".stripMargin
+      })
     case other =>
       val castToDouble = if (other.isInstanceOf[FloatType]) "(double)" else ""
       nullSafeCodeGen(ctx, ev, c => {
@@ -709,6 +777,22 @@ case class SecondsToTimestamp(child: Expression) extends 
UnaryExpression
       })
   }
 
+  private def timestampSecondsCodeGen(
+      ctx: CodegenContext,
+      ev: ExprCode)(
+      convert: String => String): ExprCode = {
+    val dataType = ctx.addReferenceObj("dataType", child.dataType, 
classOf[DataType].getName)
+    val errors = QueryExecutionErrors.getClass.getName.stripSuffix("$")
+    nullSafeCodeGen(ctx, ev, c =>
+      s"""
+         |try {
+         |  ${convert(c)}
+         |} catch (java.lang.ArithmeticException e) {
+         |  throw $errors.timestampConstructorOverflowError($c, $dataType, 
"seconds");
+         |}
+         |""".stripMargin)
+  }
+
   override def prettyName: String = "timestamp_seconds"
 
   override protected def withNewChildInternal(newChild: Expression): 
SecondsToTimestamp =
@@ -731,6 +815,8 @@ case class MillisToTimestamp(child: Expression)
 
   override def upScaleFactor: Long = MICROS_PER_MILLIS
 
+  override def inputUnit: String = "milliseconds"
+
   override def prettyName: String = "timestamp_millis"
 
   override protected def withNewChildInternal(newChild: Expression): 
MillisToTimestamp =
@@ -753,6 +839,8 @@ case class MicrosToTimestamp(child: Expression)
 
   override def upScaleFactor: Long = 1L
 
+  override def inputUnit: String = "microseconds"
+
   override def prettyName: String = "timestamp_micros"
 
   override protected def withNewChildInternal(newChild: Expression): 
MicrosToTimestamp =
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
index ad426c347914..71ae98253853 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/errors/QueryExecutionErrors.scala
@@ -2650,6 +2650,19 @@ private[sql] object QueryExecutionErrors extends 
QueryErrorsBase with ExecutionE
       summary = "")
   }
 
+  def timestampConstructorOverflowError(
+      value: Any,
+      valueType: DataType,
+      unit: String): SparkArithmeticException = {
+    new SparkArithmeticException(
+      errorClass = "DATETIME_OVERFLOW",
+      messageParameters = Map(
+        "operation" ->
+          s"create a TIMESTAMP from ${toSQLValue(value, valueType)} $unit 
since the epoch"),
+      context = Array.empty,
+      summary = "")
+  }
+
   def timeAddIntervalOverflowError(
       time: Long,
       timePrecision: Int,
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 0d7a01fb2953..a9ee2a8ba476 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
@@ -1860,8 +1860,11 @@ class DateExpressionsSuite extends SparkFunSuite with 
ExpressionEvalHelper {
     // test integral input
     testIntegralInput(testIntegralFunc)
     // test overflow
-    checkExceptionInExpression[ArithmeticException](
-      SecondsToTimestamp(Literal(Long.MaxValue, LongType)), EmptyRow, "long 
overflow")
+    checkErrorInExpression[SparkArithmeticException](
+      SecondsToTimestamp(Literal(Long.MaxValue, LongType)),
+      condition = "DATETIME_OVERFLOW",
+      parameters = Map("operation" ->
+        "create a TIMESTAMP from 9223372036854775807L seconds since the 
epoch"))
 
     def testFractionalInput(input: String): Unit = {
       Seq(input.toFloat, input.toDouble, Decimal(input)).foreach { value =>
@@ -1877,9 +1880,12 @@ class DateExpressionsSuite extends SparkFunSuite with 
ExpressionEvalHelper {
     testFractionalInput("-1.234567")
 
     // test overflow for decimal input
-    checkExceptionInExpression[ArithmeticException](
-      SecondsToTimestamp(Literal(Decimal("9".repeat(38)))), "Overflow"
-    )
+    checkErrorInExpression[SparkArithmeticException](
+      SecondsToTimestamp(Literal(Decimal("9".repeat(38)))),
+      condition = "DATETIME_OVERFLOW",
+      parameters = Map("operation" -> (
+        "create a TIMESTAMP from 99999999999999999999999999999999999999BD " +
+          "seconds since the epoch")))
     // test truncation error for decimal input
     checkExceptionInExpression[ArithmeticException](
       SecondsToTimestamp(Literal(Decimal("0.1234567"))), "Rounding necessary"
@@ -1914,8 +1920,11 @@ class DateExpressionsSuite extends SparkFunSuite with 
ExpressionEvalHelper {
     // test integral input
     testIntegralInput(testIntegralFunc)
     // test overflow
-    checkExceptionInExpression[ArithmeticException](
-      MillisToTimestamp(Literal(Long.MaxValue, LongType)), EmptyRow, "long 
overflow")
+    checkErrorInExpression[SparkArithmeticException](
+      MillisToTimestamp(Literal(Long.MaxValue, LongType)),
+      condition = "DATETIME_OVERFLOW",
+      parameters = Map("operation" ->
+        "create a TIMESTAMP from 9223372036854775807L milliseconds since the 
epoch"))
   }
 
   test("TIMESTAMP_MICROS") {
diff --git 
a/sql/core/src/test/resources/sql-tests/results/datetime-legacy.sql.out 
b/sql/core/src/test/resources/sql-tests/results/datetime-legacy.sql.out
index 7705d2b4d3d7..fc9813c59350 100644
--- a/sql/core/src/test/resources/sql-tests/results/datetime-legacy.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/datetime-legacy.sql.out
@@ -1808,8 +1808,14 @@ select TIMESTAMP_SECONDS(1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 1230219000123123L seconds since the 
epoch"
+  }
+}
 
 
 -- !query
@@ -1817,8 +1823,14 @@ select TIMESTAMP_SECONDS(-1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -1230219000123123L seconds since 
the epoch"
+  }
+}
 
 
 -- !query
@@ -1826,8 +1838,14 @@ select TIMESTAMP_MILLIS(92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
@@ -1835,8 +1853,14 @@ select TIMESTAMP_MILLIS(-92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
diff --git 
a/sql/core/src/test/resources/sql-tests/results/nonansi/timestamp.sql.out 
b/sql/core/src/test/resources/sql-tests/results/nonansi/timestamp.sql.out
index 191090f736fd..4d7786512e55 100644
--- a/sql/core/src/test/resources/sql-tests/results/nonansi/timestamp.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/nonansi/timestamp.sql.out
@@ -589,8 +589,14 @@ select TIMESTAMP_SECONDS(1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 1230219000123123L seconds since the 
epoch"
+  }
+}
 
 
 -- !query
@@ -598,8 +604,14 @@ select TIMESTAMP_SECONDS(-1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -1230219000123123L seconds since 
the epoch"
+  }
+}
 
 
 -- !query
@@ -607,8 +619,14 @@ select TIMESTAMP_MILLIS(92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
@@ -616,8 +634,14 @@ select TIMESTAMP_MILLIS(-92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
diff --git a/sql/core/src/test/resources/sql-tests/results/timestamp.sql.out 
b/sql/core/src/test/resources/sql-tests/results/timestamp.sql.out
index 9a4d9bc4391d..9f99af68b390 100644
--- a/sql/core/src/test/resources/sql-tests/results/timestamp.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/timestamp.sql.out
@@ -617,8 +617,14 @@ select TIMESTAMP_SECONDS(1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 1230219000123123L seconds since the 
epoch"
+  }
+}
 
 
 -- !query
@@ -626,8 +632,14 @@ select TIMESTAMP_SECONDS(-1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -1230219000123123L seconds since 
the epoch"
+  }
+}
 
 
 -- !query
@@ -635,8 +647,14 @@ select TIMESTAMP_MILLIS(92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
@@ -644,8 +662,14 @@ select TIMESTAMP_MILLIS(-92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
diff --git 
a/sql/core/src/test/resources/sql-tests/results/timestampNTZ/timestamp-ansi.sql.out
 
b/sql/core/src/test/resources/sql-tests/results/timestampNTZ/timestamp-ansi.sql.out
index 76552bb5b61f..f04353680b23 100644
--- 
a/sql/core/src/test/resources/sql-tests/results/timestampNTZ/timestamp-ansi.sql.out
+++ 
b/sql/core/src/test/resources/sql-tests/results/timestampNTZ/timestamp-ansi.sql.out
@@ -617,8 +617,14 @@ select TIMESTAMP_SECONDS(1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 1230219000123123L seconds since the 
epoch"
+  }
+}
 
 
 -- !query
@@ -626,8 +632,14 @@ select TIMESTAMP_SECONDS(-1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -1230219000123123L seconds since 
the epoch"
+  }
+}
 
 
 -- !query
@@ -635,8 +647,14 @@ select TIMESTAMP_MILLIS(92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
@@ -644,8 +662,14 @@ select TIMESTAMP_MILLIS(-92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
diff --git 
a/sql/core/src/test/resources/sql-tests/results/timestampNTZ/timestamp.sql.out 
b/sql/core/src/test/resources/sql-tests/results/timestampNTZ/timestamp.sql.out
index 11325905521e..904cffe03b44 100644
--- 
a/sql/core/src/test/resources/sql-tests/results/timestampNTZ/timestamp.sql.out
+++ 
b/sql/core/src/test/resources/sql-tests/results/timestampNTZ/timestamp.sql.out
@@ -589,8 +589,14 @@ select TIMESTAMP_SECONDS(1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 1230219000123123L seconds since the 
epoch"
+  }
+}
 
 
 -- !query
@@ -598,8 +604,14 @@ select TIMESTAMP_SECONDS(-1230219000123123)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -1230219000123123L seconds since 
the epoch"
+  }
+}
 
 
 -- !query
@@ -607,8 +619,14 @@ select TIMESTAMP_MILLIS(92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from 92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
@@ -616,8 +634,14 @@ select TIMESTAMP_MILLIS(-92233720368547758)
 -- !query schema
 struct<>
 -- !query output
-java.lang.ArithmeticException
-long overflow
+org.apache.spark.SparkArithmeticException
+{
+  "errorClass" : "DATETIME_OVERFLOW",
+  "sqlState" : "22008",
+  "messageParameters" : {
+    "operation" : "create a TIMESTAMP from -92233720368547758L milliseconds 
since the epoch"
+  }
+}
 
 
 -- !query
diff --git 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryExecutionErrorsSuite.scala
 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryExecutionErrorsSuite.scala
index c5b6a2335035..7eccce3fe049 100644
--- 
a/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryExecutionErrorsSuite.scala
+++ 
b/sql/core/src/test/scala/org/apache/spark/sql/errors/QueryExecutionErrorsSuite.scala
@@ -420,6 +420,28 @@ class QueryExecutionErrorsSuite
       sqlState = "22008")
   }
 
+  test("DATETIME_OVERFLOW: timestamp constructors overflow") {
+    Seq(
+      (
+        s"timestamp_seconds(CAST('${Long.MaxValue}' AS BIGINT))",
+        s"create a TIMESTAMP from ${Long.MaxValue}L seconds since the epoch"),
+      (
+        s"timestamp_millis(CAST('${Long.MaxValue}' AS BIGINT))",
+        s"create a TIMESTAMP from ${Long.MaxValue}L milliseconds since the 
epoch"),
+      (
+        s"timestamp_seconds(CAST('${"9".repeat(38)}' AS DECIMAL(38, 0)))",
+        s"create a TIMESTAMP from ${"9".repeat(38)}BD seconds since the epoch")
+    ).foreach { case (expression, operation) =>
+      checkError(
+        exception = intercept[SparkArithmeticException] {
+          sql(s"select $expression").collect()
+        },
+        condition = "DATETIME_OVERFLOW",
+        parameters = Map("operation" -> operation),
+        sqlState = "22008")
+    }
+  }
+
   test("CANNOT_PARSE_DECIMAL: unparseable decimal") {
     val e1 = intercept[SparkException] {
       withTempPath { path =>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to