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

parthchandra pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git


The following commit(s) were added to refs/heads/main by this push:
     new bf18cec52f feat: Implement TimeType support - Infrastructure - shuffle 
(#4398)
bf18cec52f is described below

commit bf18cec52fbbbb0528754a5900f39c9ffbb1d3e5
Author: Bolin Lin <[email protected]>
AuthorDate: Fri Jul 17 12:05:15 2026 -0400

    feat: Implement TimeType support - Infrastructure - shuffle (#4398)
    
    * feat: support native shuffle for timetype
    
    * feat: support columnar shuffle
    
    * feat: support TimeType in list shuffle serialization
    
    * feat: support TimeType hash partitioning
    
    * test: cover JVM TimeType range partitioning
    
    * test: refine make_time shuffle coverage
---
 native/shuffle/src/spark_unsafe/list.rs            |  8 ++-
 native/shuffle/src/spark_unsafe/row.rs             | 36 +++++++++++-
 native/spark-expr/src/hash_funcs/utils.rs          | 17 ++++++
 .../comet/codegen/CometBatchKernelCodegen.scala    |  6 +-
 .../codegen/CometBatchKernelCodegenInput.scala     | 15 ++++-
 .../codegen/CometBatchKernelCodegenOutput.scala    |  8 ++-
 .../shuffle/CometShuffleExchangeExec.scala         |  6 ++
 .../sql-tests/expressions/datetime/make_time.sql   | 13 ++---
 .../expressions/datetime/make_time_shuffle.sql     | 64 ++++++++++++++++++++++
 .../make_time_shuffle_range_partition_jvm.sql      | 34 ++++++++++++
 .../make_time_shuffle_range_partition_native.sql   | 34 ++++++++++++
 11 files changed, 227 insertions(+), 14 deletions(-)

diff --git a/native/shuffle/src/spark_unsafe/list.rs 
b/native/shuffle/src/spark_unsafe/list.rs
index 14f9feb843..22dce2cf79 100644
--- a/native/shuffle/src/spark_unsafe/list.rs
+++ b/native/shuffle/src/spark_unsafe/list.rs
@@ -24,7 +24,8 @@ use arrow::array::{
     builder::{
         ArrayBuilder, BinaryBuilder, BooleanBuilder, Date32Builder, 
Decimal128Builder,
         Float32Builder, Float64Builder, Int16Builder, Int32Builder, 
Int64Builder, Int8Builder,
-        ListBuilder, NullBuilder, StringBuilder, StructBuilder, 
TimestampMicrosecondBuilder,
+        ListBuilder, NullBuilder, StringBuilder, StructBuilder, 
Time64NanosecondBuilder,
+        TimestampMicrosecondBuilder,
     },
     MapBuilder,
 };
@@ -179,6 +180,7 @@ impl SparkUnsafeArray {
 
     impl_append_to_builder!(append_ints_to_builder, Int32Builder, i32);
     impl_append_to_builder!(append_longs_to_builder, Int64Builder, i64);
+    impl_append_to_builder!(append_time64s_to_builder, 
Time64NanosecondBuilder, i64);
     impl_append_to_builder!(append_shorts_to_builder, Int16Builder, i16);
     impl_append_to_builder!(append_bytes_to_builder, Int8Builder, i8);
     impl_append_to_builder!(append_floats_to_builder, Float32Builder, f32);
@@ -377,6 +379,10 @@ pub fn append_to_builder<const NULLABLE: bool>(
             let builder = downcast_builder_ref!(Int64Builder, builder);
             array.append_longs_to_builder::<NULLABLE>(builder);
         }
+        DataType::Time64(TimeUnit::Nanosecond) => {
+            let builder = downcast_builder_ref!(Time64NanosecondBuilder, 
builder);
+            array.append_time64s_to_builder::<NULLABLE>(builder);
+        }
         DataType::Float32 => {
             let builder = downcast_builder_ref!(Float32Builder, builder);
             array.append_floats_to_builder::<NULLABLE>(builder);
diff --git a/native/shuffle/src/spark_unsafe/row.rs 
b/native/shuffle/src/spark_unsafe/row.rs
index 449371463d..e0ebf8e7d0 100644
--- a/native/shuffle/src/spark_unsafe/row.rs
+++ b/native/shuffle/src/spark_unsafe/row.rs
@@ -29,7 +29,8 @@ use arrow::array::{
         ArrayBuilder, BinaryBuilder, BinaryDictionaryBuilder, BooleanBuilder, 
Date32Builder,
         Decimal128Builder, Float32Builder, Float64Builder, Int16Builder, 
Int32Builder,
         Int64Builder, Int8Builder, ListBuilder, MapBuilder, NullBuilder, 
StringBuilder,
-        StringDictionaryBuilder, StructBuilder, TimestampMicrosecondBuilder,
+        StringDictionaryBuilder, StructBuilder, Time64NanosecondBuilder,
+        TimestampMicrosecondBuilder,
     },
     types::Int32Type,
     Array, ArrayRef, RecordBatch, RecordBatchOptions,
@@ -278,6 +279,12 @@ pub(super) fn append_field(
                     .append_value(row.get_timestamp(idx))
             );
         }
+        DataType::Time64(TimeUnit::Nanosecond) => {
+            append_field_to_builder!(
+                Time64NanosecondBuilder,
+                |builder: &mut Time64NanosecondBuilder| 
builder.append_value(row.get_long(idx))
+            );
+        }
         DataType::Binary => {
             append_field_to_builder!(BinaryBuilder, |builder: &mut 
BinaryBuilder| builder
                 .append_value(row.get_binary(idx)));
@@ -439,6 +446,13 @@ fn append_nested_struct_fields_field_major(
                     |row: &SparkUnsafeRow, idx| row.get_timestamp(idx)
                 );
             }
+            DataType::Time64(TimeUnit::Nanosecond) => {
+                process_field!(
+                    Time64NanosecondBuilder,
+                    field_idx,
+                    |row: &SparkUnsafeRow, idx| row.get_long(idx)
+                );
+            }
             DataType::Binary => {
                 let field_builder = get_field_builder!(struct_builder, 
BinaryBuilder, field_idx);
 
@@ -656,6 +670,9 @@ fn append_list_column_batch(
         DataType::Timestamp(TimeUnit::Microsecond, _) => {
             process_primitive_lists!(TimestampMicrosecondBuilder, 
append_timestamps_to_builder);
         }
+        DataType::Time64(TimeUnit::Nanosecond) => {
+            process_primitive_lists!(Time64NanosecondBuilder, 
append_time64s_to_builder);
+        }
         // For complex element types, fall back to per-row dispatch
         _ => {
             for i in row_start..row_end {
@@ -880,6 +897,13 @@ fn append_struct_fields_field_major(
                     |row: &SparkUnsafeRow, idx| row.get_timestamp(idx)
                 );
             }
+            DataType::Time64(TimeUnit::Nanosecond) => {
+                process_field!(
+                    Time64NanosecondBuilder,
+                    field_idx,
+                    |row: &SparkUnsafeRow, idx| row.get_long(idx)
+                );
+            }
             DataType::Binary => {
                 let field_builder = get_field_builder!(struct_builder, 
BinaryBuilder, field_idx);
 
@@ -1165,6 +1189,13 @@ fn append_columns(
                     .append_value(row.get_timestamp(idx))
             );
         }
+        DataType::Time64(TimeUnit::Nanosecond) => {
+            append_column_to_builder!(
+                Time64NanosecondBuilder,
+                |builder: &mut Time64NanosecondBuilder, row: &SparkUnsafeRow, 
idx| builder
+                    .append_value(row.get_long(idx))
+            );
+        }
         DataType::Map(field, _) => {
             let map_builder = downcast_builder_ref!(
                 MapBuilder<Box<dyn ArrayBuilder>, Box<dyn ArrayBuilder>>,
@@ -1266,6 +1297,9 @@ fn make_builders(
         DataType::Timestamp(TimeUnit::Microsecond, _) => {
             
Box::new(TimestampMicrosecondBuilder::with_capacity(row_num).with_data_type(dt.clone()))
         }
+        DataType::Time64(TimeUnit::Nanosecond) => {
+            Box::new(Time64NanosecondBuilder::with_capacity(row_num))
+        }
         DataType::Map(field, _) => {
             let (key_field, value_field, map_field_names) = 
get_map_key_value_fields(field)?;
             let key_dt = key_field.data_type();
diff --git a/native/spark-expr/src/hash_funcs/utils.rs 
b/native/spark-expr/src/hash_funcs/utils.rs
index d634b27bf8..979f787b59 100644
--- a/native/spark-expr/src/hash_funcs/utils.rs
+++ b/native/spark-expr/src/hash_funcs/utils.rs
@@ -380,6 +380,10 @@ macro_rules! hash_list_with_primitive_elements {
                 let elem_array = 
$values.as_any().downcast_ref::<TimestampMicrosecondArray>().unwrap();
                 $crate::hash_list_primitive!(offsets: $offsets, $list_array, 
elem_array, $hashes_buffer, $hash_method, |v: i64| v.to_le_bytes());
             }
+            DataType::Time64(TimeUnit::Nanosecond) => {
+                let elem_array = 
$values.as_any().downcast_ref::<Time64NanosecondArray>().unwrap();
+                $crate::hash_list_primitive!(offsets: $offsets, $list_array, 
elem_array, $hashes_buffer, $hash_method, |v: i64| v.to_le_bytes());
+            }
             _ => {
                 // Fall back to recursive approach for complex element types
                 $crate::hash_list_array!($list_array_type, 
$fallback_offset_type, $col, $hashes_buffer, $recursive_hash_method);
@@ -471,6 +475,10 @@ macro_rules! hash_list_with_primitive_elements {
                 let elem_array = 
$values.as_any().downcast_ref::<TimestampMicrosecondArray>().unwrap();
                 $crate::hash_list_primitive!(fixed_size: $list_size, 
$list_array, elem_array, $hashes_buffer, $hash_method, |v: i64| 
v.to_le_bytes());
             }
+            DataType::Time64(TimeUnit::Nanosecond) => {
+                let elem_array = 
$values.as_any().downcast_ref::<Time64NanosecondArray>().unwrap();
+                $crate::hash_list_primitive!(fixed_size: $list_size, 
$list_array, elem_array, $hashes_buffer, $hash_method, |v: i64| 
v.to_le_bytes());
+            }
             _ => {
                 // Fall back to recursive approach for complex element types
                 if $list_array.null_count() == 0 {
@@ -689,6 +697,15 @@ macro_rules! create_hashes_internal {
                         $hash_method
                     );
                 }
+                DataType::Time64(TimeUnit::Nanosecond) => {
+                    $crate::hash_array_primitive!(
+                        Time64NanosecondArray,
+                        col,
+                        i64,
+                        $hashes_buffer,
+                        $hash_method
+                    );
+                }
                 DataType::Utf8 => {
                     $crate::hash_array!(StringArray, col, $hashes_buffer, 
$hash_method);
                 }
diff --git 
a/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegen.scala 
b/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegen.scala
index 107fb5e7f8..f56f95d065 100644
--- 
a/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegen.scala
+++ 
b/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegen.scala
@@ -28,7 +28,7 @@ import org.apache.spark.sql.catalyst.expressions.codegen._
 import org.apache.spark.sql.internal.SQLConf
 import org.apache.spark.sql.types._
 
-import org.apache.comet.shims.CometExprTraitShim
+import org.apache.comet.shims.{CometExprTraitShim, CometTypeShim}
 
 /**
  * Compiles a bound [[Expression]] plus an Arrow input schema into a 
[[CometBatchKernel]] that
@@ -49,7 +49,7 @@ import org.apache.comet.shims.CometExprTraitShim
  * The generated kernel is the `InternalRow` that Spark's 
`BoundReference.genCode` reads from. See
  * [[generateSource]] for how the wiring is set up.
  */
-object CometBatchKernelCodegen extends Logging with CometExprTraitShim {
+object CometBatchKernelCodegen extends Logging with CometExprTraitShim with 
CometTypeShim {
 
   /**
    * Resolve an Arrow vector class by simple name through the codegen object's 
own classloader.
@@ -67,6 +67,7 @@ object CometBatchKernelCodegen extends Logging with 
CometExprTraitShim {
     case "Float8Vector" => classOf[Float8Vector]
     case "DecimalVector" => classOf[DecimalVector]
     case "DateDayVector" => classOf[DateDayVector]
+    case "TimeNanoVector" => classOf[TimeNanoVector]
     case "TimeStampMicroVector" => classOf[TimeStampMicroVector]
     case "TimeStampMicroTZVector" => classOf[TimeStampMicroTZVector]
     case "VarCharVector" => classOf[VarCharVector]
@@ -86,6 +87,7 @@ object CometBatchKernelCodegen extends Logging with 
CometExprTraitShim {
     case _: DecimalType => true
     case _: StringType | _: BinaryType => true
     case DateType | TimestampType | TimestampNTZType => true
+    case dt if isTimeType(dt) => true
     case _: YearMonthIntervalType | _: DayTimeIntervalType => true
     case ArrayType(inner, _) => isSupportedDataType(inner)
     case st: StructType => st.fields.forall(f => 
isSupportedDataType(f.dataType))
diff --git 
a/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegenInput.scala
 
b/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegenInput.scala
index 09bfc52bd4..f31c712c62 100644
--- 
a/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegenInput.scala
+++ 
b/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegenInput.scala
@@ -27,6 +27,7 @@ import 
org.apache.spark.sql.catalyst.expressions.{BoundReference, Expression}
 import org.apache.spark.sql.types._
 
 import org.apache.comet.codegen.CometBatchKernelCodegen.{ArrayColumnSpec, 
ArrowColumnSpec, MapColumnSpec, ScalarColumnSpec, StructColumnSpec}
+import org.apache.comet.shims.CometTypeShim
 import org.apache.comet.vector.CometPlainVector
 
 /**
@@ -44,7 +45,7 @@ import org.apache.comet.vector.CometPlainVector
  * stashing references in an `OpenHashSet`) get distinct identities, and JIT 
escape analysis
  * usually scalarizes the allocation when the value is consumed locally.
  */
-private[codegen] object CometBatchKernelCodegenInput {
+private[codegen] object CometBatchKernelCodegenInput extends CometTypeShim {
 
   /**
    * Primitive Arrow vector classes wrapped in [[CometPlainVector]] at 
input-cast time so per-row
@@ -61,6 +62,7 @@ private[codegen] object CometBatchKernelCodegenInput {
     classOf[Float4Vector],
     classOf[Float8Vector],
     classOf[DateDayVector],
+    classOf[TimeNanoVector],
     classOf[TimeStampMicroVector],
     classOf[TimeStampMicroTZVector])
   private val cometPlainVectorName: String = classOf[CometPlainVector].getName
@@ -133,6 +135,7 @@ private[codegen] object CometBatchKernelCodegenInput {
     val longCases = withOrd.collect {
       case (ArrowColumnSpec(cls, _), ord)
           if cls == classOf[BigIntVector] ||
+            cls == classOf[TimeNanoVector] ||
             cls == classOf[TimeStampMicroVector] ||
             cls == classOf[TimeStampMicroTZVector] =>
         s"      case $ord: return this.col$ord.getLong(this.rowIdx);"
@@ -592,6 +595,7 @@ private[codegen] object CometBatchKernelCodegenInput {
     case ShortType => s"getShort($idx)"
     case IntegerType | DateType => s"getInt($idx)"
     case LongType | TimestampType | TimestampNTZType => s"getLong($idx)"
+    case dt if isTimeType(dt) => s"getLong($idx)"
     case FloatType => s"getFloat($idx)"
     case DoubleType => s"getDouble($idx)"
     case d: DecimalType => s"getDecimal($idx, ${d.precision}, ${d.scale})"
@@ -697,6 +701,11 @@ private[codegen] object CometBatchKernelCodegenInput {
            |      public long getLong(int i) {
            |        return $childField.getLong(startIndex + i);
            |      }""".stripMargin
+      case dt if isTimeType(dt) =>
+        s"""      @Override
+           |      public long getLong(int i) {
+           |        return $childField.getLong(startIndex + i);
+           |      }""".stripMargin
       case FloatType =>
         s"""      @Override
            |      public float getFloat(int i) {
@@ -847,6 +856,8 @@ private[codegen] object CometBatchKernelCodegenInput {
           s"        case $fi: return ${path}_f$fi.getInt(this.rowIdx);"
         case LongType | TimestampType | TimestampNTZType =>
           s"        case $fi: return ${path}_f$fi.getLong(this.rowIdx);"
+        case dt if isTimeType(dt) =>
+          s"        case $fi: return ${path}_f$fi.getLong(this.rowIdx);"
         case FloatType =>
           s"        case $fi: return ${path}_f$fi.getFloat(this.rowIdx);"
         case DoubleType =>
@@ -897,7 +908,7 @@ private[codegen] object CometBatchKernelCodegenInput {
     val longCases = scalarOrd.collect {
       case (f, fi)
           if f.sparkType == LongType || f.sparkType == TimestampType ||
-            f.sparkType == TimestampNTZType =>
+            f.sparkType == TimestampNTZType || isTimeType(f.sparkType) =>
         fieldReadScalar(fi, LongType, f.nullable)
     }
     val floatCases =
diff --git 
a/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegenOutput.scala
 
b/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegenOutput.scala
index fe282cdc65..4160c478d1 100644
--- 
a/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegenOutput.scala
+++ 
b/spark/src/main/scala/org/apache/comet/codegen/CometBatchKernelCodegenOutput.scala
@@ -31,13 +31,14 @@ import org.apache.spark.sql.comet.util.Utils
 import org.apache.spark.sql.types._
 
 import org.apache.comet.CometArrowAllocator
+import org.apache.comet.shims.CometTypeShim
 
 /**
  * Output-side emitters for the codegen kernel: [[allocateOutput]], 
[[emitOutputWriter]]
  * (top-level write entry), [[emitWrite]] (recursive per-type write), the 
output vector-class
  * lookup. Paired with [[CometBatchKernelCodegenInput]] on the read side.
  */
-private[codegen] object CometBatchKernelCodegenOutput {
+private[codegen] object CometBatchKernelCodegenOutput extends CometTypeShim {
 
   /**
    * Spark `DataType` to an Arrow `Field` with names Comet expects on FFI 
export. Spark's
@@ -169,6 +170,7 @@ private[codegen] object CometBatchKernelCodegenOutput {
     case _: StringType => classOf[VarCharVector].getName
     case BinaryType => classOf[VarBinaryVector].getName
     case DateType => classOf[DateDayVector].getName
+    case dt if isTimeType(dt) => classOf[TimeNanoVector].getName
     case TimestampType => classOf[TimeStampMicroTZVector].getName
     case TimestampNTZType => classOf[TimeStampMicroVector].getName
     case _: YearMonthIntervalType => classOf[IntervalYearVector].getName
@@ -216,6 +218,9 @@ private[codegen] object CometBatchKernelCodegenOutput {
       // DayTimeIntervalType -> DurationVector.set(int, long micros).
       val set = if (nested) "setSafe" else "set"
       OutputEmit("", s"$targetVec.$set($idx, $source);")
+    case dt if isTimeType(dt) =>
+      val set = if (nested) "setSafe" else "set"
+      OutputEmit("", s"$targetVec.$set($idx, $source);")
     case dt: DecimalType =>
       // DecimalOutputShortFastPath: precision <= 18 fits in a signed long, so 
pass the unscaled
       // value to `setSafe(int, long)` and skip the BigDecimal allocation.
@@ -398,6 +403,7 @@ private[codegen] object CometBatchKernelCodegenOutput {
       case ShortType => s"$target.getShort($idx)"
       case IntegerType | DateType => s"$target.getInt($idx)"
       case LongType | TimestampType | TimestampNTZType => 
s"$target.getLong($idx)"
+      case dt if isTimeType(dt) => s"$target.getLong($idx)"
       case FloatType => s"$target.getFloat($idx)"
       case DoubleType => s"$target.getDouble($idx)"
       case dt: DecimalType => s"$target.getDecimal($idx, ${dt.precision}, 
${dt.scale})"
diff --git 
a/spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleExchangeExec.scala
 
b/spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleExchangeExec.scala
index 7629c3e59f..c9fe324bd8 100644
--- 
a/spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleExchangeExec.scala
+++ 
b/spark/src/main/scala/org/apache/spark/sql/comet/execution/shuffle/CometShuffleExchangeExec.scala
@@ -397,6 +397,8 @@ object CometShuffleExchangeExec
         // Decimals with precision > 18 require Java BigDecimal conversion 
before hashing
         // d.precision <= 18
         true
+      case dt if isTimeType(dt) =>
+        true
       case _ =>
         false
     }
@@ -412,6 +414,8 @@ object CometShuffleExchangeExec
           _: FloatType | _: DoubleType | _: StringType | _: BinaryType | _: 
TimestampType |
           _: TimestampNTZType | _: DecimalType | _: DateType | _: NullType =>
         true
+      case dt if isTimeType(dt) =>
+        true
       case StructType(fields) =>
         fields.nonEmpty && fields.forall(f => 
supportedSerializableDataType(f.dataType))
       case ArrayType(elementType, _) =>
@@ -535,6 +539,8 @@ object CometShuffleExchangeExec
           _: FloatType | _: DoubleType | _: StringType | _: BinaryType | _: 
TimestampType |
           _: TimestampNTZType | _: DecimalType | _: DateType | _: NullType =>
         true
+      case dt if isTimeType(dt) =>
+        true
       case StructType(fields) =>
         fields.nonEmpty && fields.forall(f => 
supportedSerializableDataType(f.dataType)) &&
         // Java Arrow stream reader cannot work on duplicate field name
diff --git 
a/spark/src/test/resources/sql-tests/expressions/datetime/make_time.sql 
b/spark/src/test/resources/sql-tests/expressions/datetime/make_time.sql
index 8270e8f322..17391712cb 100644
--- a/spark/src/test/resources/sql-tests/expressions/datetime/make_time.sql
+++ b/spark/src/test/resources/sql-tests/expressions/datetime/make_time.sql
@@ -33,17 +33,16 @@ INSERT INTO test_make_time VALUES
   (12, 30, NULL),
   (NULL, NULL, NULL)
 
--- column arguments (spark_answer_only: shuffle does not support TimeType yet; 
TODO: promote to
--- full native-verification once SPARK-51779 lands)
-query spark_answer_only
+-- column arguments (TODO: promote to full native-verification once 
SPARK-51779 lands)
+query
 SELECT hours, minutes, secs, make_time(hours, minutes, secs) FROM 
test_make_time ORDER BY hours, minutes, secs
 
--- literal hour, column minutes and secs (spark_answer_only: shuffle does not 
support TimeType yet)
-query spark_answer_only
+-- literal hour, column minutes and secs
+query
 SELECT make_time(10, minutes, secs) FROM test_make_time ORDER BY minutes, secs
 
--- column hours, literal minutes and secs (spark_answer_only: shuffle does not 
support TimeType yet)
-query spark_answer_only
+-- column hours, literal minutes and secs
+query
 SELECT make_time(hours, 15, 30.5) FROM test_make_time ORDER BY hours
 
 -- all literals
diff --git 
a/spark/src/test/resources/sql-tests/expressions/datetime/make_time_shuffle.sql 
b/spark/src/test/resources/sql-tests/expressions/datetime/make_time_shuffle.sql
new file mode 100644
index 0000000000..024865b904
--- /dev/null
+++ 
b/spark/src/test/resources/sql-tests/expressions/datetime/make_time_shuffle.sql
@@ -0,0 +1,64 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements.  See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership.  The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License.  You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied.  See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+-- MinSparkVersion: 4.1
+-- Config: spark.sql.timeType.enabled=true
+-- Config: spark.comet.native.shuffle.partitioning.roundrobin.enabled=true
+-- ConfigMatrix: spark.comet.exec.shuffle.mode=native,jvm
+
+statement
+CREATE TABLE test_make_time_shuffle(hours int, minutes int, secs 
decimal(16,6)) USING parquet
+
+statement
+INSERT INTO test_make_time_shuffle VALUES (12, 30, 45.123456), (0, 0, 0.0), 
(23, 59, 59.999999), (1, 2, 3.5),
+    (NULL, 0, 0.0), (NULL, NULL, NULL)
+
+query
+SELECT /*+ REPARTITION(3) */ make_time(hours, minutes, secs) AS t FROM 
test_make_time_shuffle
+
+query
+SELECT /*+ REPARTITION(3) */ hours, make_time(hours, minutes, secs) AS t, secs 
FROM test_make_time_shuffle
+
+query
+SELECT /*+ REPARTITION(3) */ named_struct('t', make_time(hours, minutes, 
secs)) AS s FROM test_make_time_shuffle
+
+query
+SELECT /*+ REPARTITION(3) */ array(make_time(hours, minutes, secs)) AS arr 
FROM test_make_time_shuffle
+
+query
+SELECT /*+ REPARTITION(3) */
+    array(make_time(hours, minutes, secs), make_time(0, 0, 0), CAST(NULL AS 
TIME)) AS arr
+FROM test_make_time_shuffle
+
+query
+SELECT /*+ REPARTITION(3) */
+    CASE
+        WHEN hours IS NULL THEN CAST(array() AS ARRAY<TIME>)
+        ELSE array(make_time(hours, minutes, secs), make_time(23, 59, 
59.999999))
+    END AS arr
+FROM test_make_time_shuffle
+
+query
+SELECT /*+ REPARTITION(3) */ map(make_time(hours, minutes, secs), hours) AS m 
FROM test_make_time_shuffle
+WHERE hours IS NOT NULL AND minutes IS NOT NULL AND secs IS NOT NULL
+
+query
+SELECT /*+ REPARTITION(3, t) */ t
+FROM (
+    SELECT make_time(hours, minutes, secs) AS t
+    FROM test_make_time_shuffle
+)
diff --git 
a/spark/src/test/resources/sql-tests/expressions/datetime/make_time_shuffle_range_partition_jvm.sql
 
b/spark/src/test/resources/sql-tests/expressions/datetime/make_time_shuffle_range_partition_jvm.sql
new file mode 100644
index 0000000000..36316adb87
--- /dev/null
+++ 
b/spark/src/test/resources/sql-tests/expressions/datetime/make_time_shuffle_range_partition_jvm.sql
@@ -0,0 +1,34 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements.  See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership.  The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License.  You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied.  See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+-- MinSparkVersion: 4.1
+-- Config: spark.sql.timeType.enabled=true
+-- Config: spark.comet.exec.shuffle.mode=jvm
+
+statement
+CREATE TABLE test_make_time_range_shuffle_jvm(hours int, minutes int, secs 
decimal(16,6)) USING parquet
+
+statement
+INSERT INTO test_make_time_range_shuffle_jvm VALUES
+    (12, 30, 45.123456), (0, 0, 0.0), (23, 59, 59.999999), (NULL, NULL, NULL)
+
+query
+SELECT /*+ REPARTITION_BY_RANGE(3, t) */ t
+FROM (
+    SELECT make_time(hours, minutes, secs) AS t
+    FROM test_make_time_range_shuffle_jvm
+)
diff --git 
a/spark/src/test/resources/sql-tests/expressions/datetime/make_time_shuffle_range_partition_native.sql
 
b/spark/src/test/resources/sql-tests/expressions/datetime/make_time_shuffle_range_partition_native.sql
new file mode 100644
index 0000000000..3627c87fe0
--- /dev/null
+++ 
b/spark/src/test/resources/sql-tests/expressions/datetime/make_time_shuffle_range_partition_native.sql
@@ -0,0 +1,34 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements.  See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership.  The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License.  You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied.  See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+-- MinSparkVersion: 4.1
+-- Config: spark.sql.timeType.enabled=true
+-- Config: spark.comet.exec.shuffle.mode=native
+
+statement
+CREATE TABLE test_make_time_range_shuffle_native(hours int, minutes int, secs 
decimal(16,6)) USING parquet
+
+statement
+INSERT INTO test_make_time_range_shuffle_native VALUES
+    (12, 30, 45.123456), (0, 0, 0.0), (23, 59, 59.999999), (NULL, NULL, NULL)
+
+query expect_fallback(unsupported range partitioning data type for native 
shuffle)
+SELECT /*+ REPARTITION_BY_RANGE(3, t) */ t
+FROM (
+    SELECT make_time(hours, minutes, secs) AS t
+    FROM test_make_time_range_shuffle_native
+)


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

Reply via email to