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

MaxGekk 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 958e7ce75326 [SPARK-57566][CONNECT][TEST] Add test coverage for the 
TIME data type
958e7ce75326 is described below

commit 958e7ce75326524b1560222614429398fbf17912
Author: Vaibhav Garg <[email protected]>
AuthorDate: Fri Jun 26 10:58:43 2026 +0200

    [SPARK-57566][CONNECT][TEST] Add test coverage for the TIME data type
    
    ### What changes were proposed in this pull request?
    
    This PR adds end-to-end, golden-file, and proto round-trip test coverage 
for the TIME data type (`TimeType`) over Spark Connect. This is a test-only 
change with no engine or logic modifications. SPARK-57566 is a sub-task of the 
umbrella SPARK-57550 (extend TIME type support across Spark).
    
    **ClientE2ETestSuite** (Scala client, end-to-end against a real in-process 
Connect server):
    - `make_time` builtin returns a TIME value over Connect
    - `hour`, `minute`, `second` extract fields from a TIME value over Connect
    - `current_time` returns a TIME-typed column over Connect
    - A TIME column round-trips via `createDataFrame` over Connect
    - A TIME column round-trips through a parquet datasource over Connect
    
    The parquet datasource round-trip test verifies that a TIME column survives 
a real write-then-read through a file datasource over Connect, not just 
in-memory. This exercises parquet's TIME logical-type handling end-to-end and 
was added to satisfy the ticket's "createDataFrame / datasource round-trip" 
scope.
    
    **PlanGenerationTestSuite** (golden plan-generation):
    - Added `make_time`, `current_time`, and `current_time(precision)` function 
tests
    - Added the missing `LocalTime` case to the `function lit array` literal 
test (it already covered every other temporal type)
    - New and updated golden files generated via 
`SPARK_GENERATE_GOLDEN_FILES=1` and manually reviewed
    
    **LiteralExpressionProtoConverterSuite** (server-side proto/catalyst 
round-trip):
    - Added TIME literal round-trip coverage, including non-default precision 
propagation
    
    **Python note:** No new Python tests were added because Connect Python TIME 
coverage already exists through the parity suites. The classic PySpark tests 
`test_make_time`, `test_current_time`, and 
`test_create_dataframe_from_datetime_time` are re-run over a Connect session 
via `test_parity_functions` and `test_parity_creation`. The Python side is 
intentionally covered by existing parity, not omitted.
    
    ### Why are the changes needed?
    
    The TIME data type was added by SPIP SPARK-51162 and shipped in Spark 
4.1.0, but Spark Connect previously had only minimal TIME coverage: a single 
`SELECT TIME '12:13:14'` literal test in `ClientE2ETestSuite`, `LocalTime` 
literals in `PlanGenerationTestSuite`, and schema handling in 
`SparkConnectPlannerSuite`. The client-to-protobuf-to-server round-trip and the 
TIME builtin functions over Connect were unverified. These tests close that gap.
    
    ### Does this PR introduce any user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    This is a test-only change. All scoped suites were run locally and passed:
    
    - `connect-client-jvm/testOnly 
org.apache.spark.sql.PlanGenerationTestSuite` — 727 tests passed (golden files 
regenerated and manually reviewed)
    - `connect/testOnly 
org.apache.spark.sql.connect.planner.LiteralExpressionProtoConverterSuite` — 44 
tests passed
    - `connect-client-jvm/testOnly 
org.apache.spark.sql.connect.ClientE2ETestSuite -- -z "SPARK-57566"` — 5 tests 
passed
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Yes. Generated using Kiro (Claude Opus 4.8)
    
    Closes #56797 from vboo123/SPARK-57566.
    
    Lead-authored-by: Vaibhav Garg <[email protected]>
    Co-authored-by: Vaibhav Garg <[email protected]>
    Signed-off-by: Max Gekk <[email protected]>
---
 .../apache/spark/sql/PlanGenerationTestSuite.scala |  14 +++
 .../spark/sql/connect/ClientE2ETestSuite.scala     |  46 ++++++++++
 .../explain-results/function_current_time.explain  |   2 +
 .../function_current_time_with_precision.explain   |   2 +
 .../explain-results/function_lit_array.explain     |   2 +-
 .../explain-results/function_make_time.explain     |   2 +
 .../query-tests/queries/function_current_time.json |  38 ++++++++
 .../queries/function_current_time.proto.bin        | Bin 0 -> 309 bytes
 .../function_current_time_with_precision.json      |  60 ++++++++++++
 .../function_current_time_with_precision.proto.bin | Bin 0 -> 503 bytes
 .../query-tests/queries/function_lit_array.json    |  43 +++++++++
 .../queries/function_lit_array.proto.bin           | Bin 5116 -> 5346 bytes
 .../query-tests/queries/function_make_time.json    | 102 +++++++++++++++++++++
 .../queries/function_make_time.proto.bin           | Bin 0 -> 856 bytes
 .../LiteralExpressionProtoConverterSuite.scala     |  24 +++++
 15 files changed, 334 insertions(+), 1 deletion(-)

