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

MaxGekk pushed a commit to branch branch-4.x
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/branch-4.x by this push:
     new 16dacbb9383c [SPARK-57463][SQL] Render nanosecond-precision timestamp 
types in the Thrift server via the Types Framework
16dacbb9383c is described below

commit 16dacbb9383cc91bb802346c62f9b400e1473485
Author: Maxim Gekk <[email protected]>
AuthorDate: Tue Jun 16 18:47:02 2026 +0200

    [SPARK-57463][SQL] Render nanosecond-precision timestamp types in the 
Thrift server via the Types Framework
    
    ### What changes were proposed in this pull request?
    
    This PR makes the nanosecond-capable timestamp types `TIMESTAMP_NTZ(p)` and 
`TIMESTAMP_LTZ(p)` (`p` in 7-9) usable over the Spark Thrift / JDBC server, 
reaching parity with the microsecond `TimestampType` / `TimestampNTZType`.
    
    1. Implement the Types Framework `thriftTypeName` hook. 
`SparkExecuteStatementOperation` resolves a column's Thrift `TTypeId` via 
`TypeApiOps(typ).flatMap(_.thriftTypeName)`. `TimestampNanosTypeApiOps` did not 
override it (defaulted to `None`), and the nanos types are not in the 
`toTTypeIdDefault` fallback, so a nanos column hit `case other => throw new 
IllegalArgumentException("Unrecognized type name: ...")`. The fix overrides 
`thriftTypeName` in the abstract base `TimestampNanosType [...]
    
    2. Enable the nanosecond golden-file tests in `ThriftServerQueryTestSuite` 
by removing `timestamp-ntz-nanos.sql` and `timestamp-ltz-nanos.sql` from its 
ignore list (they were skipped only because nanos types were not yet mapped by 
the Thrift server).
    
    3. Drop the now-unnecessary `cast(... as string)` workarounds for the 
micros -> nanos widening cases in `cast.sql` (SPARK-57293 section), which 
existed only because a bare nanos result column was not serializable over 
JDBC/thrift. They now produce bare `TIMESTAMP_NTZ(9)` / `TIMESTAMP_LTZ(9)` 
result columns; golden files are regenerated and the output values are 
unchanged.
    
    No changes were needed in `SparkExecuteStatementOperation` or 
`RowSetUtils`. Related Hive CLI rendering through the framework is tracked 
separately by SPARK-57386.
    
    ### Why are the changes needed?
    
    To be able to retrieve nanosecond-precision timestamps via the Hive Thrift 
server. Before this change, with the preview flag enabled, such a query fails:
    
    ```
    0: jdbc:hive2://localhost:10000/default> SET 
spark.sql.timestampNanosTypes.enabled=true;
    0: jdbc:hive2://localhost:10000/default> SELECT timestamp_ntz'2021-01-01 
01:02:03.000000001';
    Error: java.lang.IllegalArgumentException: Unrecognized type name: 
timestamp_ntz(9) (state=,code=0)
    ```
    
    This is analogous to the ANSI-interval issue fixed by SPARK-35017 
(`Unrecognized type name: day-time interval`) and the TIME support added by 
SPARK-51516.
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. After the changes, nanosecond timestamp columns are returned over JDBC 
as strings rendered at the column precision (the nanos types are a preview 
feature gated by `spark.sql.timestampNanosTypes.enabled`):
    
    ```
    0: jdbc:hive2://localhost:10000/default> SET 
spark.sql.timestampNanosTypes.enabled=true;
    0: jdbc:hive2://localhost:10000/default> SELECT timestamp_ntz'2021-01-01 
01:02:03.000000001' AS ntz9;
    +--------------------------------+
    |              ntz9              |
    +--------------------------------+
    | 2021-01-01 01:02:03.000000001  |
    +--------------------------------+
    0: jdbc:hive2://localhost:10000/default> SELECT timestamp_ltz'2021-01-01 
01:02:03.123456789' AS ltz9;
    +--------------------------------+
    |              ltz9              |
    +--------------------------------+
    | 2021-01-01 01:02:03.123456789  |
    +--------------------------------+
    0: jdbc:hive2://localhost:10000/default> SELECT CAST('2021-01-01 
