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

uros-b 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 ccffd010bb52 [SPARK-57256][SQL] Cast nanosecond-precision timestamps 
to string
ccffd010bb52 is described below

commit ccffd010bb52ec5a1e9d54506bd854522da0234f
Author: Maxim Gekk <[email protected]>
AuthorDate: Sat Jun 6 06:06:24 2026 +0200

    [SPARK-57256][SQL] Cast nanosecond-precision timestamps to string
    
    ### What changes were proposed in this pull request?
    Implement casting of the nanosecond-precision timestamp types 
`TIMESTAMP_NTZ(p)` (`TimestampNTZNanosType`) and `TIMESTAMP_LTZ(p)` 
(`TimestampLTZNanosType`), `p` in [7, 9], to `STRING`.
    
    Casting is implemented in `ToStringBase` (mixed into `Cast`), so this 
change also fixes `ToPrettyString` (and therefore `Dataset.show()`) for these 
types via the shared base.
    
    The change wires the 
[SPARK-57162](https://issues.apache.org/jira/browse/SPARK-57162) formatter 
methods into the existing cast-to-string paths (interpreted and codegen):
    - `TimestampLTZNanosType(p)` -> `TimestampFormatter.formatNanos(v, p)` 
(renders in the session time zone).
    - `TimestampNTZNanosType(p)` -> 
`TimestampFormatter.formatWithoutTimeZoneNanos(v, p)` (zone-independent, UTC 
wall-clock grid).
    
    The fractional-second precision `p` is taken from the source type; sub-`p` 
digits are floored and trailing zeros are trimmed, consistent with the 
microsecond cast path (both use `FractionTimestampFormatter`).
    
    `Cast.needsTimeZone` is extended so that `TimestampLTZNanosType -> 
StringType` resolves the session time zone (mirroring `TimestampType -> 
StringType`); the NTZ variant does not need a time zone.
    
    ### Why are the changes needed?
    Today `Cast` permits these casts at analysis time (the generic `(_, 
StringType)` rule), but at runtime the nanosecond types have no dedicated case 
in `ToStringBase` and fall through to the default `String.valueOf(...)` branch, 
producing the internal form `TimestampNanosVal(epochMicros, nanosWithinMicro)` 
instead of a proper SQL timestamp string. Producing a correct textual 
representation is a prerequisite for nanosecond support in expressions, 
SHOW/pretty output, and downstream text-b [...]
    
    ### Does this PR introduce _any_ user-facing change?
    User-facing only when `spark.sql.timestampNanosTypes.enabled=true`; these 
types are not available otherwise. Casting to string never fails, so ANSI and 
non-ANSI modes behave identically.
    
    With `spark.sql.timestampNanosTypes.enabled=true`:
    ```sql
    SELECT CAST(ts AS STRING);
    -- TIMESTAMP_NTZ(9) value 2020-01-01 00:00:00.123456789
    --   before: TimestampNanosVal(1577836800000000, 789)
    --   after:  2020-01-01 00:00:00.123456789
    ```
    
    ### How was this patch tested?
    New cases in `CastSuiteBase` (run under both ANSI on/off; `checkEvaluation` 
exercises the interpreted and codegen paths): precision 7/8/9, trailing-zero 
trimming, `nanosWithinMicro` 0 and 999, LTZ time-zone shift under a non-UTC 
session zone vs. NTZ remaining unshifted, pre-epoch and year-9999 boundaries, 
and null input.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    Generated-by: Cursor
    
    Closes #56317 from MaxGekk/cast-nanos-to-string.
    
    Authored-by: Maxim Gekk <[email protected]>
    Signed-off-by: Uros Bojanic <[email protected]>
---
 .../sql/types/ops/TimestampNanosTypeApiOps.scala   |  18 +--
 .../spark/sql/catalyst/expressions/Cast.scala      |   3 +-
 .../sql/catalyst/expressions/ToStringBase.scala    |  42 ++++---
 .../sql/catalyst/expressions/CastSuiteBase.scala   | 127 ++++++++++++++++++++-
 .../expressions/TimestampNanosRowSuite.scala       |  17 +--
 .../catalyst/expressions/ToPrettyStringSuite.scala |  24 +++-
 .../sql-tests/analyzer-results/cast.sql.out        | 105 +++++++++++++++++
 .../analyzer-results/nonansi/cast.sql.out          | 105 +++++++++++++++++
 .../src/test/resources/sql-tests/inputs/cast.sql   |  31 ++++-
 .../test/resources/sql-tests/results/cast.sql.out  | 120 +++++++++++++++++++
 .../sql-tests/results/nonansi/cast.sql.out         | 120 +++++++++++++++++++
 11 files changed, 668 insertions(+), 44 deletions(-)

diff --git 
a/sql/api/src/main/scala/org/apache/spark/sql/types/ops/TimestampNanosTypeApiOps.scala
 
b/sql/api/src/main/scala/org/apache/spark/sql/types/ops/TimestampNanosTypeApiOps.scala
index aa3d52f750ef..ee6125c8f1af 100644
--- 
a/sql/api/src/main/scala/org/apache/spark/sql/types/ops/TimestampNanosTypeApiOps.scala
+++ 
b/sql/api/src/main/scala/org/apache/spark/sql/types/ops/TimestampNanosTypeApiOps.scala
@@ -31,11 +31,10 @@ import org.apache.spark.sql.types.{TimestampLTZNanosType, 
TimestampNTZNanosType}
  * prefix; storage and formatting are identical.
  *
  * SCOPE (SPARK-57207): this issue wires physical representation, literals, 
row accessors, and
- * codegen class selection. Dedicated fractional-second string formatting is 
not implemented yet:
- * there is no TimestampFormatter for the nanos timestamp types. Until one 
lands, format() (and
- * the toSQLValue() that delegates to it) raises the user-facing
- * UNSUPPORTED_FEATURE.TIMESTAMP_NANOS_TO_STRING error rather than silently 
truncating to
- * microsecond precision.
+ * codegen class selection. CAST to STRING is implemented separately, 
zone-aware, in ToStringBase
+ * (SPARK-57256). The zone-less, type-level format() here (and the 
toSQLValue() that delegates to
+ * it) still raises the user-facing 
UNSUPPORTED_FEATURE.TIMESTAMP_NANOS_TO_STRING error, since LTZ
+ * rendering needs the session time zone that this op does not have.
  *
  * Dataset encoders are wired here to the precision-aware leaves added by 
SPARK-57033
  * (LocalDateTimeNanosEncoder / InstantNanosEncoder), so that turning on the 
Types Framework
@@ -50,10 +49,11 @@ abstract class TimestampNanosTypeApiOps extends TypeApiOps 
with DataTypeErrorsBa
 
   // ==================== String Formatting ====================
 
-  // Fractional-second (nanosecond) string formatting is not implemented yet: 
there is no
-  // TimestampFormatter for the nanos timestamp types. Until one lands, 
formatting (CAST to STRING,
-  // EXPLAIN / SHOW output, and SQL-literal rendering via toSQLValue) raises a 
user-facing
-  // unsupported-feature error rather than silently truncating to microsecond 
precision.
+  // CAST to STRING for the nanosecond timestamp types is handled zone-aware 
by ToStringBase
+  // (SPARK-57256), alongside the microsecond timestamp types, because LTZ 
rendering depends on the
+  // session time zone that this zone-less, type-level formatter does not 
have. The remaining
+  // zone-less callers (EXPLAIN plan output and SQL-literal rendering via 
toSQLValue) still raise a
+  // user-facing unsupported-feature error here rather than silently 
truncating to microseconds.
   override def format(v: Any): String =
     throw DataTypeErrors.cannotConvertNanosTimestampToStringError(dataType)
 
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala
index a1935c739643..4a57ac4eeeed 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala
@@ -342,8 +342,9 @@ object Cast extends QueryErrorsBase {
     case (TimestampType, TimestampNTZType) => true
     case (TimestampNTZType, TimestampType) => true
     // NTZ string is zone-independent (mirroring micro TIMESTAMP_NTZ, which is 
not listed); only
-    // the LTZ string parse depends on the session time zone.
+    // the LTZ string parse/render depends on the session time zone.
     case (_: StringType, _: TimestampLTZNanosType) => true
+    case (_: TimestampLTZNanosType, _: StringType) => true
     case (ArrayType(fromType, _), ArrayType(toType, _)) => 
needsTimeZone(fromType, toType)
     case (MapType(fromKey, fromValue, _), MapType(toKey, toValue, _)) =>
       needsTimeZone(fromKey, toKey) || needsTimeZone(fromValue, toValue)
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/ToStringBase.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/ToStringBase.scala
index 1f157d6ac18a..561fd33b0a18 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/ToStringBase.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/ToStringBase.scala
@@ -24,13 +24,12 @@ import org.apache.spark.sql.catalyst.expressions.codegen._
 import org.apache.spark.sql.catalyst.expressions.codegen.Block._
 import org.apache.spark.sql.catalyst.util.{ArrayData, CharVarcharCodegenUtils, 
DateFormatter, FractionTimeFormatter, IntervalStringStyles, IntervalUtils, 
MapData, TimestampFormatter}
 import org.apache.spark.sql.catalyst.util.IntervalStringStyles.ANSI_STYLE
-import org.apache.spark.sql.errors.DataTypeErrors
 import org.apache.spark.sql.internal.SQLConf
 import org.apache.spark.sql.internal.SQLConf.BinaryOutputStyle
 import org.apache.spark.sql.types._
 import org.apache.spark.sql.types.ops.TypeApiOps
 import org.apache.spark.unsafe.UTF8StringBuilder
-import org.apache.spark.unsafe.types.{CalendarInterval, UTF8String}
+import org.apache.spark.unsafe.types.{CalendarInterval, TimestampNanosVal, 
UTF8String}
 import org.apache.spark.util.ArrayImplicits._
 import org.apache.spark.util.SparkStringUtils
 
@@ -67,10 +66,16 @@ trait ToStringBase { self: UnaryExpression with 
TimeZoneAwareExpression =>
       case NoConstraint => castToString(from)
     }
 
-  private def castToString(from: DataType): Any => UTF8String =
-    TypeApiOps(from)
-      .map(ops => acceptAny[Any](v => ops.formatUTF8(v)))
-      .getOrElse(castToStringDefault(from))
+  private def castToString(from: DataType): Any => UTF8String = from match {
+    // Nanosecond timestamp string formatting is zone-aware (LTZ renders in 
the session time zone),
+    // so it lives in castToStringDefault alongside the microsecond timestamp 
types rather than the
+    // zone-less Types Framework formatter (SPARK-57256).
+    case _: TimestampNTZNanosType | _: TimestampLTZNanosType => 
castToStringDefault(from)
+    case _ =>
+      TypeApiOps(from)
+        .map(ops => acceptAny[Any](v => ops.formatUTF8(v)))
+        .getOrElse(castToStringDefault(from))
+  }
 
   private def castToStringDefault(from: DataType): Any => UTF8String = from 
