@@ -19,39 +19,15 @@ package org.apache.spark.sql.catalyst.analysis
19
19
20
20
import scala .annotation .tailrec
21
21
import scala .collection .mutable
22
-
23
- import org .apache .spark .sql .catalyst .expressions .{
24
- Alias ,
25
- CaseWhen ,
26
- Cast ,
27
- Concat ,
28
- Elt ,
29
- Expression ,
30
- MapZipWith ,
31
- Stack ,
32
- WindowSpecDefinition
33
- }
34
- import org .apache .spark .sql .catalyst .plans .logical .{
35
- AddColumns ,
36
- AlterColumns ,
37
- Call ,
38
- CreateTable ,
39
- Except ,
40
- Intersect ,
41
- LogicalPlan ,
42
- Project ,
43
- ReplaceTable ,
44
- Union ,
45
- UnionLoop ,
46
- Unpivot
47
- }
22
+ import org .apache .spark .sql .catalyst .expressions .{Alias , CaseWhen , Cast , Concat , CurrentDate , Elt , Expression , MakeTimestampNTZ , MapZipWith , Stack , WindowSpecDefinition }
23
+ import org .apache .spark .sql .catalyst .plans .logical .{AddColumns , AlterColumns , Call , CreateTable , Except , Intersect , LogicalPlan , Project , ReplaceTable , Union , UnionLoop , Unpivot }
48
24
import org .apache .spark .sql .catalyst .rules .Rule
49
25
import org .apache .spark .sql .catalyst .trees .CurrentOrigin .withOrigin
50
26
import org .apache .spark .sql .catalyst .util .ResolveDefaultColumns
51
27
import org .apache .spark .sql .connector .catalog .CatalogV2Implicits .MultipartIdentifierHelper
52
28
import org .apache .spark .sql .connector .catalog .procedures .BoundProcedure
53
29
import org .apache .spark .sql .errors .DataTypeErrors .cannotMergeIncompatibleDataTypesError
54
- import org .apache .spark .sql .types .DataType
30
+ import org .apache .spark .sql .types .{ DataType , TimeType , TimestampNTZType }
55
31
56
32
abstract class TypeCoercionBase extends TypeCoercionHelper {
57
33
@@ -480,4 +456,35 @@ abstract class TypeCoercionBase extends TypeCoercionHelper {
480
456
case withChildrenResolved => StringLiteralTypeCoercion (withChildrenResolved)
481
457
}
482
458
}
459
+
460
+ /**
461
+ * Rewrites a cast from [[TimeType ]] to [[TimestampNTZType ]] into a [[MakeTimestampNTZ ]]
462
+ * expression.
463
+ *
464
+ * The conversion from TIME to TIMESTAMP_NTZ requires a date component, which TIME itself does
465
+ * not provide. This rule injects [[CurrentDate ]] as the implicit date part, effectively
466
+ * treating the TIME value as a time of day on the current date. This rewrite ensures that all
467
+ * such casts within a query use a consistent date, as required by the [[ComputeCurrentTime ]]
468
+ * rule which replaces [[CurrentDate ]] with a fixed value during analysis.
469
+ *
470
+ * For example, the following SQL:
471
+ * {{{
472
+ * SELECT CAST(make_time(12, 30, 0) AS TIMESTAMP_NTZ)
473
+ * }}}
474
+ * will be rewritten to:
475
+ * {{{
476
+ * SELECT make_timestamp_ntz(current_date, make_time(12, 30, 0))
477
+ * }}}
478
+ */
479
+ object RewriteTimeCastToTimestampNTZ extends TypeCoercionRule {
480
+ override def transform : PartialFunction [Expression , Expression ] = {
481
+ case c @ Cast (child, TimestampNTZType , _, _) if child.resolved =>
482
+ child.dataType match {
483
+ case _ : TimeType =>
484
+ // Convert TIME -> TIMESTAMP_NTZ using MakeTimestampNTZ(CurrentDate(), time)
485
+ MakeTimestampNTZ (CurrentDate (), child)
486
+ case _ => c
487
+ }
488
+ }
489
+ }
483
490
}
0 commit comments