uros-b commented on code in PR #56638:
URL: https://github.com/apache/spark/pull/56638#discussion_r3448553914


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercionHelper.scala:
##########
@@ -244,14 +247,54 @@ abstract class TypeCoercionHelper {
     (d1, d2) match {
       case (_, _: TimeType) => None
       case (_: TimeType, _) => None
-      case (_: TimestampType, _: DateType) | (_: DateType, _: TimestampType) =>
-        Some(TimestampType)
 
-      case (_: TimestampType, _: TimestampNTZType) | (_: TimestampNTZType, _: 
TimestampType) =>
-        Some(TimestampType)
-
-      case (_: TimestampNTZType, _: DateType) | (_: DateType, _: 
TimestampNTZType) =>
-        Some(TimestampNTZType)
+      // The remaining datetime types (DATE and the micro/nanos TIMESTAMP_LTZ 
/ TIMESTAMP_NTZ
+      // families) widen along two independent axes:
+      //   - time-zone family: the result is LTZ if either input is 
LTZ-family, otherwise NTZ. This
+      //     mirrors the microsecond precedent where TIMESTAMP + TIMESTAMP_NTZ 
widens to TIMESTAMP.
+      //     DATE is family-neutral and adopts the family of the other side.
+      //   - precision: the maximum of the two precisions, where the micro 
types and DATE count as 6
+      //     and the nanos types contribute their own precision p in [7, 9].
+      // The (family, precision) pair then maps back to a concrete type: 
precision 6 yields the
+      // micro type, precision in [7, 9] yields the nanos type.
+      //
+      // Note: this common-type resolution is intentionally more permissive 
than the nanosecond
+      // conversion rules in Cast.canUpCast / Cast.canANSIStoreAssign, which 
keep cross-family and
+      // DATE <-> nanos casts explicit-CAST-only while the nanos types are 
unreleased (SPARK-57323
+      // etc.). Coercion here mirrors the microsecond precedent so that UNION 
/ CASE / coalesce /
+      // IN / comparison resolve a common type the same way they do for the 
micro families; the
+      // stricter explicit-only stance is deliberately scoped to up-cast and 
store assignment, not
+      // to common-type resolution.
+      case _ =>
+        def isLtz(d: DatetimeType): Boolean =
+          d.isInstanceOf[TimestampType] || 
d.isInstanceOf[TimestampLTZNanosType]
+        def isNtz(d: DatetimeType): Boolean =
+          d.isInstanceOf[TimestampNTZType] || 
d.isInstanceOf[TimestampNTZNanosType]
+        def precisionOf(d: DatetimeType): Int = d match {
+          case t: TimestampLTZNanosType => t.precision
+          case t: TimestampNTZNanosType => t.precision
+          case _ => 6 // DateType / TimestampType / TimestampNTZType
+        }
+        // Beyond TimeType (handled above), the only datetime types are DATE 
and the micro/nanos
+        // timestamp families. Guard so that a future DatetimeType subtype 
fails fast here instead
+        // of being silently mis-widened (treated as a family-neutral 
precision-6 type and folded
+        // into DATE) when it should be wired in explicitly.
+        def isWidenable(d: DatetimeType): Boolean =
+          isLtz(d) || isNtz(d) || d.isInstanceOf[DateType]
+        if (!isWidenable(d1) || !isWidenable(d2)) {
+          throw SparkException.internalError(
+            s"Unexpected datetime types in findWiderDateTimeType: $d1, $d2")
+        } else if (!isLtz(d1) && !isNtz(d1) && !isLtz(d2) && !isNtz(d2)) {
+          // Both sides are DATE; callers short-circuit equal types, so this 
is just defensive.
+          Some(DateType)

Review Comment:
   Just to confirm - this is unreachable via current callers?



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