01:02:03.123456789' AS TIMESTAMP_NTZ(7)) AS ntz7;
    +------------------------------+
    |             ntz7             |
    +------------------------------+
    | 2021-01-01 01:02:03.1234567  |
    +------------------------------+
    0: jdbc:hive2://localhost:10000/default> SELECT CAST('2021-01-01 
01:02:03.123456789' AS TIMESTAMP_LTZ(8)) AS ltz8;
    +-------------------------------+
    |             ltz8              |
    +-------------------------------+
    | 2021-01-01 01:02:03.12345678  |
    +-------------------------------+
    ```
    
    With the flag off (the production default), a nanos literal continues to 
degrade to a microsecond timestamp, unchanged by this PR:
    
    ```
    0: jdbc:hive2://localhost:10000/default> SELECT timestamp_ntz'2021-01-01 
01:02:03.000000001' AS ntz;
    +------------------------+
    |          ntz           |
    +------------------------+
    | 2021-01-01 01:02:03.0  |
    +------------------------+
    ```
    
    ### How was this patch tested?
    
    1. New tests under `sql/hive-thriftserver`:
       - `SparkExecuteStatementOperationSuite`: asserts `toTTableSchema` maps 
`TimestampNTZNanosType(p)` / `TimestampLTZNanosType(p)` (p in 7-9) to 
`TTypeId.STRING_TYPE`.
       - `HiveThriftBinaryServerSuite`: an end-to-end JDBC test that enables 
the flag, queries NTZ/LTZ at precisions 7-9, and asserts both the column 
metadata (`VARCHAR` / `"string"`) and the rendered fractional digits.
    
    2. `ThriftServerQueryTestSuite` now runs `timestamp-ntz-nanos.sql`, 
`timestamp-ltz-nanos.sql`, and `cast.sql` end-to-end over JDBC (previously the 
nanos files were ignored).
    
    ```
    $ build/sbt -Phive -Phive-thriftserver "hive-thriftserver/testOnly 
*SparkExecuteStatementOperationSuite"
    $ build/sbt -Phive -Phive-thriftserver "hive-thriftserver/testOnly 
*HiveThriftBinaryServerSuite -- -z nanosecond"
    $ build/sbt -Phive -Phive-thriftserver "hive-thriftserver/testOnly 
*ThriftServerQueryTestSuite -- -z nanos"
    $ build/sbt -Phive -Phive-thriftserver "hive-thriftserver/testOnly 
*ThriftServerQueryTestSuite -- -z cast.sql"
    ```
    
    3. Regenerated `cast.sql` golden files via `SPARK_GENERATE_GOLDEN_FILES=1 
build/sbt "sql/testOnly org.apache.spark.sql.SQLQueryTestSuite -- -z 
cast.sql"`; the output values are unchanged (only the result column type 
changed from `string` to the nanos type).
    
    4. Manually verified end-to-end against a running Thrift server with 
`beeline` (the before/after transcripts shown above).
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Cursor (Claude Opus 4.8)
    
    Closes #56519 from MaxGekk/nanos-thriftserver.
    
    Authored-by: Maxim Gekk <[email protected]>
    Signed-off-by: Max Gekk <[email protected]>
    (cherry picked from commit a6e3fdd504cbff4dff739801e0b0b0f2b6402502)
    Signed-off-by: Max Gekk <[email protected]>
---
 .../sql/types/ops/TimestampNanosTypeApiOps.scala   |  7 ++++++
 .../sql-tests/analyzer-results/cast.sql.out        |  8 +++----
 .../analyzer-results/nonansi/cast.sql.out          |  8 +++----
 .../src/test/resources/sql-tests/inputs/cast.sql   |  7 +++---
 .../test/resources/sql-tests/results/cast.sql.out  |  8 +++----
 .../sql-tests/results/nonansi/cast.sql.out         |  8 +++----
 .../thriftserver/HiveThriftServer2Suites.scala     | 25 ++++++++++++++++++++++
 .../SparkExecuteStatementOperationSuite.scala      | 17 ++++++++++++++-
 .../thriftserver/ThriftServerQueryTestSuite.scala  |  5 +----
 9 files changed, 68 insertions(+), 25 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 32aac4dcfd9c..4e050b69471a 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
@@ -67,6 +67,13 @@ abstract class TimestampNanosTypeApiOps extends TypeApiOps 
with DataTypeErrorsBa
 
   override def toSQLValue(v: Any): String = s"$sqlTypeName '${format(v)}'"
 
