You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@paimon.apache.org by lz...@apache.org on 2024/01/15 03:39:08 UTC

(incubator-paimon) branch master updated: [hive] Support 'timestamp with local time zone' for Hive (#2685)

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

lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 0c0ab1b62 [hive] Support 'timestamp with local time zone' for Hive (#2685)
0c0ab1b62 is described below

commit 0c0ab1b62d56d2d93ba82e76dd470ed27973b4e7
Author: yuzelin <33...@users.noreply.github.com>
AuthorDate: Mon Jan 15 11:39:04 2024 +0800

    [hive] Support 'timestamp with local time zone' for Hive (#2685)
---
 .../apache/paimon/format/FormatReadWriteTest.java  |   4 +
 .../paimon/format/avro/AvroSchemaVisitor.java      |   2 +
 .../java/org/apache/paimon/hive/HiveTypeUtils.java |   6 +-
 .../paimon/hive/LocalZonedTimestampTypeUtils.java  |  36 ++++++++
 .../paimon/hive/LocalZonedTimestampTypeUtils.java  |  40 ++++++++
 .../PaimonTimestampLocalTZObjectInspector.java     |  81 ++++++++++++++++
 .../org/apache/paimon/hive/HiveWriteITCase.java    |  38 ++++++++
 .../PaimonTimestampLocalTZObjectInspectorTest.java | 102 +++++++++++++++++++++
 .../PaimonObjectInspectorFactory.java              |   2 +
 .../PaimonTimestampLocalTZObjectInspector.java     |  22 +++++
 .../paimon/hive/RandomGenericRowDataGenerator.java |   5 +
 .../PaimonInternalRowObjectInspectorTest.java      |   2 +
 12 files changed, 339 insertions(+), 1 deletion(-)

diff --git a/paimon-common/src/test/java/org/apache/paimon/format/FormatReadWriteTest.java b/paimon-common/src/test/java/org/apache/paimon/format/FormatReadWriteTest.java
index 5fe11ae01..400ef1109 100644
--- a/paimon-common/src/test/java/org/apache/paimon/format/FormatReadWriteTest.java
+++ b/paimon-common/src/test/java/org/apache/paimon/format/FormatReadWriteTest.java
@@ -149,6 +149,8 @@ public abstract class FormatReadWriteTest {
                         .field("bytes", DataTypes.BYTES())
                         .field("timestamp", DataTypes.TIMESTAMP())
                         .field("timestamp_3", DataTypes.TIMESTAMP(3))
+                        .field("timestamp_ltz", DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE())
+                        .field("timestamp_ltz_3", DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(3))
                         .field("date", DataTypes.DATE())
                         .field("decimal", DataTypes.DECIMAL(2, 2))
                         .field("decimal2", DataTypes.DECIMAL(38, 2))
@@ -202,6 +204,8 @@ public abstract class FormatReadWriteTest {
                         new byte[] {1, 5, 2},
                         Timestamp.fromMicros(123123123),
                         Timestamp.fromEpochMillis(123123123),
+                        Timestamp.fromMicros(123123123),
+                        Timestamp.fromEpochMillis(123123123),
                         2456,
                         Decimal.fromBigDecimal(new BigDecimal("0.22"), 2, 2),
                         Decimal.fromBigDecimal(new BigDecimal("12312455.22"), 38, 2),
diff --git a/paimon-format/src/main/java/org/apache/paimon/format/avro/AvroSchemaVisitor.java b/paimon-format/src/main/java/org/apache/paimon/format/avro/AvroSchemaVisitor.java
index 96e2aafa2..f622f6dd1 100644
--- a/paimon-format/src/main/java/org/apache/paimon/format/avro/AvroSchemaVisitor.java
+++ b/paimon-format/src/main/java/org/apache/paimon/format/avro/AvroSchemaVisitor.java
@@ -76,9 +76,11 @@ public interface AvroSchemaVisitor<T> {
                     return visitInt();
 
                 case "timestamp-millis":
+                case "local-timestamp-millis":
                     return visitTimestampMillis(getPrecision(type));
 
                 case "timestamp-micros":
+                case "local-timestamp-micros":
                     return visitTimestampMicros(getPrecision(type));
 
                 case "decimal":
diff --git a/paimon-hive/paimon-hive-common/src/main/java/org/apache/paimon/hive/HiveTypeUtils.java b/paimon-hive/paimon-hive-common/src/main/java/org/apache/paimon/hive/HiveTypeUtils.java
index 79e79cbd5..a0325a948 100644
--- a/paimon-hive/paimon-hive-common/src/main/java/org/apache/paimon/hive/HiveTypeUtils.java
+++ b/paimon-hive/paimon-hive-common/src/main/java/org/apache/paimon/hive/HiveTypeUtils.java
@@ -185,7 +185,7 @@ public class HiveTypeUtils {
 
         @Override
         public TypeInfo visit(LocalZonedTimestampType localZonedTimestampType) {
-            return TypeInfoFactory.timestampTypeInfo;
+            return LocalZonedTimestampTypeUtils.toHiveType(localZonedTimestampType);
         }
 
         @Override
@@ -254,6 +254,10 @@ public class HiveTypeUtils {
         }
 
         public DataType atomic(TypeInfo atomic) {
+            if (LocalZonedTimestampTypeUtils.isLocalZonedTimestampType(atomic)) {
+                return DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE();
+            }
+
             if (TypeInfoFactory.booleanTypeInfo.equals(atomic)) {
                 return DataTypes.BOOLEAN();
             } else if (TypeInfoFactory.byteTypeInfo.equals(atomic)) {
diff --git a/paimon-hive/paimon-hive-common/src/main/java/org/apache/paimon/hive/LocalZonedTimestampTypeUtils.java b/paimon-hive/paimon-hive-common/src/main/java/org/apache/paimon/hive/LocalZonedTimestampTypeUtils.java
new file mode 100644
index 000000000..fe76debfc
--- /dev/null
+++ b/paimon-hive/paimon-hive-common/src/main/java/org/apache/paimon/hive/LocalZonedTimestampTypeUtils.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.hive;
+
+import org.apache.paimon.types.LocalZonedTimestampType;
+
+import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
+import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory;
+
+/** To maintain compatibility with Hive 3. */
+public class LocalZonedTimestampTypeUtils {
+
+    public static boolean isLocalZonedTimestampType(TypeInfo hiveTypeInfo) {
+        return false;
+    }
+
+    public static TypeInfo toHiveType(LocalZonedTimestampType paimonType) {
+        return TypeInfoFactory.timestampTypeInfo;
+    }
+}
diff --git a/paimon-hive/paimon-hive-connector-3.1/src/main/java/org/apache/paimon/hive/LocalZonedTimestampTypeUtils.java b/paimon-hive/paimon-hive-connector-3.1/src/main/java/org/apache/paimon/hive/LocalZonedTimestampTypeUtils.java
new file mode 100644
index 000000000..b7c5d26ae
--- /dev/null
+++ b/paimon-hive/paimon-hive-connector-3.1/src/main/java/org/apache/paimon/hive/LocalZonedTimestampTypeUtils.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.hive;
+
+import org.apache.paimon.types.LocalZonedTimestampType;
+
+import org.apache.hadoop.hive.serde2.typeinfo.TimestampLocalTZTypeInfo;
+import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
+import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory;
+
+/**
+ * Utils to convert between Hive {@link TimestampLocalTZTypeInfo} and Paimon {@link
+ * LocalZonedTimestampType}.
+ */
+public class LocalZonedTimestampTypeUtils {
+
+    public static boolean isLocalZonedTimestampType(TypeInfo hiveTypeInfo) {
+        return hiveTypeInfo instanceof TimestampLocalTZTypeInfo;
+    }
+
+    public static TypeInfo toHiveType(LocalZonedTimestampType paimonType) {
+        return TypeInfoFactory.timestampLocalTZTypeInfo;
+    }
+}
diff --git a/paimon-hive/paimon-hive-connector-3.1/src/main/java/org/apache/paimon/hive/objectinspector/PaimonTimestampLocalTZObjectInspector.java b/paimon-hive/paimon-hive-connector-3.1/src/main/java/org/apache/paimon/hive/objectinspector/PaimonTimestampLocalTZObjectInspector.java
new file mode 100644
index 000000000..27af89e90
--- /dev/null
+++ b/paimon-hive/paimon-hive-connector-3.1/src/main/java/org/apache/paimon/hive/objectinspector/PaimonTimestampLocalTZObjectInspector.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.hive.objectinspector;
+
+import org.apache.paimon.data.Timestamp;
+
+import org.apache.hadoop.hive.common.type.TimestampTZ;
+import org.apache.hadoop.hive.serde2.io.TimestampLocalTZWritable;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.AbstractPrimitiveJavaObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.primitive.TimestampLocalTZObjectInspector;
+import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory;
+
+import java.time.ZoneId;
+
+/**
+ * {@link AbstractPrimitiveJavaObjectInspector} for TIMESTAMP WITH LOCAL TIME ZONE type. The
+ * precision is maintained.
+ */
+public class PaimonTimestampLocalTZObjectInspector extends AbstractPrimitiveJavaObjectInspector
+        implements TimestampLocalTZObjectInspector, WriteableObjectInspector {
+
+    public PaimonTimestampLocalTZObjectInspector() {
+        super(TypeInfoFactory.timestampLocalTZTypeInfo);
+    }
+
+    @Override
+    public TimestampTZ getPrimitiveJavaObject(Object o) {
+        if (o == null) {
+            return null;
+        }
+
+        return new TimestampTZ(((Timestamp) o).toLocalDateTime().atZone(ZoneId.systemDefault()));
+    }
+
+    @Override
+    public TimestampLocalTZWritable getPrimitiveWritableObject(Object o) {
+        TimestampTZ timestampTZ = getPrimitiveJavaObject(o);
+        return timestampTZ == null ? null : new TimestampLocalTZWritable(timestampTZ);
+    }
+
+    @Override
+    public Object copyObject(Object o) {
+        if (o instanceof Timestamp) {
+            // immutable
+            return o;
+        } else if (o instanceof TimestampTZ) {
+            return new TimestampTZ(((TimestampTZ) o).getZonedDateTime());
+        } else {
+            return o;
+        }
+    }
+
+    @Override
+    public Timestamp convert(Object value) {
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof TimestampTZ) {
+            return Timestamp.fromLocalDateTime(
+                    ((TimestampTZ) value).getZonedDateTime().toLocalDateTime());
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/HiveWriteITCase.java b/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/HiveWriteITCase.java
index 1fd39dd94..0674d8a62 100644
--- a/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/HiveWriteITCase.java
+++ b/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/HiveWriteITCase.java
@@ -46,6 +46,7 @@ import org.junit.runner.RunWith;
 
 import javax.annotation.Nullable;
 
+import java.time.ZoneId;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -199,4 +200,41 @@ public class HiveWriteITCase {
         assertThat(select)
                 .containsExactly(String.format("1\t2023-01-13 20:00:01%s\t2023-12-23", fraction));
     }
+
+    @Test
+    public void testInsertLocalZonedTimestamp() throws Exception {
+        List<InternalRow> emptyData = Collections.emptyList();
+
+        // test different precisions
+        int precision = ThreadLocalRandom.current().nextInt(3, 10);
+        String fraction = "." + "123456789".substring(0, precision);
+
+        String outputTableName =
+                createAppendOnlyExternalTable(
+                        RowType.of(
+                                new DataType[] {
+                                    DataTypes.INT(),
+                                    DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(precision),
+                                },
+                                new String[] {
+                                    "pt", "ltz",
+                                }),
+                        Collections.singletonList("pt"),
+                        emptyData,
+                        "hive_test_table_output",
+                        CoreOptions.FileFormatType.ORC);
+
+        assertThat(hiveShell.executeQuery("SHOW CREATE TABLE " + outputTableName))
+                .contains("  `ltz` timestamp with local time zone COMMENT 'from deserializer')");
+
+        hiveShell.execute(
+                String.format(
+                        "INSERT INTO %s VALUES (1, '2023-01-12 20:00:01%s')",
+                        outputTableName, fraction));
+
+        assertThat(hiveShell.executeQuery("SELECT * FROM " + outputTableName))
+                .containsExactly(
+                        String.format(
+                                "1\t2023-01-12 20:00:01%s %s", fraction, ZoneId.systemDefault()));
+    }
 }
diff --git a/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/objectinspector/PaimonTimestampLocalTZObjectInspectorTest.java b/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/objectinspector/PaimonTimestampLocalTZObjectInspectorTest.java
new file mode 100644
index 000000000..23932dddc
--- /dev/null
+++ b/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/objectinspector/PaimonTimestampLocalTZObjectInspectorTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.hive.objectinspector;
+
+import org.apache.paimon.data.Timestamp;
+
+import org.apache.hadoop.hive.common.type.TimestampTZ;
+import org.apache.hadoop.hive.serde2.io.TimestampLocalTZWritable;
+import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Tests for {@link PaimonTimestampLocalTZObjectInspector}. */
+public class PaimonTimestampLocalTZObjectInspectorTest {
+
+    @Test
+    public void testCategoryAndClass() {
+        PaimonTimestampLocalTZObjectInspector oi = new PaimonTimestampLocalTZObjectInspector();
+
+        assertThat(oi.getCategory()).isEqualTo(ObjectInspector.Category.PRIMITIVE);
+        assertThat(oi.getPrimitiveCategory())
+                .isEqualTo(PrimitiveObjectInspector.PrimitiveCategory.TIMESTAMPLOCALTZ);
+
+        assertThat(oi.getJavaPrimitiveClass()).isEqualTo(TimestampTZ.class);
+        assertThat(oi.getPrimitiveWritableClass()).isEqualTo(TimestampLocalTZWritable.class);
+    }
+
+    @Test
+    public void testGetPrimitiveJavaObject() {
+        PaimonTimestampLocalTZObjectInspector oi = new PaimonTimestampLocalTZObjectInspector();
+
+        LocalDateTime now = LocalDateTime.now().plusNanos(123);
+        Timestamp input = Timestamp.fromLocalDateTime(now);
+        TimestampTZ expected = new TimestampTZ(now.atZone(ZoneId.systemDefault()));
+        assertThat(oi.getPrimitiveJavaObject(input)).isEqualTo(expected);
+
+        assertThat(oi.getPrimitiveJavaObject(null)).isNull();
+    }
+
+    @Test
+    public void testGetPrimitiveWritableObject() {
+        PaimonTimestampLocalTZObjectInspector oi = new PaimonTimestampLocalTZObjectInspector();
+
+        LocalDateTime now = LocalDateTime.now().plusNanos(123);
+        Timestamp input = Timestamp.fromLocalDateTime(now);
+        TimestampTZ expected = new TimestampTZ(now.atZone(ZoneId.systemDefault()));
+        assertThat(oi.getPrimitiveWritableObject(input).getTimestampTZ()).isEqualTo(expected);
+
+        assertThat(oi.getPrimitiveWritableObject(null)).isNull();
+    }
+
+    @Test
+    public void testCopyObject() {
+        PaimonTimestampLocalTZObjectInspector oi = new PaimonTimestampLocalTZObjectInspector();
+
+        // TimestampData is immutable
+        Timestamp input1 = Timestamp.fromEpochMillis(10007);
+        Object copy1 = oi.copyObject(input1);
+        assertThat(copy1).isEqualTo(input1);
+
+        TimestampTZ input2 =
+                new TimestampTZ(input1.toLocalDateTime().atZone(ZoneId.systemDefault()));
+        Object copy2 = oi.copyObject(input2);
+        assertThat(copy2).isEqualTo(input2);
+        assertThat(copy2).isNotSameAs(input2);
+
+        assertThat(oi.copyObject(null)).isNull();
+    }
+
+    @Test
+    public void testConvertObject() {
+        PaimonTimestampLocalTZObjectInspector oi = new PaimonTimestampLocalTZObjectInspector();
+
+        LocalDateTime now = LocalDateTime.now().plusNanos(123);
+        Timestamp expected = Timestamp.fromLocalDateTime(now);
+        TimestampTZ input = new TimestampTZ(now.atZone(ZoneId.systemDefault()));
+        assertThat(oi.convert(input)).isEqualTo(expected);
+
+        assertThat(oi.convert(null)).isNull();
+    }
+}
diff --git a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonObjectInspectorFactory.java b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonObjectInspectorFactory.java
index fd556b54e..f3beef05a 100644
--- a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonObjectInspectorFactory.java
+++ b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonObjectInspectorFactory.java
@@ -76,6 +76,8 @@ public class PaimonObjectInspectorFactory {
                 return new PaimonTimeObjectInspector();
             case TIMESTAMP_WITHOUT_TIME_ZONE:
                 return new PaimonTimestampObjectInspector();
+            case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+                return new PaimonTimestampLocalTZObjectInspector();
             case ARRAY:
                 ArrayType arrayType = (ArrayType) logicalType;
                 return new PaimonListObjectInspector(arrayType.getElementType());
diff --git a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonTimestampLocalTZObjectInspector.java b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonTimestampLocalTZObjectInspector.java
new file mode 100644
index 000000000..3bec6ba7e
--- /dev/null
+++ b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonTimestampLocalTZObjectInspector.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package org.apache.paimon.hive.objectinspector;
+
+/** To maintain compatibility with Hive 3. */
+public class PaimonTimestampLocalTZObjectInspector extends PaimonTimestampObjectInspector {}
diff --git a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/RandomGenericRowDataGenerator.java b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/RandomGenericRowDataGenerator.java
index 9fb846a6b..2035552cc 100644
--- a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/RandomGenericRowDataGenerator.java
+++ b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/RandomGenericRowDataGenerator.java
@@ -59,6 +59,7 @@ public class RandomGenericRowDataGenerator {
                     DataTypes.DATE(),
                     DataTypes.TIME(),
                     DataTypes.TIMESTAMP(3),
+                    DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(3),
                     DataTypes.ARRAY(DataTypes.BIGINT()),
                     DataTypes.MAP(DataTypes.STRING(), DataTypes.INT()));
 
@@ -80,6 +81,7 @@ public class RandomGenericRowDataGenerator {
                     "date",
                     "string",
                     "timestamp",
+                    "timestamp",
                     "array<bigint>",
                     "map<string,int>");
 
@@ -101,6 +103,7 @@ public class RandomGenericRowDataGenerator {
                     "f_date",
                     "f_time",
                     "f_timestamp",
+                    "f_timestamp_ltz",
                     "f_list_long",
                     "f_map_string_int");
 
@@ -122,6 +125,7 @@ public class RandomGenericRowDataGenerator {
                     "comment_date",
                     "comment_time",
                     "comment_timestamp",
+                    "comment_timestamp_ltz",
                     "comment_list_long",
                     "comment_map_string_int");
 
@@ -172,6 +176,7 @@ public class RandomGenericRowDataGenerator {
                         random.nextInt(10000),
                         random.nextInt(86400),
                         Timestamp.fromEpochMillis(random.nextLong(Integer.MAX_VALUE)),
+                        Timestamp.fromEpochMillis(random.nextLong(Integer.MAX_VALUE)),
                         new GenericArray(randomLongArray),
                         new GenericMap(randomMap));
         for (int i = 0; i < rowData.getFieldCount(); i++) {
diff --git a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/objectinspector/PaimonInternalRowObjectInspectorTest.java b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/objectinspector/PaimonInternalRowObjectInspectorTest.java
index 9930a62ce..594c83250 100644
--- a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/objectinspector/PaimonInternalRowObjectInspectorTest.java
+++ b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/objectinspector/PaimonInternalRowObjectInspectorTest.java
@@ -60,6 +60,7 @@ public class PaimonInternalRowObjectInspectorTest {
                         ObjectInspector.Category.PRIMITIVE,
                         ObjectInspector.Category.PRIMITIVE,
                         ObjectInspector.Category.PRIMITIVE,
+                        ObjectInspector.Category.PRIMITIVE,
                         ObjectInspector.Category.LIST,
                         ObjectInspector.Category.MAP);
 
@@ -100,6 +101,7 @@ public class PaimonInternalRowObjectInspectorTest {
                                         "f_date:date",
                                         "f_time:string",
                                         "f_timestamp:timestamp",
+                                        "f_timestamp_ltz:timestamp",
                                         "f_list_long:array<bigint>",
                                         "f_map_string_int:map<string,int>"))
                         + ">";