match {
     case CalendarIntervalType =>
@@ -82,6 +87,12 @@ trait ToStringBase { self: UnaryExpression with 
TimeZoneAwareExpression =>
       acceptAny[Long](t => UTF8String.fromString(timestampFormatter.format(t)))
     case TimestampNTZType =>
       acceptAny[Long](t => 
UTF8String.fromString(timestampNTZFormatter.format(t)))
+    case t: TimestampLTZNanosType =>
+      acceptAny[TimestampNanosVal](v =>
+        UTF8String.fromString(timestampFormatter.formatNanos(v, t.precision)))
+    case t: TimestampNTZNanosType =>
+      acceptAny[TimestampNanosVal](v =>
+        
UTF8String.fromString(timestampNTZFormatter.formatWithoutTimeZoneNanos(v, 
t.precision)))
     case _: TimeType =>
       acceptAny[Long](t => UTF8String.fromString(timeFormatter.format(t)))
     case ArrayType(et, _) =>
@@ -235,6 +246,18 @@ trait ToStringBase { self: UnaryExpression with 
TimeZoneAwareExpression =>
           ctx.addReferenceObj("timestampNTZFormatter", timestampNTZFormatter),
           timestampNTZFormatter.getClass)
         (c, evPrim) => code"$evPrim = UTF8String.fromString($tf.format($c));"
+      case t: TimestampLTZNanosType =>
+        val tf = JavaCode.global(
+          ctx.addReferenceObj("timestampFormatter", timestampFormatter),
+          timestampFormatter.getClass)
+        (c, evPrim) =>
+          code"$evPrim = UTF8String.fromString($tf.formatNanos($c, 
${t.precision}));"
+      case t: TimestampNTZNanosType =>
+        val tf = JavaCode.global(
+          ctx.addReferenceObj("timestampNTZFormatter", timestampNTZFormatter),
+          timestampNTZFormatter.getClass)
+        (c, evPrim) =>
+          code"$evPrim = 
UTF8String.fromString($tf.formatWithoutTimeZoneNanos($c, ${t.precision}));"
       case _: TimeType =>
         val tf = JavaCode.global(
           ctx.addReferenceObj("timeFormatter", timeFormatter),
@@ -306,13 +329,6 @@ trait ToStringBase { self: UnaryExpression with 
TimeZoneAwareExpression =>
         (c, evPrim) => code"$evPrim = 
UTF8String.fromString($c.toPlainString());"
       case _: StringType =>
         (c, evPrim) => code"$evPrim = $c;"
-      // Fractional-second (nanosecond) timestamp formatting is not 
implemented yet: there is no
-      // TimestampFormatter for the nanos timestamp types. The interpreted 
path raises this via the
-      // Types Framework (castToString -> TypeApiOps.format); the codegen path 
has no framework
-      // hook, so it raises the same user-facing error directly until a 
formatter lands
-      // (SPARK-57207).
-      case _: TimestampNTZNanosType | _: TimestampLTZNanosType =>
-        throw DataTypeErrors.cannotConvertNanosTimestampToStringError(from)
       case _ =>
         (c, evPrim) => code"$evPrim = 
UTF8String.fromString(String.valueOf($c));"
     }
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuiteBase.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuiteBase.scala
index b33045ad90a8..5c346a980d58 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuiteBase.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuiteBase.scala
@@ -83,7 +83,12 @@ abstract class CastSuiteBase extends SparkFunSuite with 
ExpressionEvalHelper {
     }
 
     atomicTypes.foreach(dt => checkNullCast(NullType, dt))
-    (atomicTypes ++ timeTypes).foreach(dt => checkNullCast(dt, StringType))
+    val timestampNanosTypes = Seq(
+      TimestampLTZNanosType(TimestampLTZNanosType.MIN_PRECISION),
+      TimestampLTZNanosType(TimestampLTZNanosType.MAX_PRECISION),
+      TimestampNTZNanosType(TimestampNTZNanosType.MIN_PRECISION),
+      TimestampNTZNanosType(TimestampNTZNanosType.MAX_PRECISION))
+    (atomicTypes ++ timeTypes ++ timestampNanosTypes).foreach(dt => 
checkNullCast(dt, StringType))
     checkNullCast(StringType, BinaryType)
     checkNullCast(StringType, BooleanType)
     numericTypes.foreach(dt => checkNullCast(dt, BooleanType))
@@ -1070,6 +1075,126 @@ abstract class CastSuiteBase extends SparkFunSuite with 
ExpressionEvalHelper {
     }
   }
 