+  // ==================== Thrift Mapping ====================
+
+  // Over the Thrift / JDBC server the nanosecond timestamp value is sent as a 
string column
+  // (RowSetUtils renders it via HiveResult.toHiveString at the column 
precision), so map the
+  // column to STRING_TYPE for consistency, mirroring the reference TimeType 
ops.
+  override def thriftTypeName: Option[String] = Some("STRING_TYPE")
+
   // ==================== Row Encoding ====================
 
   // Honor the spark.sql.timestampNanosTypes.enabled gate just like the legacy
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 ea9c634bbd89..8af6e17e41c2 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
@@ -775,9 +775,9 @@ Project [concat(ts=, cast(cast(2020-01-01 
00:00:00.123456789 as timestamp_ntz(9)
 
 
 -- !query
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9)) as string)
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9))
 -- !query analysis
-Project [cast(cast(cast(2020-01-01 00:00:00.123456 as timestamp_ntz) as 
timestamp_ntz(9)) as string) AS CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS 
TIMESTAMP_NTZ) AS TIMESTAMP_NTZ(9)) AS STRING)#x]
+Project [cast(cast(2020-01-01 00:00:00.123456 as timestamp_ntz) as 
timestamp_ntz(9)) AS CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP_NTZ) AS 
TIMESTAMP_NTZ(9))#x]
 +- OneRowRelation
 
 
@@ -796,9 +796,9 @@ Project [cast(cast(cast(2020-01-01 00:00:00.123456 as 
timestamp_ntz) as timestam
 
 
 -- !query
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9)) as string)
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9))
 -- !query analysis
-Project [cast(cast(cast(2020-01-01 00:00:00.123456 as timestamp) as 
timestamp_ltz(9)) as string) AS CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS 
TIMESTAMP) AS TIMESTAMP_LTZ(9)) AS STRING)#x]
+Project [cast(cast(2020-01-01 00:00:00.123456 as timestamp) as 
timestamp_ltz(9)) AS CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP) AS 
TIMESTAMP_LTZ(9))#x]
 +- OneRowRelation
 
 
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 a04d020e13cc..fb1662484aa9 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
@@ -639,9 +639,9 @@ Project [concat(ts=, cast(cast(2020-01-01 
00:00:00.123456789 as timestamp_ntz(9)
 
 
 -- !query
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9)) as string)
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9))
 -- !query analysis
-Project [cast(cast(cast(2020-01-01 00:00:00.123456 as timestamp_ntz) as 
timestamp_ntz(9)) as string) AS CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS 
TIMESTAMP_NTZ) AS TIMESTAMP_NTZ(9)) AS STRING)#x]
+Project [cast(cast(2020-01-01 00:00:00.123456 as timestamp_ntz) as 
timestamp_ntz(9)) AS CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP_NTZ) AS 
TIMESTAMP_NTZ(9))#x]
 +- OneRowRelation
 
 
@@ -660,9 +660,9 @@ Project [cast(cast(cast(2020-01-01 00:00:00.123456 as 
timestamp_ntz) as timestam
 
 
 -- !query
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9)) as string)
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9))
 -- !query analysis
-Project [cast(cast(cast(2020-01-01 00:00:00.123456 as timestamp) as 
timestamp_ltz(9)) as string) AS CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS 
TIMESTAMP) AS TIMESTAMP_LTZ(9)) AS STRING)#x]
+Project [cast(cast(2020-01-01 00:00:00.123456 as timestamp) as 
timestamp_ltz(9)) AS CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP) AS 
TIMESTAMP_LTZ(9))#x]
 +- OneRowRelation
 
 
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 78373951c565..3d8636900938 100644
--- a/sql/core/src/test/resources/sql-tests/inputs/cast.sql
+++ b/sql/core/src/test/resources/sql-tests/inputs/cast.sql
@@ -138,16 +138,15 @@ select concat('ts=', cast(cast('2020-01-01 
00:00:00.123456789' as timestamp_ntz(
 
 -- SPARK-57293: cast between nanosecond-precision timestamps and their 
microsecond counterparts.
 -- Both directions stay within one zone family (pure representation 
conversions, no timezone
--- involvement). Widening (micros -> nanos(p)) is wrapped in cast(... as 
string) because a bare
--- nanos result column is not yet serializable by JDBC/thrift; 
narrowing/round-trip yield micros.
+-- involvement); narrowing/round-trip yield micros.
 -- TIMESTAMP_NTZ <-> TIMESTAMP_NTZ(p): widening sets the sub-microsecond part 
to 0.
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9)) as string);
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9));
 -- Narrowing TIMESTAMP_NTZ(p) -> TIMESTAMP_NTZ drops the sub-microsecond 
