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 d87ba33e3 [hive] HiveCatalog supports TIME type by converting time to 
string (#1813)
d87ba33e3 is described below

commit d87ba33e3a875f48282987f0c796087afea5cf20
Author: yuzelin <[email protected]>
AuthorDate: Tue Aug 15 21:27:27 2023 +0800

    [hive] HiveCatalog supports TIME type by converting time to string (#1813)
---
 .../java/org/apache/paimon/hive/HiveTypeUtils.java |  6 +++
 .../PaimonObjectInspectorFactory.java              |  7 +++
 .../objectinspector/PaimonTimeObjectInspector.java | 53 +++++++++++++++++++
 .../apache/paimon/hive/HiveCatalogITCaseBase.java  | 26 ----------
 .../paimon/hive/PaimonStorageHandlerITCase.java    | 52 +++++++++++++++++++
 .../paimon/hive/RandomGenericRowDataGenerator.java |  5 ++
 .../PaimonInternalRowObjectInspectorTest.java      |  2 +
 .../PaimonTimeObjectInspectorTest.java             | 60 ++++++++++++++++++++++
 8 files changed, 185 insertions(+), 26 deletions(-)

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 986d6416a..79e79cbd5 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
@@ -37,6 +37,7 @@ import org.apache.paimon.types.MapType;
 import org.apache.paimon.types.MultisetType;
 import org.apache.paimon.types.RowType;
 import org.apache.paimon.types.SmallIntType;
+import org.apache.paimon.types.TimeType;
 import org.apache.paimon.types.TimestampType;
 import org.apache.paimon.types.TinyIntType;
 import org.apache.paimon.types.VarBinaryType;
@@ -172,6 +173,11 @@ public class HiveTypeUtils {
             return TypeInfoFactory.dateTypeInfo;
         }
 
+        @Override
+        public TypeInfo visit(TimeType timeType) {
+            return TypeInfoFactory.stringTypeInfo;
+        }
+
         @Override
         public TypeInfo visit(TimestampType timestampType) {
             return TypeInfoFactory.timestampTypeInfo;
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 b8f798f41..fd556b54e 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
@@ -26,6 +26,7 @@ import org.apache.paimon.types.DataType;
 import org.apache.paimon.types.DecimalType;
 import org.apache.paimon.types.MapType;
 import org.apache.paimon.types.RowType;
+import org.apache.paimon.types.TimeType;
 import org.apache.paimon.types.VarCharType;
 
 import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
@@ -35,6 +36,8 @@ import 
org.apache.hadoop.hive.serde2.typeinfo.PrimitiveTypeInfo;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import static org.apache.paimon.utils.Preconditions.checkArgument;
+
 /** Factory to create {@link ObjectInspector}s according to the given {@link 
DataType}. */
 public class PaimonObjectInspectorFactory {
 
@@ -67,6 +70,10 @@ public class PaimonObjectInspectorFactory {
                 }
             case DATE:
                 return new PaimonDateObjectInspector();
+            case TIME_WITHOUT_TIME_ZONE:
+                TimeType timeType = (TimeType) logicalType;
+                checkArgument(timeType.getPrecision() <= 3, "TIME type 
precision must be <= 3.");
+                return new PaimonTimeObjectInspector();
             case TIMESTAMP_WITHOUT_TIME_ZONE:
                 return new PaimonTimestampObjectInspector();
             case ARRAY:
diff --git 
a/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonTimeObjectInspector.java
 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonTimeObjectInspector.java
new file mode 100644
index 000000000..e81a18afa
--- /dev/null
+++ 
b/paimon-hive/paimon-hive-connector-common/src/main/java/org/apache/paimon/hive/objectinspector/PaimonTimeObjectInspector.java
@@ -0,0 +1,53 @@
+/*
+ * 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.utils.DateTimeUtils;
+
+import 
org.apache.hadoop.hive.serde2.objectinspector.primitive.AbstractPrimitiveJavaObjectInspector;
+import 
org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;
+import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory;
+import org.apache.hadoop.io.Text;
+
+/** {@link AbstractPrimitiveJavaObjectInspector} for TIME type. */
+public class PaimonTimeObjectInspector extends 
AbstractPrimitiveJavaObjectInspector
+        implements StringObjectInspector, WriteableObjectInspector {
+
+    public PaimonTimeObjectInspector() {
+        super(TypeInfoFactory.stringTypeInfo);
+    }
+
+    @Override
+    public String getPrimitiveJavaObject(Object o) {
+        if (o == null) {
+            return null;
+        }
+        return DateTimeUtils.toLocalTime((int) o).toString();
+    }
+
+    @Override
+    public Text getPrimitiveWritableObject(Object o) {
+        return o == null ? null : new Text(getPrimitiveJavaObject(o));
+    }
+
+    @Override
+    public Integer convert(Object value) {
+        return value == null ? null : DateTimeUtils.parseTime((String) value);
+    }
+}
diff --git 
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java
 
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java
index c2ceba3bc..4ebf21136 100644
--- 
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java
+++ 
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java
@@ -27,7 +27,6 @@ import org.apache.paimon.fs.local.LocalFileIO;
 import org.apache.paimon.hive.annotation.Minio;
 import org.apache.paimon.hive.runner.PaimonEmbeddedHiveRunner;
 import org.apache.paimon.s3.MinioTestContainer;
-import org.apache.paimon.table.FileStoreTable;
 
 import com.klarna.hiverunner.HiveShell;
 import com.klarna.hiverunner.annotations.HiveSQL;
@@ -64,7 +63,6 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.UUID;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
@@ -750,30 +748,6 @@ public abstract class HiveCatalogITCaseBase {
         assertThat(tableOptions).doesNotContainKey("lock.enabled");
     }
 
-    @Test
-    public void testClearSchemaAfterUnSupportType()
-            throws InterruptedException, ExecutionException, 
Catalog.TableNotExistException {
-        assertThatThrownBy(
-                        () ->
-                                tEnv.executeSql(
-                                                "CREATE TABLE t001(id INT 
PRIMARY KEY NOT ENFORCED , d TIME)")
-                                        .await())
-                .hasRootCauseInstanceOf(UnsupportedOperationException.class)
-                .hasRootCauseMessage("Unsupported type: TIME(0)");
-        Identifier identifier = new Identifier("test_db", "t001");
-        Catalog catalog =
-                ((FlinkCatalog) 
tEnv.getCatalog(tEnv.getCurrentCatalog()).get()).catalog();
-        assertThat(catalog.tableExists(identifier)).isFalse();
-
-        tEnv.executeSql("CREATE TABLE  t002(id INT PRIMARY KEY NOT ENFORCED , 
b STRING)").await();
-        assertThatThrownBy(() -> tEnv.executeSql("ALTER TABLE t002 MODIFY b 
TIME").await())
-                .hasRootCauseInstanceOf(UnsupportedOperationException.class)
-                .hasRootCauseMessage("Unsupported type: TIME(0)");
-        identifier = new Identifier("test_db", "t002");
-        FileStoreTable table = (FileStoreTable) catalog.getTable(identifier);
-        assertThat(table.schema().fields().toString()).isEqualTo("[`id` INT 
NOT NULL, `b` STRING]");
-    }
-
     @Test
     public void testAddPartitionsToMetastore() throws Exception {
         prepareTestAddPartitionsToMetastore();
diff --git 
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/PaimonStorageHandlerITCase.java
 
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/PaimonStorageHandlerITCase.java
index 28ef6833d..17bb98bc8 100644
--- 
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/PaimonStorageHandlerITCase.java
+++ 
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/PaimonStorageHandlerITCase.java
@@ -976,6 +976,58 @@ public class PaimonStorageHandlerITCase {
                 .containsExactly("NULL\t2022-06-18 08:30:00.1");
     }
 
+    @Test
+    public void testTime() throws Exception {
+        Table table =
+                FileStoreTestUtils.createFileStoreTable(
+                        getBasicConf(),
+                        RowType.of(
+                                new DataType[] {
+                                    DataTypes.INT().notNull(), 
DataTypes.TIME(), DataTypes.TIME(2)
+                                },
+                                new String[] {"pk", "time0", "time2"}),
+                        Collections.emptyList(),
+                        Collections.singletonList("pk"));
+
+        StreamWriteBuilder streamWriteBuilder = table.newStreamWriteBuilder();
+        StreamTableWrite write = streamWriteBuilder.newWrite();
+        StreamTableCommit commit = streamWriteBuilder.newCommit();
+
+        write.write(GenericRow.of(1, 0, 0)); // 00:00
+        commit.commit(0, write.prepareCommit(true, 0));
+
+        write.write(GenericRow.of(2, 86_399_999, 86_399_999)); // 
23:59:59.999999
+        commit.commit(1, write.prepareCommit(true, 1));
+
+        write.write(GenericRow.of(3, 45_001_000, 45_001_000)); // 12:30:01
+        commit.commit(2, write.prepareCommit(true, 2));
+
+        write.write(GenericRow.of(4, null, null));
+        commit.commit(4, write.prepareCommit(true, 3));
+
+        write.close();
+
+        createExternalTable();
+
+        // the TIME column will be converted to STRING column
+        assertThat(hiveShell.executeQuery("SHOW CREATE TABLE " + 
externalTable))
+                .contains(
+                        "  `time0` string COMMENT 'from deserializer', ",
+                        "  `time2` string COMMENT 'from deserializer')");
+
+        assertThat(hiveShell.executeQuery("SELECT * FROM " + externalTable))
+                .containsExactlyInAnyOrder(
+                        "1\t00:00\t00:00",
+                        "2\t23:59:59.999\t23:59:59.999",
+                        "3\t12:30:01\t12:30:01",
+                        "4\tNULL\tNULL");
+
+        assertThat(
+                        hiveShell.executeQuery(
+                                "SELECT * FROM " + externalTable + " WHERE 
time0 = '12:30:01'"))
+                .containsExactlyInAnyOrder("3\t12:30:01\t12:30:01");
+    }
+
     @Test
     public void testMapKey() throws Exception {
         Options conf = getBasicConf();
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 74d4c92c0..9fb846a6b 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
@@ -57,6 +57,7 @@ public class RandomGenericRowDataGenerator {
                     DataTypes.STRING(),
                     DataTypes.VARBINARY(Integer.MAX_VALUE),
                     DataTypes.DATE(),
+                    DataTypes.TIME(),
                     DataTypes.TIMESTAMP(3),
                     DataTypes.ARRAY(DataTypes.BIGINT()),
                     DataTypes.MAP(DataTypes.STRING(), DataTypes.INT()));
@@ -77,6 +78,7 @@ public class RandomGenericRowDataGenerator {
                     "string",
                     "binary",
                     "date",
+                    "string",
                     "timestamp",
                     "array<bigint>",
                     "map<string,int>");
@@ -97,6 +99,7 @@ public class RandomGenericRowDataGenerator {
                     "f_string",
                     "f_binary",
                     "f_date",
+                    "f_time",
                     "f_timestamp",
                     "f_list_long",
                     "f_map_string_int");
@@ -117,6 +120,7 @@ public class RandomGenericRowDataGenerator {
                     "comment_string",
                     "comment_binary",
                     "comment_date",
+                    "comment_time",
                     "comment_timestamp",
                     "comment_list_long",
                     "comment_map_string_int");
@@ -166,6 +170,7 @@ public class RandomGenericRowDataGenerator {
                         BinaryString.fromString(randomString(100)),
                         randomBytes,
                         random.nextInt(10000),
+                        random.nextInt(86400),
                         
Timestamp.fromEpochMillis(random.nextLong(Integer.MAX_VALUE)),
                         new GenericArray(randomLongArray),
                         new GenericMap(randomMap));
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 774e71df3..9930a62ce 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
@@ -59,6 +59,7 @@ public class PaimonInternalRowObjectInspectorTest {
                         ObjectInspector.Category.PRIMITIVE,
                         ObjectInspector.Category.PRIMITIVE,
                         ObjectInspector.Category.PRIMITIVE,
+                        ObjectInspector.Category.PRIMITIVE,
                         ObjectInspector.Category.LIST,
                         ObjectInspector.Category.MAP);
 
@@ -97,6 +98,7 @@ public class PaimonInternalRowObjectInspectorTest {
                                         "f_string:string",
                                         "f_binary:binary",
                                         "f_date:date",
+                                        "f_time:string",
                                         "f_timestamp:timestamp",
                                         "f_list_long:array<bigint>",
                                         "f_map_string_int:map<string,int>"))
diff --git 
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/objectinspector/PaimonTimeObjectInspectorTest.java
 
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/objectinspector/PaimonTimeObjectInspectorTest.java
new file mode 100644
index 000000000..2904434b9
--- /dev/null
+++ 
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/objectinspector/PaimonTimeObjectInspectorTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.hadoop.hive.serde2.objectinspector.ObjectInspector;
+import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
+import org.apache.hadoop.io.Text;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Tests for {@link PaimonTimeObjectInspector}. */
+public class PaimonTimeObjectInspectorTest {
+
+    @Test
+    public void testCategoryAndClass() {
+        PaimonTimeObjectInspector oi = new PaimonTimeObjectInspector();
+
+        
assertThat(oi.getCategory()).isEqualTo(ObjectInspector.Category.PRIMITIVE);
+        assertThat(oi.getPrimitiveCategory())
+                .isEqualTo(PrimitiveObjectInspector.PrimitiveCategory.STRING);
+
+        assertThat(oi.getJavaPrimitiveClass()).isEqualTo(String.class);
+        assertThat(oi.getPrimitiveWritableClass()).isEqualTo(Text.class);
+    }
+
+    @Test
+    public void testGetPrimitiveJavaObject() {
+        PaimonTimeObjectInspector oi = new PaimonTimeObjectInspector();
+
+        int input = 1;
+        assertThat(oi.getPrimitiveJavaObject(input)).isEqualTo("00:00:00.001");
+        assertThat(oi.getPrimitiveJavaObject(null)).isNull();
+    }
+
+    @Test
+    public void testGetPrimitiveWritableObject() {
+        PaimonTimeObjectInspector oi = new PaimonTimeObjectInspector();
+
+        int input = 86_399_000;
+        
assertThat(oi.getPrimitiveWritableObject(input).toString()).isEqualTo("23:59:59");
+        assertThat(oi.getPrimitiveWritableObject(null)).isNull();
+    }
+}

Reply via email to