+  test("SPARK-57256: cast timestamp_ntz with nanosecond precision to string") {
+    // NTZ rendering uses the UTC wall-clock grid and is independent of the 
session time zone.
+    def ntz(ldt: LocalDateTime, precision: Int, zoneId: Option[String]): Cast =
+      cast(Literal.create(localDateTimeToNanosVal(ldt), 
TimestampNTZNanosType(precision)),
+        StringType, zoneId)
+
+    outstandingZoneIds.foreach { zid =>
+      val tz = Option(zid.getId)
+      val ldt = LocalDateTime.of(2020, 1, 1, 0, 0, 0, 123456789)
+      // Sub-precision digits are floored, then trailing zeros are trimmed.
+      checkEvaluation(ntz(ldt, 9, tz), "2020-01-01 00:00:00.123456789")
+      checkEvaluation(ntz(ldt, 8, tz), "2020-01-01 00:00:00.12345678")
+      checkEvaluation(ntz(ldt, 7, tz), "2020-01-01 00:00:00.1234567")
+
+      // nanosWithinMicro boundaries 0 and 999.
+      checkEvaluation(
+        ntz(LocalDateTime.of(2020, 1, 1, 0, 0, 0, 123456000), 9, tz),
+        "2020-01-01 00:00:00.123456")
+      checkEvaluation(
+        ntz(LocalDateTime.of(2020, 1, 1, 0, 0, 0, 123456999), 9, tz),
+        "2020-01-01 00:00:00.123456999")
+
+      // An all-zero fraction trims to no fractional part at all.
+      checkEvaluation(ntz(LocalDateTime.of(2020, 1, 1, 0, 0, 0, 0), 9, tz),
+        "2020-01-01 00:00:00")
+
+      // Pre-epoch and year-9999 boundaries.
+      checkEvaluation(
+        ntz(LocalDateTime.of(1969, 12, 31, 23, 59, 59, 123456789), 9, tz),
+        "1969-12-31 23:59:59.123456789")
+      checkEvaluation(
+        ntz(LocalDateTime.of(9999, 12, 31, 23, 59, 59, 999999999), 9, tz),
+        "9999-12-31 23:59:59.999999999")
+
+      // Null input.
+      checkEvaluation(
+        cast(Literal.create(null, TimestampNTZNanosType(9)), StringType, tz), 
null)
+    }
+  }
+
+  test("SPARK-57256: cast timestamp_ltz with nanosecond precision to string") {
+    // The physical value is an epoch instant (built here from a UTC wall 
clock); the string is
+    // rendered in the session time zone.
+    def ltz(ldt: LocalDateTime, precision: Int, zoneId: String): Cast =
+      cast(Literal.create(localDateTimeToNanosVal(ldt), 
TimestampLTZNanosType(precision)),
+        StringType, Option(zoneId))
+
+    val ldt = LocalDateTime.of(2020, 1, 1, 0, 0, 0, 123456789)
+    // UTC session zone: the wall clock matches the UTC instant. Sub-precision 
digits are floored
+    // and trailing zeros trimmed.
+    checkEvaluation(ltz(ldt, 9, "UTC"), "2020-01-01 00:00:00.123456789")
+    checkEvaluation(ltz(ldt, 8, "UTC"), "2020-01-01 00:00:00.12345678")
+    checkEvaluation(ltz(ldt, 7, "UTC"), "2020-01-01 00:00:00.1234567")
+
+    // A non-UTC session zone shifts the wall clock; the fractional second is 
unaffected.
+    checkEvaluation(ltz(ldt, 9, "America/Los_Angeles"), "2019-12-31 
16:00:00.123456789")
+    checkEvaluation(ltz(ldt, 9, "Asia/Kolkata"), "2020-01-01 
05:30:00.123456789")
+
+    // DST spring-forward boundary in America/Los_Angeles: 2020-03-08 02:00 
PST -> 03:00 PDT.
+    // The UTC instant 10:00:00 lands at 03:00:00 PDT (UTC-7); fractional part 
is unaffected.
+    checkEvaluation(
+      ltz(LocalDateTime.of(2020, 3, 8, 10, 0, 0, 123456789), 9, 
"America/Los_Angeles"),
+      "2020-03-08 03:00:00.123456789")
+
+    // nanosWithinMicro boundaries 0 and 999 (under UTC).
+    checkEvaluation(
+      ltz(LocalDateTime.of(2020, 1, 1, 0, 0, 0, 123456000), 9, "UTC"),
+      "2020-01-01 00:00:00.123456")
+    checkEvaluation(
+      ltz(LocalDateTime.of(2020, 1, 1, 0, 0, 0, 123456999), 9, "UTC"),
+      "2020-01-01 00:00:00.123456999")
+
+    // An all-zero fraction trims to no fractional part at all.
+    checkEvaluation(ltz(LocalDateTime.of(2020, 1, 1, 0, 0, 0, 0), 9, "UTC"),
+      "2020-01-01 00:00:00")
+
+    // Pre-epoch and year-9999 boundaries (under UTC).
+    checkEvaluation(
+      ltz(LocalDateTime.of(1969, 12, 31, 23, 59, 59, 123456789), 9, "UTC"),
+      "1969-12-31 23:59:59.123456789")
+    checkEvaluation(
+      ltz(LocalDateTime.of(9999, 12, 31, 23, 59, 59, 999999999), 9, "UTC"),
+      "9999-12-31 23:59:59.999999999")
+
+    // Null input.
+    checkEvaluation(
+      cast(Literal.create(null, TimestampLTZNanosType(9)), StringType, 
UTC_OPT), null)
+  }
+
+  test("SPARK-57256: cast complex types with nanosecond timestamps to string") 
{
+    val ntzElem = Literal.create(
+      localDateTimeToNanosVal(LocalDateTime.of(2020, 1, 1, 0, 0, 0, 
123456789)),
+      TimestampNTZNanosType(9))
+    val ltzElem = Literal.create(
+      localDateTimeToNanosVal(LocalDateTime.of(2020, 1, 1, 0, 0, 0, 
123456789)),
+      TimestampLTZNanosType(9))
+
+    // array<timestamp_ntz_nanos> with a null element exercises the recursive 
element path
+    // (including nullString) in ToStringBase. NTZ is independent of the 
session time zone.
+    checkEvaluation(
+      cast(CreateArray(Seq(ntzElem, Literal.create(null, 
TimestampNTZNanosType(9)))), StringType),
+      "[2020-01-01 00:00:00.123456789, null]")
+
+    // array<timestamp_ltz_nanos> is rendered in the session time zone (here 
UTC).
+    checkEvaluation(
+      cast(
+        CreateArray(Seq(ltzElem, Literal.create(null, 
TimestampLTZNanosType(9)))),
+        StringType,
+        UTC_OPT),
+      "[2020-01-01 00:00:00.123456789, null]")
+
+    // A struct nesting both nanosecond timestamp variants.
+    checkEvaluation(
+      cast(
+        CreateNamedStruct(Seq(Literal("ntz"), ntzElem, Literal("ltz"), 
ltzElem)),
+        StringType,
+        UTC_OPT),
+      "{2020-01-01 00:00:00.123456789, 2020-01-01 00:00:00.123456789}")
+  }
+
   test("SPARK-35112: Cast string to day-time interval") {
     checkEvaluation(cast(Literal.create("0 0:0:0"), DayTimeIntervalType()), 0L)
     checkEvaluation(cast(Literal.create(" interval '0 0:0:0' Day TO second   
"),
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/TimestampNanosRowSuite.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/TimestampNanosRowSuite.scala
index 02c967c0ffec..d85350504f7f 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/TimestampNanosRowSuite.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/TimestampNanosRowSuite.scala
@@ -17,7 +17,7 @@
 
 package org.apache.spark.sql.catalyst.expressions
 
-import org.apache.spark.{SparkFunSuite, SparkUnsupportedOperationException}
+import org.apache.spark.SparkFunSuite
 import org.apache.spark.sql.catalyst.InternalRow
 import 
org.apache.spark.sql.catalyst.expressions.codegen.GenerateUnsafeProjection
 import org.apache.spark.sql.catalyst.util.GenericArrayData
@@ -184,21 +184,6 @@ class TimestampNanosRowSuite extends SparkFunSuite with 
ExpressionEvalHelper {
     checkEvaluation(Literal.create(null, TimestampLTZNanosType(7)), null)
   }
 
-  // Fractional-second formatting is not implemented yet, so CAST(nanos AS 
STRING) raises the
-  // user-facing UNSUPPORTED_FEATURE.TIMESTAMP_NANOS_TO_STRING error. Both the 
interpreted
-  // (ToStringBase.castToString -> TypeApiOps.format) and codegen 
(ToStringBase.castToStringCode)
-  // paths must fail the same way (SPARK-57207).
-  test("CAST nanos timestamp to STRING raises an unsupported-feature error in 
both eval modes") {
-    Seq(
-      Literal.create(ntzValue, TimestampNTZNanosType(9)),
-      Literal.create(ltzValue, TimestampLTZNanosType(7))).foreach { lit =>
-      checkErrorInExpression[SparkUnsupportedOperationException](
-        Cast(lit, StringType),
-        condition = "UNSUPPORTED_FEATURE.TIMESTAMP_NANOS_TO_STRING",
-        parameters = Map("dataType" -> ("\"" + lit.dataType.sql + "\"")))
-    }
-  }
-
   testBothCodegenAndInterpreted("UnsafeRow handles extreme epoch micros for 
nanos") {
     val fieldTypes: Array[DataType] = Array(TimestampNTZNanosType(9))
     val converter = UnsafeProjection.create(fieldTypes)
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/ToPrettyStringSuite.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/ToPrettyStringSuite.scala
index 6a2651edd9ab..c00a33ee48d8 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/ToPrettyStringSuite.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/ToPrettyStringSuite.scala
@@ -21,7 +21,7 @@ import org.apache.spark.SparkFunSuite
 import org.apache.spark.sql.catalyst.util.DateTimeTestUtils.UTC_OPT
 import org.apache.spark.sql.internal.SQLConf
 import org.apache.spark.sql.types._
-import org.apache.spark.unsafe.types.{UTF8String, VariantVal}
+import org.apache.spark.unsafe.types.{TimestampNanosVal, UTF8String, 
VariantVal}
 
 class ToPrettyStringSuite extends SparkFunSuite with ExpressionEvalHelper {
 
@@ -135,6 +135,28 @@ class ToPrettyStringSuite extends SparkFunSuite with 
ExpressionEvalHelper {
     assert(prettyString.sql === child.sql)
   }
 
+  test("SPARK-57256: TimestampNTZNanos as pretty strings") {
+    def ntzNanos(micros: Long, nanos: Short): Expression =
+      ToPrettyString(Literal.create(new TimestampNanosVal(micros, nanos), 
TimestampNTZNanosType(9)))
+    checkEvaluation(ntzNanos(0L, 1), "1970-01-01 00:00:00.000000001")
+    checkEvaluation(ntzNanos(1L, 0), "1970-01-01 00:00:00.000001")
+    checkEvaluation(
+      ToPrettyString(Literal.create(TimestampNanosVal.ZERO, 
TimestampNTZNanosType(9))),
+      "1970-01-01 00:00:00")
+  }
+
+  test("SPARK-57256: TimestampLTZNanos as pretty strings") {
+    def ltzNanos(micros: Long, nanos: Short): Expression =
+      ToPrettyString(Literal.create(new TimestampNanosVal(micros, nanos), 
TimestampLTZNanosType(9)))
+    withSQLConf(SQLConf.SESSION_LOCAL_TIMEZONE.key -> "UTC") {
+      checkEvaluation(ltzNanos(0L, 1), "1970-01-01 00:00:00.000000001")
+      checkEvaluation(ltzNanos(1L, 0), "1970-01-01 00:00:00.000001")
+      checkEvaluation(
+        ToPrettyString(Literal.create(TimestampNanosVal.ZERO, 
TimestampLTZNanosType(9))),
+        "1970-01-01 00:00:00")
+    }
+  }
+
   test("Time as pretty strings") {
     checkEvaluation(ToPrettyString(Literal(1000 * 1000L, TimeType())), 
"00:00:00.001")
     checkEvaluation(ToPrettyString(Literal(1000L, TimeType())), 
"00:00:00.000001")
diff --git 
a/sql/core/src/test/resources/sql-tests/analyzer-results/cast.sql.out 
b/sql/core/src/test/resources/sql-tests/analyzer-results/cast.sql.out
index b077443a9f28..cc296a57abc5 100644
--- a/sql/core/src/test/resources/sql-tests/analyzer-results/cast.sql.out
+++ b/sql/core/src/test/resources/sql-tests/analyzer-results/cast.sql.out
@@ -669,6 +669,111 @@ Project [isnull(cast(a as timestamp_ltz(9))) AS (CAST(a 
AS TIMESTAMP_LTZ(9)) IS
 +- OneRowRelation
 
 
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(9)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(8)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(8)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(8)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(7)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(7)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(7)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000000' as timestamp_ntz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.000000000 as timestamp_ntz(9)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.000000000 AS TIMESTAMP_NTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000999' as timestamp_ntz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.000000999 as timestamp_ntz(9)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.000000999 AS TIMESTAMP_NTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000001' as timestamp_ntz(8)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.000000001 as timestamp_ntz(8)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.000000001 AS TIMESTAMP_NTZ(8)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ltz(9)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ltz(7)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(7)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('1960-01-01 00:00:00.000000001' as timestamp_ntz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(1960-01-01 00:00:00.000000001 as timestamp_ntz(9)) as 
string) AS CAST(CAST(1960-01-01 00:00:00.000000001 AS TIMESTAMP_NTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('1960-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string)
+-- !query analysis
+Project [cast(cast(1960-01-01 00:00:00.123456789 as timestamp_ltz(7)) as 
string) AS CAST(CAST(1960-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(7)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(array(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)), 
cast(null as timestamp_ntz(9))) as string)
+-- !query analysis
+Project [cast(array(cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(9)), 
cast(null as timestamp_ntz(9))) as string) AS CAST(array(CAST(2020-01-01 
00:00:00.123456789 AS TIMESTAMP_NTZ(9)), CAST(NULL AS TIMESTAMP_NTZ(9))) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(map('k', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9))) as string)
+-- !query analysis
+Project [cast(map(k, cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(9))) 
as string) AS CAST(map(k, CAST(2020-01-01 00:00:00.123456789 AS 
TIMESTAMP_NTZ(9))) AS STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(named_struct('f', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ltz(9))) as string)
+-- !query analysis
+Project [cast(named_struct(f, cast(2020-01-01 00:00:00.123456789 as 
timestamp_ltz(9))) as string) AS CAST(named_struct(f, CAST(2020-01-01 
00:00:00.123456789 AS TIMESTAMP_LTZ(9))) AS STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast(null as timestamp_ntz(9)) as string)
+-- !query analysis
+Project [cast(cast(null as timestamp_ntz(9)) as string) AS CAST(CAST(NULL AS 
TIMESTAMP_NTZ(9)) AS STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select concat('ts=', cast(cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9)) as string))
+-- !query analysis
+Project [concat(ts=, cast(cast(2020-01-01 00:00:00.123456789 as 
timestamp_ntz(9)) as string)) AS concat(ts=, CAST(CAST(2020-01-01 
00:00:00.123456789 AS TIMESTAMP_NTZ(9)) AS STRING))#x]
++- OneRowRelation
+
+
 -- !query
 select cast(cast('inf' as double) as timestamp)
 -- !query analysis
diff --git 
a/sql/core/src/test/resources/sql-tests/analyzer-results/nonansi/cast.sql.out 
b/sql/core/src/test/resources/sql-tests/analyzer-results/nonansi/cast.sql.out
index 1255f2266629..bcc410b322ae 100644
--- 
a/sql/core/src/test/resources/sql-tests/analyzer-results/nonansi/cast.sql.out
+++ 
b/sql/core/src/test/resources/sql-tests/analyzer-results/nonansi/cast.sql.out
@@ -533,6 +533,111 @@ Project [isnull(cast(a as timestamp_ltz(9))) AS (CAST(a 
AS TIMESTAMP_LTZ(9)) IS
 +- OneRowRelation
 
 
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(9)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(8)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(8)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(8)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(7)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(7)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(7)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000000' as timestamp_ntz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.000000000 as timestamp_ntz(9)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.000000000 AS TIMESTAMP_NTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000999' as timestamp_ntz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.000000999 as timestamp_ntz(9)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.000000999 AS TIMESTAMP_NTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000001' as timestamp_ntz(8)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.000000001 as timestamp_ntz(8)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.000000001 AS TIMESTAMP_NTZ(8)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ltz(9)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string)
+-- !query analysis
+Project [cast(cast(2020-01-01 00:00:00.123456789 as timestamp_ltz(7)) as 
string) AS CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(7)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('1960-01-01 00:00:00.000000001' as timestamp_ntz(9)) as 
string)
+-- !query analysis
+Project [cast(cast(1960-01-01 00:00:00.000000001 as timestamp_ntz(9)) as 
string) AS CAST(CAST(1960-01-01 00:00:00.000000001 AS TIMESTAMP_NTZ(9)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast('1960-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string)
+-- !query analysis
+Project [cast(cast(1960-01-01 00:00:00.123456789 as timestamp_ltz(7)) as 
string) AS CAST(CAST(1960-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(7)) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(array(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)), 
cast(null as timestamp_ntz(9))) as string)
+-- !query analysis
+Project [cast(array(cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(9)), 
cast(null as timestamp_ntz(9))) as string) AS CAST(array(CAST(2020-01-01 
00:00:00.123456789 AS TIMESTAMP_NTZ(9)), CAST(NULL AS TIMESTAMP_NTZ(9))) AS 
STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(map('k', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9))) as string)
+-- !query analysis
+Project [cast(map(k, cast(2020-01-01 00:00:00.123456789 as timestamp_ntz(9))) 
as string) AS CAST(map(k, CAST(2020-01-01 00:00:00.123456789 AS 
TIMESTAMP_NTZ(9))) AS STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(named_struct('f', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ltz(9))) as string)
+-- !query analysis
+Project [cast(named_struct(f, cast(2020-01-01 00:00:00.123456789 as 
timestamp_ltz(9))) as string) AS CAST(named_struct(f, CAST(2020-01-01 
00:00:00.123456789 AS TIMESTAMP_LTZ(9))) AS STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select cast(cast(null as timestamp_ntz(9)) as string)
+-- !query analysis
+Project [cast(cast(null as timestamp_ntz(9)) as string) AS CAST(CAST(NULL AS 
TIMESTAMP_NTZ(9)) AS STRING)#x]
++- OneRowRelation
+
+
+-- !query
+select concat('ts=', cast(cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9)) as string))
+-- !query analysis
+Project [concat(ts=, cast(cast(2020-01-01 00:00:00.123456789 as 
timestamp_ntz(9)) as string)) AS concat(ts=, CAST(CAST(2020-01-01 
00:00:00.123456789 AS TIMESTAMP_NTZ(9)) AS STRING))#x]
++- OneRowRelation
+
+
 -- !query
 select cast(cast('inf' as double) as timestamp)
 -- !query analysis
diff --git a/sql/core/src/test/resources/sql-tests/inputs/cast.sql 
b/sql/core/src/test/resources/sql-tests/inputs/cast.sql
index 5065e7c335e7..5aead54b2722 100644
--- a/sql/core/src/test/resources/sql-tests/inputs/cast.sql
+++ b/sql/core/src/test/resources/sql-tests/inputs/cast.sql
@@ -103,14 +103,39 @@ select cast('2022-01-01 00:00:00' as timestamp_ntz);
 select cast('a' as timestamp_ntz);
 
 -- SPARK-57211: cast string to nanosecond-precision timestamps 
TIMESTAMP_NTZ(p)/TIMESTAMP_LTZ(p).
--- The reverse direction (nanos -> string) is not wired yet, so positive cases 
assert the result
--- type via typeof. Negative cases exercise the ANSI parse-error path and use 
IS NULL so the result
--- column stays non-nanos (a bare nanos result column is not yet serializable 
by JDBC/thrift).
+-- Positive cases assert the result type via typeof. Negative cases exercise 
the ANSI parse-error
+-- path and use IS NULL so the result column stays non-nanos (a bare nanos 
result column is not yet
+-- serializable by JDBC/thrift).
 select typeof(cast('2022-01-01 00:00:00.123456789' as timestamp_ntz(9)));
 select typeof(cast('2022-01-01 00:00:00.123456789' as timestamp_ltz(7)));
 select cast('a' as timestamp_ntz(9)) is null;
 select cast('a' as timestamp_ltz(9)) is null;
 
+-- SPARK-57256: cast nanosecond-precision timestamps to string. The result 
column is STRING (the
+-- nanos type is only intermediate), so the value is produced by the 
Cast-to-string expression
+-- (ToStringBase). The nanos preview flag defaults to enabled under tests, and 
LTZ wall-clock inputs
+-- round-trip in any session time zone, so these cases stay zone-independent.
+-- TIMESTAMP_NTZ(p): precision-driven fraction width and trailing-zero 
trimming.
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)) as 
string);
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(8)) as 
string);
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(7)) as 
string);
+select cast(cast('2020-01-01 00:00:00.000000000' as timestamp_ntz(9)) as 
string);
+select cast(cast('2020-01-01 00:00:00.000000999' as timestamp_ntz(9)) as 
string);
+select cast(cast('2020-01-01 00:00:00.000000001' as timestamp_ntz(8)) as 
string);
+-- TIMESTAMP_LTZ(p): exercises the zone-aware path; a wall-clock input 
round-trips.
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(9)) as 
string);
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string);
+-- Pre-1970 (negative-epoch) values.
+select cast(cast('1960-01-01 00:00:00.000000001' as timestamp_ntz(9)) as 
string);
+select cast(cast('1960-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string);
+-- Complex types cast to string (recursive element path, including a nested 
NULL).
+select cast(array(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)), 
cast(null as timestamp_ntz(9))) as string);
+select cast(map('k', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9))) as string);
+select cast(named_struct('f', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ltz(9))) as string);
+-- NULL and a real string context.
+select cast(cast(null as timestamp_ntz(9)) as string);
+select concat('ts=', cast(cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9)) as string));
+
 select cast(cast('inf' as double) as timestamp);
 select cast(cast('inf' as float) as timestamp);
 
diff --git a/sql/core/src/test/resources/sql-tests/results/cast.sql.out 
b/sql/core/src/test/resources/sql-tests/results/cast.sql.out
index 10b6f4526889..2cff542eb98d 100644
--- a/sql/core/src/test/resources/sql-tests/results/cast.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/cast.sql.out
@@ -1354,6 +1354,126 @@ org.apache.spark.SparkDateTimeException
 }
 
 
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(9)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.123456789
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(8)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(8)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.12345678
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(7)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(7)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.1234567
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000000' as timestamp_ntz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.000000000 AS TIMESTAMP_NTZ(9)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000999' as timestamp_ntz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.000000999 AS TIMESTAMP_NTZ(9)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.000000999
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000001' as timestamp_ntz(8)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.000000001 AS TIMESTAMP_NTZ(8)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(9)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.123456789
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(7)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.1234567
+
+
+-- !query
+select cast(cast('1960-01-01 00:00:00.000000001' as timestamp_ntz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(1960-01-01 00:00:00.000000001 AS TIMESTAMP_NTZ(9)) AS 
STRING):string>
+-- !query output
+1960-01-01 00:00:00.000000001
+
+
+-- !query
+select cast(cast('1960-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string)
+-- !query schema
+struct<CAST(CAST(1960-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(7)) AS 
STRING):string>
+-- !query output
+1960-01-01 00:00:00.1234567
+
+
+-- !query
+select cast(array(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)), 
cast(null as timestamp_ntz(9))) as string)
+-- !query schema
+struct<CAST(array(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(9)), 
CAST(NULL AS TIMESTAMP_NTZ(9))) AS STRING):string>
+-- !query output
+[2020-01-01 00:00:00.123456789, null]
+
+
+-- !query
+select cast(map('k', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9))) as string)
+-- !query schema
+struct<CAST(map(k, CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(9))) AS 
STRING):string>
+-- !query output
+{k -> 2020-01-01 00:00:00.123456789}
+
+
+-- !query
+select cast(named_struct('f', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ltz(9))) as string)
+-- !query schema
+struct<CAST(named_struct(f, CAST(2020-01-01 00:00:00.123456789 AS 
TIMESTAMP_LTZ(9))) AS STRING):string>
+-- !query output
+{2020-01-01 00:00:00.123456789}
+
+
+-- !query
+select cast(cast(null as timestamp_ntz(9)) as string)
+-- !query schema
+struct<CAST(CAST(NULL AS TIMESTAMP_NTZ(9)) AS STRING):string>
+-- !query output
+NULL
+
+
+-- !query
+select concat('ts=', cast(cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9)) as string))
+-- !query schema
+struct<concat(ts=, CAST(CAST(2020-01-01 00:00:00.123456789 AS 
TIMESTAMP_NTZ(9)) AS STRING)):string>
+-- !query output
+ts=2020-01-01 00:00:00.123456789
+
+
 -- !query
 select cast(cast('inf' as double) as timestamp)
 -- !query schema