digits (floor).
 select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ntz(9)) as 
timestamp_ntz);
 -- Round-trip micros -> nanos(p) -> micros returns the original microseconds.
 select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9)) as timestamp_ntz);
 -- TIMESTAMP_LTZ <-> TIMESTAMP_LTZ(p): same conversions on the epoch-micros 
instant.
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9)) as string);
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9));
 select cast(cast('2020-01-01 00:00:00.123456789' as timestamp_ltz(9)) as 
timestamp);
 select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9)) 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 ba18d1e10168..f152fa699184 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
@@ -1475,9 +1475,9 @@ ts=2020-01-01 00:00:00.123456789
 
 
 -- !query
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9)) as string)
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9))
 -- !query schema
-struct<CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP_NTZ) AS 
TIMESTAMP_NTZ(9)) AS STRING):string>
+struct<CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP_NTZ) AS 
TIMESTAMP_NTZ(9)):timestamp_ntz(9)>
 -- !query output
 2020-01-01 00:00:00.123456
 
@@ -1499,9 +1499,9 @@ struct<CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS 
TIMESTAMP_NTZ) AS TIMESTAMP_
 
 
 -- !query
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9)) as string)
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9))
 -- !query schema
-struct<CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP) AS 
TIMESTAMP_LTZ(9)) AS STRING):string>
+struct<CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP) AS 
TIMESTAMP_LTZ(9)):timestamp_ltz(9)>
 -- !query output
 2020-01-01 00:00:00.123456
 
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 442daf553aee..466eb68cb5ff 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
@@ -737,9 +737,9 @@ ts=2020-01-01 00:00:00.123456789
 
 
 -- !query
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9)) as string)
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp_ntz) as 
timestamp_ntz(9))
 -- !query schema
-struct<CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP_NTZ) AS 
TIMESTAMP_NTZ(9)) AS STRING):string>
+struct<CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP_NTZ) AS 
TIMESTAMP_NTZ(9)):timestamp_ntz(9)>
 -- !query output
 2020-01-01 00:00:00.123456
 
@@ -761,9 +761,9 @@ struct<CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS 
TIMESTAMP_NTZ) AS TIMESTAMP_
 
 
 -- !query
-select cast(cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9)) as string)
+select cast(cast('2020-01-01 00:00:00.123456' as timestamp) as 
timestamp_ltz(9))
 -- !query schema
-struct<CAST(CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP) AS 
TIMESTAMP_LTZ(9)) AS STRING):string>
+struct<CAST(CAST(2020-01-01 00:00:00.123456 AS TIMESTAMP) AS 
TIMESTAMP_LTZ(9)):timestamp_ltz(9)>
 -- !query output
 2020-01-01 00:00:00.123456
 
diff --git 
a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/HiveThriftServer2Suites.scala
 
b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/HiveThriftServer2Suites.scala
index 65232aa2ce71..bee77647707e 100644
--- 
a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/HiveThriftServer2Suites.scala
+++ 
b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/HiveThriftServer2Suites.scala
@@ -244,6 +244,31 @@ class HiveThriftBinaryServerSuite extends 
HiveThriftServer2Test {
     }
   }
 
