stevomitric commented on code in PR #56677:
URL: https://github.com/apache/spark/pull/56677#discussion_r3459995402


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala:
##########
@@ -158,6 +158,14 @@ object Cast extends QueryErrorsBase {
     case (_: TimeType, _: TimeType) => true
     case (_: TimeType, _: IntegralType) => true
 
+    // TIME(p) <-> TIMESTAMP_NTZ(q), q in [6, 9] (precision 6 is the micro 
TimestampNTZType,
+    // [7, 9] is TimestampNTZNanosType). Restricted to the NTZ family on 
purpose: TIMESTAMP_LTZ
+    // is not a valid counterpart for these casts.
+    case (_: TimeType, TimestampNTZType) => true

Review Comment:
   No canANSIStoreAssign arm - the pair falls through the (_: DatetimeType, _: 
DatetimeType) => true catch-all (:465), so TIME -> TIMESTAMP_NTZ becomes an 
implicit ANSI store assignment: INSERT INTO t(ts_ntz) SELECT time_col silently 
stamps CURRENT_DATE — the same injection the new UNION/CASE tests reject. Add 
four => false arms before the catch-all + a store-assign test?



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala:
##########
@@ -1932,6 +1995,10 @@ case class Cast(
       val zid = zoneIdValue(ctx)
       (c, evPrim, evNull) =>
         code"$evPrim = $dateTimeUtilsCls.convertTz($c.epochMicros, 
java.time.ZoneOffset.UTC, $zid);"
+    case _: TimeType =>
+      val zid = zoneIdValue(ctx)
+      (c, evPrim, evNull) =>
+        code"$evPrim = 
$dateTimeUtilsCls.makeTimestampNTZ($dateTimeUtilsCls.currentDate($zid), $c);"

Review Comment:
   Nit: per-row currentDate read; fine since it's only the eval fallback 
(ComputeCurrentTime rewrites it away), just not value-stable across midnight.



##########
sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/SparkConnectProtoSuite.scala:
##########
@@ -986,6 +986,23 @@ class SparkConnectProtoSuite extends PlanTest with 
SparkConnectPlanTest {
       sparkTestRelation.select(col("id").cast("string")))
   }
 
+  test("SPARK-57618: cast TIMESTAMP_NTZ to TIME") {

Review Comment:
   Nit: only covers TIMESTAMP_NTZ -> TIME; the TIME -> TIMESTAMP_NTZ direction 
is untested over Connect (TIME isn't in the DataType proto converter yet, as 
the comment notes).



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/optimizer/finishAnalysis.scala:
##########
@@ -119,8 +119,15 @@ object ComputeCurrentTime extends Rule[LogicalPlan] {
     val currentDates = collection.mutable.HashMap.empty[ZoneId, Literal]
     val localTimestamps = collection.mutable.HashMap.empty[ZoneId, Literal]
 
+    // The CAST bit is included so this rule can find TIME -> TIMESTAMP_NTZ 
casts (which depend on
+    // CURRENT_DATE) and stabilize them below. CAST is a broad pattern, so 
this widens the rule's
+    // traversal to most plans; the precise `Cast.isTimeToTimestampNTZ` guard 
keeps the rewrite
+    // scoped. We intentionally do not tag these casts with CURRENT_LIKE 
instead: inline-table
+    // validation treats CURRENT_LIKE as safe to defer, so tagging would let 
unrelated non-foldable
+    // NTZ-target casts (e.g. CAST(rand() AS TIMESTAMP_NTZ)) bypass that 
validation (see SPARK-57618
+    // and ResolveInlineTablesSuite).
     def transformCondition(treePatternbits: TreePatternBits): Boolean = {
-      treePatternbits.containsPattern(CURRENT_LIKE)
+      treePatternbits.containsPattern(CURRENT_LIKE) || 
treePatternbits.containsPattern(CAST)

Review Comment:
   Pruning on CAST makes this rule traverse nearly every plan with a cast. 
Worth a dedicated narrow pattern (TIME_TO_TIMESTAMP_NTZ_CAST tagged on Cast) to 
keep traversal selective.



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