diff --git a/sql/core/src/test/resources/sql-tests/results/nonansi/cast.sql.out 
b/sql/core/src/test/resources/sql-tests/results/nonansi/cast.sql.out
index 2b73fe4e63da..d215cf7cee3c 100644
--- a/sql/core/src/test/resources/sql-tests/results/nonansi/cast.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/nonansi/cast.sql.out
@@ -616,6 +616,126 @@ struct<(CAST(a AS TIMESTAMP_LTZ(9)) IS NULL):boolean>
 true
 
 
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(9)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.123456789
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(8)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(8)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.12345678
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(7)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(7)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.1234567
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000000' as timestamp_ntz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.000000000 AS TIMESTAMP_NTZ(9)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000999' as timestamp_ntz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.000000999 AS TIMESTAMP_NTZ(9)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.000000999
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.000000001' as timestamp_ntz(8)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.000000001 AS TIMESTAMP_NTZ(8)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(9)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.123456789
+
+
+-- !query
+select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string)
+-- !query schema
+struct<CAST(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(7)) AS 
STRING):string>
+-- !query output
+2020-01-01 00:00:00.1234567
+
+
+-- !query
+select cast(cast('1960-01-01 00:00:00.000000001' as timestamp_ntz(9)) as 
string)
+-- !query schema
+struct<CAST(CAST(1960-01-01 00:00:00.000000001 AS TIMESTAMP_NTZ(9)) AS 
STRING):string>
+-- !query output
+1960-01-01 00:00:00.000000001
+
+
+-- !query
+select cast(cast('1960-01-01 00:00:00.123456789' as timestamp_ltz(7)) as 
string)
+-- !query schema
+struct<CAST(CAST(1960-01-01 00:00:00.123456789 AS TIMESTAMP_LTZ(7)) AS 
STRING):string>
+-- !query output
+1960-01-01 00:00:00.1234567
+
+
+-- !query
+select cast(array(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)), 
cast(null as timestamp_ntz(9))) as string)
+-- !query schema
+struct<CAST(array(CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(9)), 
CAST(NULL AS TIMESTAMP_NTZ(9))) AS STRING):string>
+-- !query output
+[2020-01-01 00:00:00.123456789, null]
+
+
+-- !query
+select cast(map('k', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9))) as string)
+-- !query schema
+struct<CAST(map(k, CAST(2020-01-01 00:00:00.123456789 AS TIMESTAMP_NTZ(9))) AS 
STRING):string>
+-- !query output
+{k -> 2020-01-01 00:00:00.123456789}
+
+
+-- !query
+select cast(named_struct('f', cast('2020-01-01 00:00:00.123456789' as 
timestamp_ltz(9))) as string)
+-- !query schema
+struct<CAST(named_struct(f, CAST(2020-01-01 00:00:00.123456789 AS 
TIMESTAMP_LTZ(9))) AS STRING):string>
+-- !query output
+{2020-01-01 00:00:00.123456789}
+
+
+-- !query
+select cast(cast(null as timestamp_ntz(9)) as string)
+-- !query schema
+struct<CAST(CAST(NULL AS TIMESTAMP_NTZ(9)) AS STRING):string>
+-- !query output
+NULL
+
+
+-- !query
+select concat('ts=', cast(cast('2020-01-01 00:00:00.123456789' as 
timestamp_ntz(9)) as string))
+-- !query schema
+struct<concat(ts=, CAST(CAST(2020-01-01 00:00:00.123456789 AS 
TIMESTAMP_NTZ(9)) AS STRING)):string>
+-- !query output
+ts=2020-01-01 00:00:00.123456789
+
+
 -- !query
 select cast(cast('inf' as double) as timestamp)
 -- !query schema


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


Reply via email to