+  test("SPARK-57463: nanosecond-precision timestamp types over JDBC") {
+    withJdbcStatement() { statement =>
+      statement.execute("SET spark.sql.timestampNanosTypes.enabled=true")
+      // Fix the session zone so the LTZ wall-clock value is deterministic.
+      statement.execute("SET spark.sql.session.timeZone=UTC")
+
+      // The cast truncates the 9-digit fraction to the column precision 
(SPARK-57256), matching
+      // the cast-to-string / HiveResult rendering.
+      val expectedFractions = Map(7 -> ".1234567", 8 -> ".12345678", 9 -> 
".123456789")
+      val base = "2019-07-22 18:14:00"
+      Seq("TIMESTAMP_NTZ", "TIMESTAMP_LTZ").foreach { typeName =>
+        for (p <- 7 to 9) {
+          val resultSet = statement.executeQuery(
+            s"SELECT CAST('$base.123456789' AS $typeName($p))")
+          assert(resultSet.next())
+          assert(resultSet.getString(1) === s"$base${expectedFractions(p)}")
+          val metaData = resultSet.getMetaData
+          // The nanosecond timestamp column is mapped to STRING_TYPE in the 
Thrift server.
+          assert(metaData.getColumnTypeName(1) === "string")
+          assert(metaData.getColumnType(1) === java.sql.Types.VARCHAR)
+        }
+      }
+    }
+  }
+
   test("SPARK-4407 regression: Complex type support") {
     withJdbcStatement("test_map") { statement =>
       val queries = Seq(
diff --git 
a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/SparkExecuteStatementOperationSuite.scala
 
b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/SparkExecuteStatementOperationSuite.scala
index 749179b6ef50..ddd7f19ef238 100644
--- 
a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/SparkExecuteStatementOperationSuite.scala
+++ 
b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/SparkExecuteStatementOperationSuite.scala
@@ -32,7 +32,7 @@ import org.mockito.invocation.InvocationOnMock
 import org.apache.spark.sql.classic.{DataFrame, SparkSession}
 import org.apache.spark.sql.hive.thriftserver.ui.HiveThriftServer2EventManager
 import org.apache.spark.sql.test.SharedSparkSession
-import org.apache.spark.sql.types.{GeographyType, GeometryType, IntegerType, 
NullType, StringType, StructField, StructType}
+import org.apache.spark.sql.types.{GeographyType, GeometryType, IntegerType, 
NullType, StringType, StructField, StructType, TimestampLTZNanosType, 
TimestampNTZNanosType}
 
 class SparkExecuteStatementOperationSuite extends SharedSparkSession {
 
@@ -76,6 +76,21 @@ class SparkExecuteStatementOperationSuite extends 
SharedSparkSession {
     assert(geogType === TTypeId.STRING_TYPE)
   }
 
+  test("SPARK-57463 nanosecond-precision timestamp types are mapped to 
STRING_TYPE " +
+    "in ThriftServer") {
+    for (p <- TimestampNTZNanosType.MIN_PRECISION to 
TimestampNTZNanosType.MAX_PRECISION) {
+      val tableSchema = StructType(Seq(
+        StructField("ntz", TimestampNTZNanosType(p)),
+        StructField("ltz", TimestampLTZNanosType(p))))
+      val columns = SparkExecuteStatementOperation.toTTableSchema(tableSchema)
+      assert(columns.getColumnsSize == 2)
+      val ntzType = 
columns.getColumns.get(0).getTypeDesc.getTypes.get(0).getPrimitiveEntry.getType
+      assert(ntzType === TTypeId.STRING_TYPE)
+      val ltzType = 
columns.getColumns.get(1).getTypeDesc.getTypes.get(0).getPrimitiveEntry.getType
+      assert(ltzType === TTypeId.STRING_TYPE)
+    }
+  }
+
   Seq(
     (OperationState.CANCELED, (_: SparkExecuteStatementOperation).cancel()),
     (OperationState.TIMEDOUT, (_: 
SparkExecuteStatementOperation).timeoutCancel()),
diff --git 
a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/ThriftServerQueryTestSuite.scala
 
b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/ThriftServerQueryTestSuite.scala
index f9d333479bbd..401b3c126d85 100644
--- 
a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/ThriftServerQueryTestSuite.scala
+++ 
b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/ThriftServerQueryTestSuite.scala
@@ -118,10 +118,7 @@ class ThriftServerQueryTestSuite extends SQLQueryTestSuite 
with SharedThriftServ
     "pipe-operators.sql",
     // VARIANT type
     "variant/named-function-arguments.sql",
-    "variant-field-extractions.sql",
-    // SPARK-57257: nanosecond-precision timestamp types are not yet mapped by 
the Thrift Server
-    "timestamp-ltz-nanos.sql",
-    "timestamp-ntz-nanos.sql"
+    "variant-field-extractions.sql"
   )
 
   override def runQueries(


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

Reply via email to