diff --git 
a/sql/connect/client/jvm/src/test/scala/org/apache/spark/sql/PlanGenerationTestSuite.scala
 
b/sql/connect/client/jvm/src/test/scala/org/apache/spark/sql/PlanGenerationTestSuite.scala
index 08b28e2b2081..a74b25459bad 100644
--- 
a/sql/connect/client/jvm/src/test/scala/org/apache/spark/sql/PlanGenerationTestSuite.scala
+++ 
b/sql/connect/client/jvm/src/test/scala/org/apache/spark/sql/PlanGenerationTestSuite.scala
@@ -2368,6 +2368,18 @@ class PlanGenerationTestSuite extends ConnectFunSuite 
with Logging {
     fn.make_date(fn.lit(2018), fn.lit(5), fn.lit(14))
   }
 
+  temporalFunctionTest("make_time") {
+    fn.make_time(fn.lit(12), fn.lit(13), fn.lit(14))
+  }
+
+  temporalFunctionTest("current_time") {
+    fn.current_time()
+  }
+
+  temporalFunctionTest("current_time with precision") {
+    fn.current_time(3)
+  }
+
   temporalFunctionTest("months_between") {
     fn.months_between(fn.current_date(), fn.col("d"))
   }
@@ -3440,6 +3452,8 @@ class PlanGenerationTestSuite extends ConnectFunSuite 
with Logging {
       fn.lit(Array(java.sql.Date.valueOf("2023-02-23"), 
java.sql.Date.valueOf("2023-03-01"))),
       fn.lit(Array(java.time.Duration.ofSeconds(100L), 
java.time.Duration.ofSeconds(200L))),
       fn.lit(Array(java.time.Period.ofDays(100), 
java.time.Period.ofDays(200))),
+      fn.lit(
+        Array(java.time.LocalTime.of(23, 59, 59, 999999999), 
java.time.LocalTime.of(12, 0, 0))),
       fn.lit(Array(new CalendarInterval(2, 20, 100L), new CalendarInterval(2, 
21, 200L))))
   }
 
diff --git 
a/sql/connect/client/jvm/src/test/scala/org/apache/spark/sql/connect/ClientE2ETestSuite.scala
 
b/sql/connect/client/jvm/src/test/scala/org/apache/spark/sql/connect/ClientE2ETestSuite.scala
index 0ac946a19e4b..c5a6c025cb36 100644
--- 
a/sql/connect/client/jvm/src/test/scala/org/apache/spark/sql/connect/ClientE2ETestSuite.scala
+++ 
b/sql/connect/client/jvm/src/test/scala/org/apache/spark/sql/connect/ClientE2ETestSuite.scala
@@ -1745,6 +1745,52 @@ class ClientE2ETestSuite
     checkAnswer(df, Row(LocalTime.of(12, 13, 14)))
   }
 
