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

jackietien pushed a commit to branch object_type
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/object_type by this push:
     new 48520edda26 add GeoPenetrate function
     new 1bc950dc155 Merge branch 'object_type' of 
https://github.com/apache/iotdb into object_type
48520edda26 is described below

commit 48520edda261427fcd6c663052c7ce681216ad38
Author: JackieTien97 <[email protected]>
AuthorDate: Mon Jul 7 19:50:31 2025 +0800

    add GeoPenetrate function
---
 .../main/java/org/apache/iotdb/ObjectExample.java  |   8 +-
 .../java/org/apache/iotdb/ObjectReadExample.java   |  16 +++
 .../java/org/apache/iotdb/udf/api/type/Type.java   |  10 +-
 .../relational/function/scalar/GeoPenetrate.java   | 123 +++++++++++++++++++++
 .../unary/scalar/ReadObjectColumnTransformer.java  |   2 +-
 .../utils/model/CompressedTsFileModelReader.java   |   2 +-
 .../apache/iotdb/db/utils/model/ModelReader.java   |  22 ++--
 .../iotdb/db/utils/model/ModelReaderType.java      |  25 -----
 .../utils/model/UnCompressedTiffModelReader.java   |   2 +-
 .../commons/udf/utils/UDFDataTypeTransformer.java  |   7 ++
 10 files changed, 177 insertions(+), 40 deletions(-)

diff --git a/example/session/src/main/java/org/apache/iotdb/ObjectExample.java 
b/example/session/src/main/java/org/apache/iotdb/ObjectExample.java
index b040dc5313b..6a880cc0174 100644
--- a/example/session/src/main/java/org/apache/iotdb/ObjectExample.java
+++ b/example/session/src/main/java/org/apache/iotdb/ObjectExample.java
@@ -48,7 +48,7 @@ public class ObjectExample {
             .username("root")
             .password("root")
             .build()) {
-      session.executeNonQueryStatement("CREATE DATABASE test1");
+      session.executeNonQueryStatement("CREATE DATABASE IF NOT EXISTS test1");
       session.executeNonQueryStatement("use test1");
 
       // insert table data by tablet
@@ -82,7 +82,8 @@ public class ObjectExample {
           true,
           0,
           Files.readAllBytes(
-              
Paths.get("/Users/ht/Downloads/2_1746622362350_fa24aa15233f4e76bcda789a5771f43f")));
+              Paths.get(
+                  
"/Users/jackietien/Downloads/2_1746622362350_fa24aa15233f4e76bcda789a5771f43f")));
       session.insert(tablet);
       tablet.reset();
 
@@ -99,7 +100,8 @@ public class ObjectExample {
           true,
           0,
           Files.readAllBytes(
-              
Paths.get("/Users/ht/Downloads/2_1746622367063_8fb5ac8e21724140874195b60b878664")));
+              Paths.get(
+                  
"/Users/jackietien/Downloads/2_1746622367063_8fb5ac8e21724140874195b60b878664")));
       session.insert(tablet);
       tablet.reset();
 
diff --git 
a/example/session/src/main/java/org/apache/iotdb/ObjectReadExample.java 
b/example/session/src/main/java/org/apache/iotdb/ObjectReadExample.java
index 4fd68322fe0..bf4417c15be 100644
--- a/example/session/src/main/java/org/apache/iotdb/ObjectReadExample.java
+++ b/example/session/src/main/java/org/apache/iotdb/ObjectReadExample.java
@@ -28,6 +28,8 @@ import org.apache.iotdb.session.TableSessionBuilder;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.tsfile.utils.Binary;
 
+import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 
 public class ObjectReadExample {
@@ -71,6 +73,20 @@ public class ObjectReadExample {
         }
       }
 
