sunchao commented on code in PR #57088:
URL: https://github.com/apache/spark/pull/57088#discussion_r3540463537


##########
sql/core/src/test/scala/org/apache/spark/sql/execution/arrow/ArrowWriterSuite.scala:
##########
@@ -323,6 +323,118 @@ class ArrowWriterSuite extends SparkFunSuite {
     }
   }
 
+  test("calendar interval overflow raises DATETIME_OVERFLOW at the conversion 
site") {
+    // The default IntervalMonthDayNano mapping multiplies microseconds by 
1000 into Arrow's
+    // int64 nanosecond field. The overflow must surface as the structured 
DATETIME_OVERFLOW
+    // (not a raw ArithmeticException), and the translation must be scoped to 
the conversion:
+    // an unrelated (Spark)ArithmeticException raised by upstream evaluation 
must pass through
+    // unchanged, which the writer guarantees by catching only around 
Math.multiplyExact.

Review Comment:
   [P3] Could we add the regression case for the upstream-exception half of 
this invariant? This test currently checks only the `Math.multiplyExact` 
overflow. If a future refactor widened the `try` to include 
`input.getInterval`, an upstream `DIVIDE_BY_ZERO` could be relabeled as 
`DATETIME_OVERFLOW` while this test stayed green. A custom `InternalRow` whose 
`getInterval` throws a `SparkArithmeticException`, followed by an assertion 
that the original exception escapes unchanged, would pin the behavior.



##########
sql/api/src/main/scala/org/apache/spark/sql/util/ArrowUtils.scala:
##########
@@ -437,6 +478,23 @@ private[sql] object ArrowUtils {
     }
   }
 
+  /**
+   * Whether the Arrow struct field is the lossless representation of a 
CalendarInterval built by
+   * `toArrowField` with `losslessInternalTypes = true`. Also callable from 
Java
+   * (ArrowColumnVector) to select the interval accessor for such structs.
+   */
+  def isCalendarIntervalStructField(field: Field): Boolean = {
+    field.getType.isInstanceOf[ArrowType.Struct] &&
+    field.getChildren.asScala
+      .map(_.getName)
+      .asJava
+      .containsAll(Seq("months", "days", "microseconds").asJava) &&
+    field.getChildren.asScala.exists { child =>
+      child.getName == "months" &&
+      child.getMetadata.getOrDefault(calendarIntervalStructKey, "false") == 
"true"

Review Comment:
   [P3] Could this recognize only the exact canonical shape: exactly three 
children in `(months, days, microseconds)` order with `int32`, `int32`, and 
`int64` types and the expected nullability? A tagged reordered schema such as 
`(days, months, microseconds)` passes this predicate today. 
`CalendarIntervalStructWriter` writes children positionally while 
`ArrowColumnVector` reads them by name, so that shape silently swaps months and 
days. The current producer is canonical; this is defensive hardening for 
corrupt or future-evolved tagged schemas.



-- 
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]

Reply via email to