+  test("SPARK-57566: make_time builtin returns a TIME value over Connect") {
+    val df = spark.range(1).select(make_time(lit(12), lit(13), 
lit(14)).as("t"))
+    assert(df.schema.fields.head.dataType.isInstanceOf[TimeType])
+    checkAnswer(df, Row(LocalTime.of(12, 13, 14)))
+  }
+
+  test("SPARK-57566: hour, minute and second extract fields from a TIME value 
over Connect") {
+    val df = spark
+      .range(1)
+      .select(make_time(lit(12), lit(13), lit(14)).as("t"))
+      .select(hour(col("t")), minute(col("t")), second(col("t")))
+    checkAnswer(df, Row(12, 13, 14))
+  }
+
+  test("SPARK-57566: current_time returns a TIME-typed column over Connect") {
+    val df = spark.sql("SELECT current_time()")
+    assert(df.schema.fields.head.dataType.isInstanceOf[TimeType])
+  }
+
+  test("SPARK-57566: TIME column round-trips via createDataFrame over 
Connect") {
+    val schema = StructType(Array(StructField("t", TimeType())))
+    val rows = Seq(
+      Row(LocalTime.of(1, 2, 3)),
+      Row(LocalTime.of(23, 59, 59)),
+      Row(LocalTime.of(12, 30, 45, 123456000)))
+    val df = spark.createDataFrame(rows.asJava, schema)
+    assert(df.schema.fields.head.dataType === TimeType())
+    checkAnswer(df, rows)
+  }
+
+  test("SPARK-57566: TIME column round-trips through a parquet datasource over 
Connect") {
+    val schema = StructType(Array(StructField("t", TimeType())))
+    val rows = Seq(
+      Row(LocalTime.of(1, 2, 3)),
+      Row(LocalTime.of(23, 59, 59)),
+      Row(LocalTime.of(12, 30, 45, 123456000)))
+    withTempPath { file =>
+      val path = file.toPath.toAbsolutePath.toString
+      spark.createDataFrame(rows.asJava, schema).write.parquet(path)
+
+      val df = spark.read.parquet(path)
+      assert(df.schema.fields.head.dataType === TimeType())
+      checkAnswer(df, rows)
+    }
+  }
+
   test("SPARK-53054: DataFrameReader defaults to spark.sql.sources.default") {
     withTempPath { file =>
       val path = file.getAbsoluteFile.toURI.toString
diff --git 
a/sql/connect/common/src/test/resources/query-tests/explain-results/function_current_time.explain
 
b/sql/connect/common/src/test/resources/query-tests/explain-results/function_current_time.explain
new file mode 100644
index 000000000000..3115ec11b3fc
--- /dev/null
+++ 
b/sql/connect/common/src/test/resources/query-tests/explain-results/function_current_time.explain
@@ -0,0 +1,2 @@
+Project [current_time(6, Some(America/Los_Angeles)) AS current_time(6)#0]
++- LocalRelation <empty>, [d#0, t#0, s#0, x#0L, wt#0]
diff --git 
a/sql/connect/common/src/test/resources/query-tests/explain-results/function_current_time_with_precision.explain
 
b/sql/connect/common/src/test/resources/query-tests/explain-results/function_current_time_with_precision.explain
new file mode 100644
index 000000000000..3d9c0a153625
--- /dev/null
+++ 
b/sql/connect/common/src/test/resources/query-tests/explain-results/function_current_time_with_precision.explain
@@ -0,0 +1,2 @@
+Project [current_time(3, Some(America/Los_Angeles)) AS current_time(3)#0]
++- LocalRelation <empty>, [d#0, t#0, s#0, x#0L, wt#0]
diff --git 
a/sql/connect/common/src/test/resources/query-tests/explain-results/function_lit_array.explain
 
b/sql/connect/common/src/test/resources/query-tests/explain-results/function_lit_array.explain
index 0f4ae8813e89..9aeeeea96eae 100644
--- 
a/sql/connect/common/src/test/resources/query-tests/explain-results/function_lit_array.explain
+++ 
b/sql/connect/common/src/test/resources/query-tests/explain-results/function_lit_array.explain
@@ -1,2 +1,2 @@
-Project [[] AS ARRAY()#0, [[1],[2],[3]] AS ARRAY(ARRAY(1), ARRAY(2), 
ARRAY(3))#0, [[[1]],[[2]],[[3]]] AS ARRAY(ARRAY(ARRAY(1)), ARRAY(ARRAY(2)), 
ARRAY(ARRAY(3)))#0, [true,false] AS ARRAY(true, false)#0, 0x434445 AS 
X'434445'#0, [9872,9873,9874] AS ARRAY(9872S, 9873S, 9874S)#0, 
[-8726532,8726532,-8726533] AS ARRAY(-8726532, 8726532, -8726533)#0, 
[7834609328726531,7834609328726532,7834609328726533] AS 
ARRAY(7834609328726531L, 7834609328726532L, 7834609328726533L)#0, 
[2.718281828459045,1.0, [...]
+Project [[] AS ARRAY()#0, [[1],[2],[3]] AS ARRAY(ARRAY(1), ARRAY(2), 
ARRAY(3))#0, [[[1]],[[2]],[[3]]] AS ARRAY(ARRAY(ARRAY(1)), ARRAY(ARRAY(2)), 
ARRAY(ARRAY(3)))#0, [true,false] AS ARRAY(true, false)#0, 0x434445 AS 
X'434445'#0, [9872,9873,9874] AS ARRAY(9872S, 9873S, 9874S)#0, 
[-8726532,8726532,-8726533] AS ARRAY(-8726532, 8726532, -8726533)#0, 
[7834609328726531,7834609328726532,7834609328726533] AS 
ARRAY(7834609328726531L, 7834609328726532L, 7834609328726533L)#0, 
[2.718281828459045,1.0, [...]
 +- LocalRelation <empty>, [id#0L, a#0, b#0]
diff --git 
a/sql/connect/common/src/test/resources/query-tests/explain-results/function_make_time.explain
 
b/sql/connect/common/src/test/resources/query-tests/explain-results/function_make_time.explain
new file mode 100644
index 000000000000..79a60f9a2f97
--- /dev/null
+++ 
b/sql/connect/common/src/test/resources/query-tests/explain-results/function_make_time.explain
@@ -0,0 +1,2 @@
+Project [static_invoke(DateTimeUtils.makeTime(12, 13, cast(14 as 
decimal(16,6)))) AS make_time(12, 13, 14)#0]
++- LocalRelation <empty>, [d#0, t#0, s#0, x#0L, wt#0]
diff --git 
a/sql/connect/common/src/test/resources/query-tests/queries/function_current_time.json
 
b/sql/connect/common/src/test/resources/query-tests/queries/function_current_time.json
new file mode 100644
index 000000000000..f5c7923fa531
--- /dev/null
+++ 
b/sql/connect/common/src/test/resources/query-tests/queries/function_current_time.json
@@ -0,0 +1,38 @@
+{
+  "common": {
+    "planId": "1"
+  },
+  "project": {
+    "input": {
+      "common": {
+        "planId": "0"
+      },
+      "localRelation": {
+        "schema": 
"struct\u003cd:date,t:timestamp,s:string,x:bigint,wt:struct\u003cstart:timestamp,end:timestamp\u003e\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "current_time",
+        "isInternal": false
+      },
+      "common": {
+        "origin": {
+          "jvmOrigin": {
+            "stackTrace": [{
+              "classLoaderName": "app",
+              "declaringClass": "org.apache.spark.sql.functions$",
+              "methodName": "current_time",
+              "fileName": "functions.scala"
+            }, {
+              "classLoaderName": "app",
+              "declaringClass": "org.apache.spark.sql.PlanGenerationTestSuite",
+              "methodName": "~~trimmed~anonfun~~",
+              "fileName": "PlanGenerationTestSuite.scala"
+            }]
+          }
+        }
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git 
a/sql/connect/common/src/test/resources/query-tests/queries/function_current_time.proto.bin
 
b/sql/connect/common/src/test/resources/query-tests/queries/function_current_time.proto.bin
new file mode 100644
index 000000000000..0c5a79cc196a
Binary files /dev/null and 
b/sql/connect/common/src/test/resources/query-tests/queries/function_current_time.proto.bin
 differ
diff --git 
a/sql/connect/common/src/test/resources/query-tests/queries/function_current_time_with_precision.json
 
b/sql/connect/common/src/test/resources/query-tests/queries/function_current_time_with_precision.json
new file mode 100644
index 000000000000..d693b79bc2f7
--- /dev/null
+++ 
b/sql/connect/common/src/test/resources/query-tests/queries/function_current_time_with_precision.json
@@ -0,0 +1,60 @@
+{
+  "common": {
+    "planId": "1"
+  },
+  "project": {
+    "input": {
+      "common": {
+        "planId": "0"
+      },
+      "localRelation": {
+        "schema": 
"struct\u003cd:date,t:timestamp,s:string,x:bigint,wt:struct\u003cstart:timestamp,end:timestamp\u003e\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "current_time",
+        "arguments": [{
+          "literal": {
+            "integer": 3
+          },
+          "common": {
+            "origin": {
+              "jvmOrigin": {
+                "stackTrace": [{
+                  "classLoaderName": "app",
+                  "declaringClass": "org.apache.spark.sql.functions$",
+                  "methodName": "current_time",
+                  "fileName": "functions.scala"
+                }, {
+                  "classLoaderName": "app",
+                  "declaringClass": 
"org.apache.spark.sql.PlanGenerationTestSuite",
+                  "methodName": "~~trimmed~anonfun~~",
+                  "fileName": "PlanGenerationTestSuite.scala"
+                }]
+              }
+            }
+          }
+        }],
+        "isInternal": false
+      },
+      "common": {
+        "origin": {
+          "jvmOrigin": {
+            "stackTrace": [{
+              "classLoaderName": "app",
+              "declaringClass": "org.apache.spark.sql.functions$",
+              "methodName": "current_time",
+              "fileName": "functions.scala"
+            }, {
+              "classLoaderName": "app",
+              "declaringClass": "org.apache.spark.sql.PlanGenerationTestSuite",
+              "methodName": "~~trimmed~anonfun~~",
+              "fileName": "PlanGenerationTestSuite.scala"
+            }]
+          }
+        }
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git 
a/sql/connect/common/src/test/resources/query-tests/queries/function_current_time_with_precision.proto.bin
 
b/sql/connect/common/src/test/resources/query-tests/queries/function_current_time_with_precision.proto.bin
new file mode 100644
index 000000000000..7946d18b17d9
Binary files /dev/null and 
b/sql/connect/common/src/test/resources/query-tests/queries/function_current_time_with_precision.proto.bin
 differ
diff --git 
a/sql/connect/common/src/test/resources/query-tests/queries/function_lit_array.json
 
b/sql/connect/common/src/test/resources/query-tests/queries/function_lit_array.json
index 65902ad604b4..9b77a8bd9b42 100644
--- 
a/sql/connect/common/src/test/resources/query-tests/queries/function_lit_array.json
+++ 
b/sql/connect/common/src/test/resources/query-tests/queries/function_lit_array.json
@@ -859,6 +859,49 @@
           }
         }
       }
+    }, {
+      "literal": {
+        "array": {
+          "elements": [{
+            "time": {
+              "nano": "86399999999999",
+              "precision": 6
+            }
+          }, {
+            "time": {
+              "nano": "43200000000000",
+              "precision": 6
+            }
+          }]
+        },
+        "dataType": {
+          "array": {
+            "elementType": {
+              "time": {
+                "precision": 6
+              }
+            },
+            "containsNull": true
+          }
+        }
+      },
+      "common": {
+        "origin": {
+          "jvmOrigin": {
+            "stackTrace": [{
+              "classLoaderName": "app",
+              "declaringClass": "org.apache.spark.sql.functions$",
+              "methodName": "lit",
+              "fileName": "functions.scala"
+            }, {
+              "classLoaderName": "app",
+              "declaringClass": "org.apache.spark.sql.PlanGenerationTestSuite",
+              "methodName": "~~trimmed~anonfun~~",
+              "fileName": "PlanGenerationTestSuite.scala"
+            }]
+          }
+        }
+      }
     }, {
       "literal": {
         "array": {
diff --git 
a/sql/connect/common/src/test/resources/query-tests/queries/function_lit_array.proto.bin
 
b/sql/connect/common/src/test/resources/query-tests/queries/function_lit_array.proto.bin
index 7e2b7c3bf999..20b6d81c3cee 100644
Binary files 
a/sql/connect/common/src/test/resources/query-tests/queries/function_lit_array.proto.bin
 and 
b/sql/connect/common/src/test/resources/query-tests/queries/function_lit_array.proto.bin
 differ
diff --git 
a/sql/connect/common/src/test/resources/query-tests/queries/function_make_time.json
 
b/sql/connect/common/src/test/resources/query-tests/queries/function_make_time.json
new file mode 100644
index 000000000000..3aaf552d06f7
--- /dev/null
+++ 
b/sql/connect/common/src/test/resources/query-tests/queries/function_make_time.json
@@ -0,0 +1,102 @@
+{
+  "common": {
+    "planId": "1"
+  },
+  "project": {
+    "input": {
+      "common": {
+        "planId": "0"
+      },
+      "localRelation": {
+        "schema": 
"struct\u003cd:date,t:timestamp,s:string,x:bigint,wt:struct\u003cstart:timestamp,end:timestamp\u003e\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "make_time",
+        "arguments": [{
+          "literal": {
+            "integer": 12
+          },
+          "common": {
+            "origin": {
+              "jvmOrigin": {
+                "stackTrace": [{
+                  "classLoaderName": "app",
+                  "declaringClass": "org.apache.spark.sql.functions$",
+                  "methodName": "lit",
+                  "fileName": "functions.scala"
+                }, {
+                  "classLoaderName": "app",
+                  "declaringClass": 
"org.apache.spark.sql.PlanGenerationTestSuite",
+                  "methodName": "~~trimmed~anonfun~~",
+                  "fileName": "PlanGenerationTestSuite.scala"
+                }]
+              }
+            }
+          }
+        }, {
+          "literal": {
+            "integer": 13
+          },
+          "common": {
+            "origin": {
+              "jvmOrigin": {
+                "stackTrace": [{
+                  "classLoaderName": "app",
+                  "declaringClass": "org.apache.spark.sql.functions$",
+                  "methodName": "lit",
+                  "fileName": "functions.scala"
+                }, {
+                  "classLoaderName": "app",
+                  "declaringClass": 
"org.apache.spark.sql.PlanGenerationTestSuite",
+                  "methodName": "~~trimmed~anonfun~~",
+                  "fileName": "PlanGenerationTestSuite.scala"
+                }]
+              }
+            }
+          }
+        }, {
+          "literal": {
+            "integer": 14
+          },
+          "common": {
+            "origin": {
+              "jvmOrigin": {
+                "stackTrace": [{
+                  "classLoaderName": "app",
+                  "declaringClass": "org.apache.spark.sql.functions$",
+                  "methodName": "lit",
+                  "fileName": "functions.scala"
+                }, {
+                  "classLoaderName": "app",
+                  "declaringClass": 
"org.apache.spark.sql.PlanGenerationTestSuite",
+                  "methodName": "~~trimmed~anonfun~~",
+                  "fileName": "PlanGenerationTestSuite.scala"
+                }]
+              }
+            }
+          }
+        }],
+        "isInternal": false
+      },
+      "common": {
+        "origin": {
+          "jvmOrigin": {
+            "stackTrace": [{
+              "classLoaderName": "app",
+              "declaringClass": "org.apache.spark.sql.functions$",
+              "methodName": "make_time",
+              "fileName": "functions.scala"
+            }, {
+              "classLoaderName": "app",
+              "declaringClass": "org.apache.spark.sql.PlanGenerationTestSuite",
+              "methodName": "~~trimmed~anonfun~~",
+              "fileName": "PlanGenerationTestSuite.scala"
+            }]
+          }
+        }
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git 
a/sql/connect/common/src/test/resources/query-tests/queries/function_make_time.proto.bin
 
b/sql/connect/common/src/test/resources/query-tests/queries/function_make_time.proto.bin
new file mode 100644
index 000000000000..170c14951c9d
Binary files /dev/null and 
b/sql/connect/common/src/test/resources/query-tests/queries/function_make_time.proto.bin
 differ
diff --git 
a/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/LiteralExpressionProtoConverterSuite.scala
 
b/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/LiteralExpressionProtoConverterSuite.scala
index 3eab2560bcc1..9c176a7a54f2 100644
--- 
a/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/LiteralExpressionProtoConverterSuite.scala
+++ 
b/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/LiteralExpressionProtoConverterSuite.scala
@@ -17,6 +17,8 @@
 
 package org.apache.spark.sql.connect.planner
 
+import java.time.LocalTime
+
 import org.scalatest.funsuite.AnyFunSuite // scalastyle:ignore funsuite
 
 import org.apache.spark.connect.proto
@@ -53,6 +55,28 @@ class LiteralExpressionProtoConverterSuite extends 
AnyFunSuite { // scalastyle:i
     }
   }
 
+  test("SPARK-57566: TIME literal proto and catalyst value round-trip") {
+    val times =
+      Seq(LocalTime.of(0, 0, 0), LocalTime.of(12, 13, 14), LocalTime.of(23, 
59, 59, 999999999))
+    for (t <- times) {
+      val literalProto = toLiteralProto(t, TimeType())
+      // The literal carries the TIME proto type with the expected precision.
+      assert(literalProto.getTime.getPrecision == TimeType.DEFAULT_PRECISION)
+      // Proto -> Scala value round-trips back to the original LocalTime.
+      assertResult(t)(LiteralValueProtoConverter.toScalaValue(literalProto))
+      // Proto -> Catalyst expression matches a directly-built catalyst 
literal.
+      val convert = 
CatalystTypeConverters.createToCatalystConverter(TimeType())
+      val expected = expressions.Literal(convert(t), TimeType())
+      
assertResult(expected)(LiteralExpressionProtoConverter.toCatalystExpression(literalProto))
+    }
+  }
+
+  test("SPARK-57566: TIME literal proto propagates a non-default precision") {
+    val literalProto = toLiteralProto(LocalTime.of(1, 2, 3), TimeType(3))
+    assert(literalProto.getTime.getPrecision == 3)
+    assertResult(LocalTime.of(1, 2, 
3))(LiteralValueProtoConverter.toScalaValue(literalProto))
+  }
+
   // The goal of this test is to check that converting a Scala value -> Proto 
-> Catalyst value
   // is equivalent to converting a Scala value directly to a Catalyst value.
   Seq[(Any, DataType)](


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

Reply via email to