+      try (SessionDataSet dataSet =
+          session.executeQueryStatement("select geo_penetrate(file, 
'0,3,7501,7504') from test1")) {
+        SessionDataSet.DataIterator iterator = dataSet.iterator();
+        while (iterator.next()) {
+          Binary binary = iterator.getBlob(1);
+          ByteBuffer byteBuffer = ByteBuffer.wrap(binary.getValues());
+          float[] res = new float[byteBuffer.limit() / Float.BYTES];
+          for (int i = 0; i < res.length; i++) {
+            res[i] = byteBuffer.getFloat();
+          }
+          System.out.println(Arrays.toString(res));
+        }
+      }
+
     } catch (IoTDBConnectionException e) {
       e.printStackTrace();
     } catch (StatementExecutionException e) {
diff --git 
a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/type/Type.java 
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/type/Type.java
index a5c2852ac1b..c4c38c285dc 100644
--- a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/type/Type.java
+++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/type/Type.java
@@ -56,7 +56,11 @@ public enum Type {
   BLOB((byte) 10),
 
   /* STRING */
-  STRING((byte) 11);
+  STRING((byte) 11),
+
+  /* OBJECT */
+  OBJECT((byte) 12);
+
   private final byte dataType;
 
   Type(byte type) {
@@ -92,6 +96,7 @@ public enum Type {
       case DATE:
         return o instanceof LocalDate;
       case BLOB:
+      case OBJECT:
         return o instanceof Binary;
       case STRING:
       case TEXT:
@@ -102,7 +107,8 @@ public enum Type {
   }
 
   public static List<Type> allTypes() {
-    return Arrays.asList(BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT, 
TIMESTAMP, DATE, BLOB, STRING);
+    return Arrays.asList(
+        BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT, TIMESTAMP, DATE, BLOB, 
STRING, OBJECT);
   }
 
   public static List<Type> numericTypes() {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/scalar/GeoPenetrate.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/scalar/GeoPenetrate.java
new file mode 100644
index 00000000000..440b3728bc4
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/scalar/GeoPenetrate.java
@@ -0,0 +1,123 @@
+/*
+ * 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.iotdb.db.queryengine.plan.relational.function.scalar;
+
+import org.apache.iotdb.db.exception.sql.SemanticException;
+import org.apache.iotdb.db.utils.model.ModelReader;
+import org.apache.iotdb.udf.api.customizer.analysis.ScalarFunctionAnalysis;
+import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments;
+import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException;
+import org.apache.iotdb.udf.api.exception.UDFException;
+import org.apache.iotdb.udf.api.relational.ScalarFunction;
+import org.apache.iotdb.udf.api.relational.access.Record;
+import org.apache.iotdb.udf.api.type.Type;
+
+import org.apache.tsfile.utils.Binary;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import static 
org.apache.iotdb.db.queryengine.transformation.dag.column.unary.scalar.ReadObjectColumnTransformer.getObjectPathFromBinary;
+
+public class GeoPenetrate implements ScalarFunction {
+
+  private ModelReader reader;
+  private List<List<Integer>> startAndEndTimeArray;
+
+  @Override
+  public ScalarFunctionAnalysis analyze(FunctionArguments arguments)
+      throws UDFArgumentNotValidException {
+    if (arguments.getArgumentsSize() != 2 && arguments.getArgumentsSize() != 
3) {
+      throw new UDFArgumentNotValidException(
+          "function requires 2 or 3 arguments, current parameters' size is "
+              + arguments.getArgumentsSize());
+    }
+    if (arguments.getDataType(0) != Type.OBJECT) {
+      throw new UDFArgumentNotValidException("function's first parameter type 
should be OBJECT");
+    }
+
+    if (arguments.getDataType(1) != Type.STRING) {
+      throw new UDFArgumentNotValidException("function's second parameter type 
should be STRING");
+    }
+
+    if (arguments.getArgumentsSize() == 3 && arguments.getDataType(1) != 
Type.STRING) {
+      throw new UDFArgumentNotValidException("function's third parameter type 
should be STRING");
+    }
+
+    return new 
ScalarFunctionAnalysis.Builder().outputDataType(Type.BLOB).build();
+  }
+
+  @Override
+  public void beforeStart(FunctionArguments arguments) throws UDFException {
+    if (arguments.getArgumentsSize() == 2) {
+      reader = ModelReader.getDefaultInstance();
+    }
+  }
+
+  @Override
+  public Object evaluate(Record input) throws UDFException {
+    if (reader == null) {
+      reader = ModelReader.getInstance(input.getString(2));
+    }
+    if (startAndEndTimeArray == null) {
+      startAndEndTimeArray = getStartAndEndTimeArray(input.getString(1));
+    }
+    if (input.isNull(0)) {
+      return null;
+    } else {
+      File objectPath = getObjectPathFromBinary(input.getBinary(0));
+      List<float[]> res = reader.penetrate(objectPath.getAbsolutePath(), 
startAndEndTimeArray);
+      int count = 0;
+      for (float[] array : res) {
+        count += array.length;
+      }
+      ByteBuffer byteBuffer = ByteBuffer.allocate(count * Float.BYTES);
+      for (float[] array : res) {
+        for (float value : array) {
+          ReadWriteIOUtils.write(value, byteBuffer);
+        }
+      }
+      return new Binary(byteBuffer.array());
+    }
+  }
+
+  // argument like: 1,2;200,201;300,401
+  private List<List<Integer>> getStartAndEndTimeArray(String argument) {
+    String[] arguments = argument.split(",");
+    if (arguments.length % 2 != 0) {
+      throw new SemanticException("second argument is wrong: " + argument);
+    }
+    List<List<Integer>> res = new ArrayList<>(arguments.length);
+    for (int index = 0; index < arguments.length; index += 2) {
+      List<Integer> startAndEndTime = new ArrayList<>(2);
+      try {
+        startAndEndTime.add(Integer.parseInt(arguments[index]));
+        startAndEndTime.add(Integer.parseInt(arguments[index + 1]));
+      } catch (NumberFormatException e) {
+        throw new SemanticException("second argument is wrong: " + argument);
+      }
+      res.add(startAndEndTime);
+    }
+    return res;
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/ReadObjectColumnTransformer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/ReadObjectColumnTransformer.java
index 74db2d31ca3..60a178a33c8 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/ReadObjectColumnTransformer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/column/unary/scalar/ReadObjectColumnTransformer.java
@@ -130,7 +130,7 @@ public class ReadObjectColumnTransformer extends 
UnaryColumnTransformer {
     return new Binary(bytes);
   }
 
-  private File getObjectPathFromBinary(Binary binary) {
+  public static File getObjectPathFromBinary(Binary binary) {
     byte[] bytes = binary.getValues();
     String relativeObjectFilePath =
         new String(bytes, 8, bytes.length - 8, TSFileConfig.STRING_CHARSET);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/CompressedTsFileModelReader.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/CompressedTsFileModelReader.java
index 8cc0c4a9eb6..2849e0657dd 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/CompressedTsFileModelReader.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/CompressedTsFileModelReader.java
@@ -48,7 +48,7 @@ public class CompressedTsFileModelReader extends ModelReader {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(CompressedTsFileModelReader.class);
 
   @Override
-  List<float[]> penetrate(String filePath, List<List<Integer>> 
startAndEndTimeArray) {
+  public List<float[]> penetrate(String filePath, List<List<Integer>> 
startAndEndTimeArray) {
     try {
       List<float[]> results = new ArrayList<>(startAndEndTimeArray.size());
       int currentQueryIndex = 0;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/ModelReader.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/ModelReader.java
index 14b4f939323..18a6f5aed43 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/ModelReader.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/ModelReader.java
@@ -19,6 +19,8 @@
 
 package org.apache.iotdb.db.utils.model;
 
+import org.apache.iotdb.db.exception.sql.SemanticException;
+
 import java.util.List;
 
 public abstract class ModelReader {
@@ -30,14 +32,20 @@ public abstract class ModelReader {
    *     integers
    * @return a list of float arrays, each array corresponds to a start and end 
time pair
    */
-  abstract List<float[]> penetrate(String filePath, List<List<Integer>> 
startAndEndTimeArray);
+  public abstract List<float[]> penetrate(
+      String filePath, List<List<Integer>> startAndEndTimeArray);
+
+  public static ModelReader getDefaultInstance() {
+    return new CompressedTsFileModelReader();
+  }
 
-  public ModelReader getInstance(ModelReaderType modelFileType) {
-    switch (modelFileType) {
-      case UNCOMPRESSED_TIFF:
-        return new UnCompressedTiffModelReader();
-      default:
-        return new CompressedTsFileModelReader();
+  public static ModelReader getInstance(String modelFileType) {
+    if (modelFileType.equalsIgnoreCase("UNCOMPRESSED_TIFF")) {
+      return new UnCompressedTiffModelReader();
+    } else if (modelFileType.equalsIgnoreCase("COMPRESSED_TSFILE")) {
+      return new CompressedTsFileModelReader();
+    } else {
+      throw new SemanticException("Unsupported model file type: " + 
modelFileType);
     }
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/ModelReaderType.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/ModelReaderType.java
deleted file mode 100644
index fe07b4d0f8e..00000000000
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/ModelReaderType.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.iotdb.db.utils.model;
-
-public enum ModelReaderType {
-  COMPRESSED_TSFILE,
-  UNCOMPRESSED_TIFF
-}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/UnCompressedTiffModelReader.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/UnCompressedTiffModelReader.java
index 99f3d183126..debfeab42a3 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/UnCompressedTiffModelReader.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/model/UnCompressedTiffModelReader.java
@@ -25,7 +25,7 @@ import java.util.List;
 public class UnCompressedTiffModelReader extends ModelReader {
 
   @Override
-  List<float[]> penetrate(String filePath, List<List<Integer>> 
startAndEndTimeArray) {
+  public List<float[]> penetrate(String filePath, List<List<Integer>> 
startAndEndTimeArray) {
     return Collections.emptyList();
   }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/utils/UDFDataTypeTransformer.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/utils/UDFDataTypeTransformer.java
index 83792ebf66a..cf9ecf89f96 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/utils/UDFDataTypeTransformer.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/utils/UDFDataTypeTransformer.java
@@ -30,6 +30,7 @@ import org.apache.tsfile.read.common.type.DoubleType;
 import org.apache.tsfile.read.common.type.FloatType;
 import org.apache.tsfile.read.common.type.IntType;
 import org.apache.tsfile.read.common.type.LongType;
+import org.apache.tsfile.read.common.type.ObjectType;
 import org.apache.tsfile.read.common.type.StringType;
 import org.apache.tsfile.read.common.type.TimestampType;
 
@@ -82,6 +83,8 @@ public class UDFDataTypeTransformer {
         return Type.BLOB;
       case STRING:
         return Type.STRING;
+      case OBJECT:
+        return Type.OBJECT;
       default:
         throw new IllegalArgumentException("Invalid input: " + type);
     }
@@ -112,6 +115,8 @@ public class UDFDataTypeTransformer {
         return BlobType.BLOB;
       case STRING:
         return StringType.STRING;
+      case OBJECT:
+        return ObjectType.OBJECT;
       default:
         throw new IllegalArgumentException("Invalid input: " + type);
     }
@@ -139,6 +144,8 @@ public class UDFDataTypeTransformer {
         return Type.BLOB;
       case 11:
         return Type.STRING;
+      case 12:
+        return Type.OBJECT;
       default:
         throw new IllegalArgumentException("Invalid input: " + type);
     }

Reply via email to