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

panxiaolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 96c4471b4a [feature](udf) udf array/map support decimal and  update 
doc  (#23560)
96c4471b4a is described below

commit 96c4471b4a6a7531a882b206347534efc9596117
Author: Mryange <59914473+mrya...@users.noreply.github.com>
AuthorDate: Thu Aug 31 07:44:18 2023 +0800

    [feature](udf) udf array/map support decimal and  update doc  (#23560)
    
    * update
    
    * decimal
    
    * update table name
    
    * remove log
    
    * add log
---
 .../ecosystem/udf/java-user-defined-function.md    |  3 +-
 .../ecosystem/udf/java-user-defined-function.md    |  3 +-
 .../apache/doris/common/jni/utils/UdfUtils.java    | 96 ++++++++-------------
 .../java/org/apache/doris/udf/BaseExecutor.java    | 29 ++++---
 .../java/org/apache/doris/udf/UdafExecutor.java    | 15 ++--
 .../java/org/apache/doris/udf/UdfExecutor.java     | 28 ++-----
 .../data/javaudf_p0/test_javaudf_with_decimal.out  | 13 +++
 .../java/org/apache/doris/udf/MyArrayDecimal.java  | 35 ++++++++
 .../java/org/apache/doris/udf/MyMapDecimal.java    | 35 ++++++++
 .../java/org/apache/doris/udf/MyMapRetDecimal.java | 42 ++++++++++
 .../org/apache/doris/udf/MyReturnMapString.java    |  1 -
 .../org/apache/doris/udf/MySumReturnMapIntDou.java |  1 -
 .../suites/javaudf_p0/test_javaudf_agg_map.groovy  | 14 ++--
 .../javaudf_p0/test_javaudf_with_decimal.groovy    | 97 ++++++++++++++++++++++
 14 files changed, 294 insertions(+), 118 deletions(-)

diff --git a/docs/en/docs/ecosystem/udf/java-user-defined-function.md 
b/docs/en/docs/ecosystem/udf/java-user-defined-function.md
index c6b57fed3c..d1e3ee2998 100644
--- a/docs/en/docs/ecosystem/udf/java-user-defined-function.md
+++ b/docs/en/docs/ecosystem/udf/java-user-defined-function.md
@@ -59,8 +59,9 @@ Java UDF provides users with a Java interface written in UDF 
to facilitate the e
 |String|String|
 |Decimal|BigDecimal|
 |```array<Type>```|```ArrayList<Type>```|
+|```map<Type1,Type2>```|```HashMap<Type1,Type2>```|
 
-* Array types can nested basic types, Eg: In Doris: ```array<int>``` 
corresponds to JAVA UDF Argument Type: ```ArrayList<Integer>```, Others is also.
+* Array/Map types can nested basic types, Eg: In Doris: ```array<int>``` 
corresponds to JAVA UDF Argument Type: ```ArrayList<Integer>```, Others is also.
 ## Write UDF functions
 
 This section mainly introduces how to develop a Java UDF. Samples for the Java 
version are provided under `samples/doris-demo/java-udf-demo/` for your 
reference, Check it out 
[here](https://github.com/apache/incubator-doris/tree/master/samples/doris-demo/java-udf-demo)
diff --git a/docs/zh-CN/docs/ecosystem/udf/java-user-defined-function.md 
b/docs/zh-CN/docs/ecosystem/udf/java-user-defined-function.md
index a30fcca614..e7e37b56e5 100644
--- a/docs/zh-CN/docs/ecosystem/udf/java-user-defined-function.md
+++ b/docs/zh-CN/docs/ecosystem/udf/java-user-defined-function.md
@@ -57,8 +57,9 @@ Java UDF 为用户提供UDF编写的Java接口,以方便用户使用Java语言
 |String|String|
 |Decimal|BigDecimal|
 |```array<Type>```|```ArrayList<Type>```|
+|```map<Type1,Type2>```|```HashMap<Type1,Type2>```|
 
-* array类型可以嵌套基本类型,例如Doris: ```array<int>```对应JAVA UDF Argument Type: 
```ArrayList<Integer>```, 其他依此类推
+* array/map类型可以嵌套基本类型,例如Doris: ```array<int>```对应JAVA UDF Argument Type: 
```ArrayList<Integer>```, 其他依此类推
 ## 编写 UDF 函数
 
 本小节主要介绍如何开发一个 Java UDF。在 `samples/doris-demo/java-udf-demo/` 
下提供了示例,可供参考,查看点击[这里](https://github.com/apache/doris/tree/master/samples/doris-demo/java-udf-demo)
diff --git 
a/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/UdfUtils.java
 
b/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/UdfUtils.java
index 5f7c050136..1eb0c8d07d 100644
--- 
a/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/UdfUtils.java
+++ 
b/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/UdfUtils.java
@@ -19,17 +19,12 @@ package org.apache.doris.common.jni.utils;
 
 import org.apache.doris.catalog.ArrayType;
 import org.apache.doris.catalog.MapType;
-import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
 import org.apache.doris.common.Pair;
 import org.apache.doris.common.exception.InternalException;
 import org.apache.doris.thrift.TPrimitiveType;
-import org.apache.doris.thrift.TScalarType;
-import org.apache.doris.thrift.TTypeDesc;
-import org.apache.doris.thrift.TTypeNode;
 
-import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
 import com.vesoft.nebula.client.graph.data.DateTimeWrapper;
 import com.vesoft.nebula.client.graph.data.DateWrapper;
@@ -98,6 +93,7 @@ public class UdfUtils {
         DECIMAL128("DECIMAL128", TPrimitiveType.DECIMAL128I, 16),
         ARRAY_TYPE("ARRAY_TYPE", TPrimitiveType.ARRAY, 0),
         MAP_TYPE("MAP_TYPE", TPrimitiveType.MAP, 0);
+
         private final String description;
         private final TPrimitiveType thriftType;
         private final int len;
@@ -106,6 +102,9 @@ public class UdfUtils {
         private Type itemType;
         private Type keyType;
         private Type valueType;
+        private int keyScale;
+        private int valueScale;
+
         JavaUdfDataType(String description, TPrimitiveType thriftType, int 
len) {
             this.description = description;
             this.thriftType = thriftType;
@@ -212,63 +211,22 @@ public class UdfUtils {
         public void setValueType(Type type) {
             this.valueType = type;
         }
-    }
 
-    public static Pair<Type, Integer> fromThrift(TTypeDesc typeDesc, int 
nodeIdx) throws InternalException {
-        TTypeNode node = typeDesc.getTypes().get(nodeIdx);
-        Type type = null;
-        switch (node.getType()) {
-            case SCALAR: {
-                Preconditions.checkState(node.isSetScalarType());
-                TScalarType scalarType = node.getScalarType();
-                if (scalarType.getType() == TPrimitiveType.CHAR) {
-                    Preconditions.checkState(scalarType.isSetLen());
-                    type = ScalarType.createCharType(scalarType.getLen());
-                } else if (scalarType.getType() == TPrimitiveType.VARCHAR) {
-                    Preconditions.checkState(scalarType.isSetLen());
-                    type = ScalarType.createVarcharType(scalarType.getLen());
-                } else if (scalarType.getType() == TPrimitiveType.DECIMALV2) {
-                    Preconditions.checkState(scalarType.isSetPrecision()
-                            && scalarType.isSetScale());
-                    type = 
ScalarType.createDecimalType(scalarType.getPrecision(),
-                            scalarType.getScale());
-                } else if (scalarType.getType() == TPrimitiveType.DECIMAL32
-                        || scalarType.getType() == TPrimitiveType.DECIMAL64
-                        || scalarType.getType() == TPrimitiveType.DECIMAL128I) 
{
-                    Preconditions.checkState(scalarType.isSetPrecision()
-                            && scalarType.isSetScale());
-                    type = 
ScalarType.createDecimalV3Type(scalarType.getPrecision(),
-                            scalarType.getScale());
-                } else {
-                    type = ScalarType.createType(
-                            PrimitiveType.fromThrift(scalarType.getType()));
-                }
-                break;
-            }
-            case ARRAY: {
-                Preconditions.checkState(nodeIdx + 1 < 
typeDesc.getTypesSize());
-                Pair<Type, Integer> childType = fromThrift(typeDesc, nodeIdx + 
1);
-                type = new ArrayType(childType.first);
-                nodeIdx = childType.second;
-                break;
-            }
-            case MAP: {
-                Preconditions.checkState(nodeIdx + 2 < 
typeDesc.getTypesSize());
-                Pair<Type, Integer> keyType = fromThrift(typeDesc, nodeIdx + 
1);
-                Pair<Type, Integer> valueType = fromThrift(typeDesc, 
keyType.second);
-                type = new MapType(keyType.first, valueType.first);
-                nodeIdx = valueType.second;
-                break;
-            }
+        public void setKeyScale(int scale) {
+            this.keyScale = scale;
+        }
 
-            default:
-                throw new InternalException("Return type " + node.getType() + 
" is not supported now!");
+        public void setValueScale(int scale) {
+            this.valueScale = scale;
+        }
+
+        public int getKeyScale() {
+            return keyScale;
         }
-        return Pair.of(type, nodeIdx);
-    }
 
-    public static long getAddressAtOffset(long base, int offset) {
-        return base + 8L * offset;
+        public int getValueScale() {
+            return valueScale;
+        }
     }
 
     public static void copyMemory(
@@ -339,9 +297,13 @@ public class UdfUtils {
             MapType mapType = (MapType) retType;
             result.setKeyType(mapType.getKeyType());
             result.setValueType(mapType.getValueType());
-            if (mapType.getKeyType().isDatetimeV2() || 
mapType.getKeyType().isDecimalV3()) {
-                result.setPrecision(mapType.getKeyType().getPrecision());
-                result.setScale(((ScalarType) 
mapType.getKeyType()).getScalarScale());
+            Type keyType = mapType.getKeyType();
+            Type valuType = mapType.getValueType();
+            if (keyType.isDatetimeV2() || keyType.isDecimalV3()) {
+                result.setKeyScale(((ScalarType) keyType).getScalarScale());
+            }
+            if (valuType.isDatetimeV2() || valuType.isDecimalV3()) {
+                result.setValueScale(((ScalarType) valuType).getScalarScale());
             }
         }
         return Pair.of(res.length != 0, result);
@@ -368,10 +330,22 @@ public class UdfUtils {
             } else if (parameterTypes[finalI].isArrayType()) {
                 ArrayType arrType = (ArrayType) parameterTypes[finalI];
                 inputArgTypes[i].setItemType(arrType.getItemType());
+                if (arrType.getItemType().isDatetimeV2() || 
arrType.getItemType().isDecimalV3()) {
+                    
inputArgTypes[i].setPrecision(arrType.getItemType().getPrecision());
+                    inputArgTypes[i].setScale(((ScalarType) 
arrType.getItemType()).getScalarScale());
+                }
             } else if (parameterTypes[finalI].isMapType()) {
                 MapType mapType = (MapType) parameterTypes[finalI];
+                Type keyType = mapType.getKeyType();
+                Type valuType = mapType.getValueType();
                 inputArgTypes[i].setKeyType(mapType.getKeyType());
                 inputArgTypes[i].setValueType(mapType.getValueType());
+                if (keyType.isDatetimeV2() || keyType.isDecimalV3()) {
+                    inputArgTypes[i].setKeyScale(((ScalarType) 
keyType).getScalarScale());
+                }
+                if (valuType.isDatetimeV2() || valuType.isDecimalV3()) {
+                    inputArgTypes[i].setValueScale(((ScalarType) 
valuType).getScalarScale());
+                }
             }
             if (res.length == 0) {
                 return Pair.of(false, inputArgTypes);
diff --git 
a/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/BaseExecutor.java
 
b/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/BaseExecutor.java
index 41dfe04c2a..9c1cb17ba5 100644
--- 
a/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/BaseExecutor.java
+++ 
b/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/BaseExecutor.java
@@ -24,6 +24,7 @@ import org.apache.doris.common.exception.UdfRuntimeException;
 import org.apache.doris.common.jni.utils.JNINativeMethod;
 import org.apache.doris.common.jni.utils.UdfUtils;
 import org.apache.doris.common.jni.utils.UdfUtils.JavaUdfDataType;
+import org.apache.doris.thrift.TFunction;
 import org.apache.doris.thrift.TJavaUdfExecutorCtorParams;
 
 import com.esotericsoftware.reflectasm.MethodAccess;
@@ -76,6 +77,7 @@ public abstract class BaseExecutor {
     protected JavaUdfDataType retType;
     protected Class[] argClass;
     protected MethodAccess methodAccess;
+    protected TFunction fn;
 
     /**
      * Create a UdfExecutor, using parameters from a serialized thrift object. 
Used
@@ -95,6 +97,7 @@ public abstract class BaseExecutor {
         for (int i = 0; i < request.fn.arg_types.size(); ++i) {
             parameterTypes[i] = Type.fromThrift(request.fn.arg_types.get(i));
         }
+        fn = request.fn;
         String jarFile = request.location;
         Type funcRetType = Type.fromThrift(request.fn.ret_type);
         init(request, jarFile, funcRetType, parameterTypes);
@@ -125,6 +128,7 @@ public abstract class BaseExecutor {
             res = res + " key: " + retType.getValueType().toString() + " sql: 
" + retType.getValueType().toSql();
         }
         res = res + " methodAccess: " + methodAccess.toString();
+        res = res + " fn.toString(): " + fn.toString();
         return res;
     }
 
@@ -276,7 +280,6 @@ public abstract class BaseExecutor {
                 UdfUtils.UNSAFE.putInt(null, offsetsAddr + 4L * row, 
Integer.parseUnsignedInt(String.valueOf(offset)));
                 UdfUtils.copyMemory(bytes, UdfUtils.BYTE_ARRAY_OFFSET, null, 
outputBufferBase + offset - bytes.length,
                         bytes.length);
-                updateOutputOffset(offset);
                 break;
             }
             case ARRAY_TYPE:
@@ -285,10 +288,6 @@ public abstract class BaseExecutor {
         }
     }
 
-
-    protected void updateOutputOffset(long offset) {
-    }
-
     public Object[] convertBasicArg(boolean isUdf, int argIdx, boolean 
isNullable, int rowStart, int rowEnd,
             long nullMapAddr, long columnAddr, long strOffsetAddr) {
         switch (argTypes[argIdx]) {
@@ -470,7 +469,7 @@ public abstract class BaseExecutor {
 
     public Object[] convertMapArg(PrimitiveType type, int argIdx, boolean 
isNullable, int rowStart, int rowEnd,
             long nullMapAddr,
-            long offsetsAddr, long nestedNullMapAddr, long dataAddr, long 
strOffsetAddr) {
+            long offsetsAddr, long nestedNullMapAddr, long dataAddr, long 
strOffsetAddr, int scale) {
         Object[] argument = (Object[]) Array.newInstance(ArrayList.class, 
rowEnd - rowStart);
         for (int row = rowStart; row < rowEnd; ++row) {
             long offsetStart = UdfUtils.UNSAFE.getLong(null, offsetsAddr + 8L 
* (row - 1));
@@ -561,19 +560,19 @@ public abstract class BaseExecutor {
                 case DECIMALV2:
                 case DECIMAL128: {
                     argument[row - rowStart] = UdfConvert
-                            
.convertArrayDecimalArg(argTypes[argIdx].getScale(), 16L, row, currentRowNum,
+                            .convertArrayDecimalArg(scale, 16L, row, 
currentRowNum,
                                     offsetStart, isNullable, nullMapAddr, 
nestedNullMapAddr, dataAddr);
                     break;
                 }
                 case DECIMAL32: {
                     argument[row - rowStart] = UdfConvert
-                            
.convertArrayDecimalArg(argTypes[argIdx].getScale(), 4L, row, currentRowNum,
+                            .convertArrayDecimalArg(scale, 4L, row, 
currentRowNum,
                                     offsetStart, isNullable, nullMapAddr, 
nestedNullMapAddr, dataAddr);
                     break;
                 }
                 case DECIMAL64: {
                     argument[row - rowStart] = UdfConvert
-                            
.convertArrayDecimalArg(argTypes[argIdx].getScale(), 8L, row, currentRowNum,
+                            .convertArrayDecimalArg(scale, 8L, row, 
currentRowNum,
                                     offsetStart, isNullable, nullMapAddr, 
nestedNullMapAddr, dataAddr);
                     break;
                 }
@@ -813,18 +812,18 @@ public abstract class BaseExecutor {
 
     public void copyBatchArrayResultImpl(boolean isNullable, int numRows, 
Object[] result, long nullMapAddr,
             long offsetsAddr, long nestedNullMapAddr, long dataAddr, long 
strOffsetAddr,
-            PrimitiveType type) {
+            PrimitiveType type, int scale) {
         long hasPutElementNum = 0;
         for (int row = 0; row < numRows; ++row) {
             hasPutElementNum = copyTupleArrayResultImpl(hasPutElementNum, 
isNullable, row, result[row], nullMapAddr,
-                    offsetsAddr, nestedNullMapAddr, dataAddr, strOffsetAddr, 
type);
+                    offsetsAddr, nestedNullMapAddr, dataAddr, strOffsetAddr, 
type, scale);
         }
     }
 
     public long copyTupleArrayResultImpl(long hasPutElementNum, boolean 
isNullable, int row, Object result,
             long nullMapAddr,
             long offsetsAddr, long nestedNullMapAddr, long dataAddr, long 
strOffsetAddr,
-            PrimitiveType type) {
+            PrimitiveType type, int scale) {
         switch (type) {
             case BOOLEAN: {
                 hasPutElementNum = UdfConvert
@@ -914,21 +913,21 @@ public abstract class BaseExecutor {
             }
             case DECIMAL32: {
                 hasPutElementNum = UdfConvert
-                        .copyBatchArrayDecimalV3Result(retType.getScale(), 4L, 
hasPutElementNum, isNullable, row,
+                        .copyBatchArrayDecimalV3Result(scale, 4L, 
hasPutElementNum, isNullable, row,
                                 result, nullMapAddr,
                                 offsetsAddr, nestedNullMapAddr, dataAddr);
                 break;
             }
             case DECIMAL64: {
                 hasPutElementNum = UdfConvert
-                        .copyBatchArrayDecimalV3Result(retType.getScale(), 8L, 
hasPutElementNum, isNullable, row,
+                        .copyBatchArrayDecimalV3Result(scale, 8L, 
hasPutElementNum, isNullable, row,
                                 result, nullMapAddr,
                                 offsetsAddr, nestedNullMapAddr, dataAddr);
                 break;
             }
             case DECIMAL128: {
                 hasPutElementNum = UdfConvert
-                        .copyBatchArrayDecimalV3Result(retType.getScale(), 
16L, hasPutElementNum, isNullable, row,
+                        .copyBatchArrayDecimalV3Result(scale, 16L, 
hasPutElementNum, isNullable, row,
                                 result, nullMapAddr,
                                 offsetsAddr, nestedNullMapAddr, dataAddr);
                 break;
diff --git 
a/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/UdafExecutor.java
 
b/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/UdafExecutor.java
index bb397f689a..29ac4b272b 100644
--- 
a/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/UdafExecutor.java
+++ 
b/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/UdafExecutor.java
@@ -48,7 +48,6 @@ public class UdafExecutor extends BaseExecutor {
 
     private static final Logger LOG = Logger.getLogger(UdafExecutor.class);
 
-    private long inputPlacesPtr;
     private HashMap<String, Method> allMethods;
     private HashMap<Long, Object> stateObjMap;
     private Class retClass;
@@ -88,11 +87,11 @@ public class UdafExecutor extends BaseExecutor {
         PrimitiveType valueType = 
argTypes[argIdx].getValueType().getPrimitiveType();
         Object[] keyCol = convertMapArg(keyType, argIdx, isNullable, rowStart, 
rowEnd, nullMapAddr, offsetsAddr,
                 keyNestedNullMapAddr, keyDataAddr,
-                keyStrOffsetAddr);
+                keyStrOffsetAddr, argTypes[argIdx].getKeyScale());
         Object[] valueCol = convertMapArg(valueType, argIdx, isNullable, 
rowStart, rowEnd, nullMapAddr, offsetsAddr,
                 valueNestedNullMapAddr,
                 valueDataAddr,
-                valueStrOffsetAddr);
+                valueStrOffsetAddr, argTypes[argIdx].getValueScale());
         return buildHashMap(keyType, valueType, keyCol, valueCol);
     }
 
@@ -304,12 +303,13 @@ public class UdafExecutor extends BaseExecutor {
             UdfUtils.UNSAFE.putByte(nullMapAddr + row, (byte) 0);
         }
         copyTupleArrayResultImpl(hasPutElementNum, isNullable, row, result, 
nullMapAddr, offsetsAddr, nestedNullMapAddr,
-                dataAddr, strOffsetAddr, 
retType.getItemType().getPrimitiveType());
+                dataAddr, strOffsetAddr, 
retType.getItemType().getPrimitiveType(), retType.getScale());
     }
 
     public void copyTupleMapResult(long hasPutElementNum, boolean isNullable, 
int row, Object result, long nullMapAddr,
             long offsetsAddr,
-            long keyNsestedNullMapAddr, long keyDataAddr, long 
keyStrOffsetAddr,
+            long keyNsestedNullMapAddr, long keyDataAddr,
+            long keyStrOffsetAddr,
             long valueNsestedNullMapAddr, long valueDataAddr, long 
valueStrOffsetAddr) throws UdfRuntimeException {
         if (nullMapAddr > 0) {
             UdfUtils.UNSAFE.putByte(nullMapAddr + row, (byte) 0);
@@ -323,16 +323,15 @@ public class UdafExecutor extends BaseExecutor {
         buildArrayListFromHashMap(resultArr, keyType, valueType, keyCol, 
valueCol);
         copyTupleArrayResultImpl(hasPutElementNum, isNullable, row,
                 valueCol[0], nullMapAddr, offsetsAddr,
-                valueNsestedNullMapAddr, valueDataAddr, valueStrOffsetAddr, 
valueType);
+                valueNsestedNullMapAddr, valueDataAddr, valueStrOffsetAddr, 
valueType, retType.getKeyScale());
         copyTupleArrayResultImpl(hasPutElementNum, isNullable, row, keyCol[0], 
nullMapAddr, offsetsAddr,
-                keyNsestedNullMapAddr, keyDataAddr, keyStrOffsetAddr, keyType);
+                keyNsestedNullMapAddr, keyDataAddr, keyStrOffsetAddr, keyType, 
retType.getValueScale());
     }
 
     @Override
     protected void init(TJavaUdfExecutorCtorParams request, String jarPath, 
Type funcRetType,
             Type... parameterTypes) throws UdfRuntimeException {
         String className = request.fn.aggregate_fn.symbol;
-        inputPlacesPtr = request.input_places_ptr;
         allMethods = new HashMap<>();
         stateObjMap = new HashMap<>();
 
diff --git 
a/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/UdfExecutor.java
 
b/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/UdfExecutor.java
index 55a7ef89ea..f0319a5304 100644
--- 
a/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/UdfExecutor.java
+++ 
b/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/UdfExecutor.java
@@ -44,15 +44,6 @@ public class UdfExecutor extends BaseExecutor {
     // setup by init() and cleared by close()
     private Method method;
 
-    // Pre-constructed input objects for the UDF. This minimizes object 
creation
-    // overhead
-    // as these objects are reused across calls to evaluate().
-    private Object[] inputObjects;
-
-    private long outputOffset;
-    private long rowIdx;
-
-    private long batchSizePtr;
     private int evaluateIndex;
 
     /**
@@ -92,10 +83,10 @@ public class UdfExecutor extends BaseExecutor {
         PrimitiveType valueType = 
argTypes[argIdx].getValueType().getPrimitiveType();
         Object[] keyCol = convertMapArg(keyType, argIdx, isNullable, 0, 
numRows, nullMapAddr, offsetsAddr,
                 keyNestedNullMapAddr, keyDataAddr,
-                keyStrOffsetAddr);
+                keyStrOffsetAddr, argTypes[argIdx].getKeyScale());
         Object[] valueCol = convertMapArg(valueType, argIdx, isNullable, 0, 
numRows, nullMapAddr, offsetsAddr,
                 valueNestedNullMapAddr, valueDataAddr,
-                valueStrOffsetAddr);
+                valueStrOffsetAddr, argTypes[argIdx].getValueScale());
         return buildHashMap(keyType, valueType, keyCol, valueCol);
     }
 
@@ -131,7 +122,7 @@ public class UdfExecutor extends BaseExecutor {
         Preconditions.checkState(result.length == numRows,
                 "copyBatchArrayResult result size should equal;");
         copyBatchArrayResultImpl(isNullable, numRows, result, nullMapAddr, 
offsetsAddr, nestedNullMapAddr, dataAddr,
-                strOffsetAddr, retType.getItemType().getPrimitiveType());
+                strOffsetAddr, retType.getItemType().getPrimitiveType(), 
retType.getScale());
     }
 
     public void copyBatchMapResult(boolean isNullable, int numRows, Object[] 
result, long nullMapAddr,
@@ -147,10 +138,10 @@ public class UdfExecutor extends BaseExecutor {
 
         copyBatchArrayResultImpl(isNullable, numRows, valueCol, nullMapAddr, 
offsetsAddr, valueNsestedNullMapAddr,
                 valueDataAddr,
-                valueStrOffsetAddr, valueType);
+                valueStrOffsetAddr, valueType, retType.getKeyScale());
         copyBatchArrayResultImpl(isNullable, numRows, keyCol, nullMapAddr, 
offsetsAddr, keyNsestedNullMapAddr,
                 keyDataAddr,
-                keyStrOffsetAddr, keyType);
+                keyStrOffsetAddr, keyType, retType.getValueScale());
     }
 
     /**
@@ -168,21 +159,12 @@ public class UdfExecutor extends BaseExecutor {
         return method;
     }
 
-
-    @Override
-    protected void updateOutputOffset(long offset) {
-        outputOffset = offset;
-    }
-
     // Preallocate the input objects that will be passed to the underlying UDF.
     // These objects are allocated once and reused across calls to evaluate()
     @Override
     protected void init(TJavaUdfExecutorCtorParams request, String jarPath, 
Type funcRetType,
             Type... parameterTypes) throws UdfRuntimeException {
         String className = request.fn.scalar_fn.symbol;
-        batchSizePtr = request.batch_size_ptr;
-        outputOffset = 0L;
-        rowIdx = 0L;
         ArrayList<String> signatures = Lists.newArrayList();
         try {
             LOG.debug("Loading UDF '" + className + "' from " + jarPath);
diff --git a/regression-test/data/javaudf_p0/test_javaudf_with_decimal.out 
b/regression-test/data/javaudf_p0/test_javaudf_with_decimal.out
new file mode 100644
index 0000000000..4a05a63689
--- /dev/null
+++ b/regression-test/data/javaudf_p0/test_javaudf_with_decimal.out
@@ -0,0 +1,13 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !select_1 --
+[1.123, 1.123] 3
+[2.123, 2.123] 3
+
+-- !select_2 --
+{1.123:1.123457}       9
+{2.123:2.123457}       9
+
+-- !select_3 --
+1      {1.0000000000:1.1110000000}
+2      {2.0000000000:2.2220000000}
+
diff --git 
a/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyArrayDecimal.java
 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyArrayDecimal.java
new file mode 100644
index 0000000000..c689a44af9
--- /dev/null
+++ 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyArrayDecimal.java
@@ -0,0 +1,35 @@
+// 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.doris.udf;
+import java.math.BigDecimal;
+
+import org.apache.hadoop.hive.ql.exec.UDF;
+import org.apache.log4j.Logger;
+import java.util.*;
+
+public class MyArrayDecimal extends UDF {
+    private static final Logger LOG = Logger.getLogger(MyArrayDecimal.class);
+
+    public Integer evaluate(ArrayList<BigDecimal> arr) {
+        Integer scale = 0;
+        for (BigDecimal value : arr) {
+            scale = value.scale();
+        }
+        return scale;
+    }
+}
diff --git 
a/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyMapDecimal.java
 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyMapDecimal.java
new file mode 100644
index 0000000000..f33c230b37
--- /dev/null
+++ 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyMapDecimal.java
@@ -0,0 +1,35 @@
+// 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.doris.udf;
+import java.math.BigDecimal;
+
+import org.apache.hadoop.hive.ql.exec.UDF;
+import org.apache.log4j.Logger;
+import java.util.*;
+
+public class MyMapDecimal extends UDF {
+    private static final Logger LOG = Logger.getLogger(MyMapDecimal.class);
+
+    public Integer evaluate(HashMap<BigDecimal, BigDecimal> mp) {
+        Integer scale = 0;
+        for (Map.Entry<BigDecimal, BigDecimal> value : mp.entrySet()) {
+            scale = value.getKey().scale() + value.getValue().scale();
+        }
+        return scale;
+    }
+}
diff --git 
a/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyMapRetDecimal.java
 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyMapRetDecimal.java
new file mode 100644
index 0000000000..b5c860de94
--- /dev/null
+++ 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyMapRetDecimal.java
@@ -0,0 +1,42 @@
+// 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.doris.udf;
+import java.math.BigDecimal;
+
+import org.apache.hadoop.hive.ql.exec.UDF;
+import org.apache.log4j.Logger;
+import java.util.*;
+
+public class MyMapRetDecimal extends UDF {
+    private static final Logger LOG = Logger.getLogger(MyMapRetDecimal.class);
+
+    public HashMap<BigDecimal, BigDecimal> evaluate(int id) {
+        BigDecimal idBigDecimal = new BigDecimal(id);
+
+        BigDecimal result = BigDecimal.ZERO;
+        result = result.add(idBigDecimal.divide(new BigDecimal("1")));
+        result = result.add(idBigDecimal.divide(new BigDecimal("10")));
+        result = result.add(idBigDecimal.divide(new BigDecimal("100")));
+        result = result.add(idBigDecimal.divide(new BigDecimal("1000")));
+        HashMap<BigDecimal, BigDecimal> mp = new HashMap<>();
+        for (int i = 0; i < 10; i++) {
+            mp.put(idBigDecimal, result);
+        }
+        return mp;
+    }
+}
diff --git 
a/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyReturnMapString.java
 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyReturnMapString.java
index a416a8371e..17daa4e412 100644
--- 
a/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyReturnMapString.java
+++ 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MyReturnMapString.java
@@ -36,7 +36,6 @@ public class MyReturnMapString {
     }
 
     public void add(State state, Integer k, Double v) {
-        LOG.info("udaf nest  k v " + k + "  " + v);
         state.counter.put(k, v);
     }
 
diff --git 
a/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MySumReturnMapIntDou.java
 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MySumReturnMapIntDou.java
index 7a86666ef3..5e1c8bb265 100644
--- 
a/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MySumReturnMapIntDou.java
+++ 
b/regression-test/java-udf-src/src/main/java/org/apache/doris/udf/MySumReturnMapIntDou.java
@@ -39,7 +39,6 @@ public class MySumReturnMapIntDou {
     }
 
     public void add(State state, Integer k, Double v) {
-        LOG.info("udaf nest  k v " + k + "  " + v);
         state.counter.put(k, v);
     }
 
diff --git a/regression-test/suites/javaudf_p0/test_javaudf_agg_map.groovy 
b/regression-test/suites/javaudf_p0/test_javaudf_agg_map.groovy
index facd8fe1f9..03f84e5b34 100644
--- a/regression-test/suites/javaudf_p0/test_javaudf_agg_map.groovy
+++ b/regression-test/suites/javaudf_p0/test_javaudf_agg_map.groovy
@@ -27,9 +27,9 @@ suite("test_javaudf_agg_map") {
     try {
         try_sql("DROP FUNCTION IF EXISTS mapii(Map<Int,Int>);")
         try_sql("DROP FUNCTION IF EXISTS mapid(Map<Int,Double>);")
-        try_sql("DROP TABLE IF EXISTS db")
+        try_sql("DROP TABLE IF EXISTS db_agg_map")
         sql """
-             CREATE TABLE IF NOT EXISTS db(
+             CREATE TABLE IF NOT EXISTS db_agg_map(
                         `id` INT NULL COMMENT "",
                         `i` INT NULL COMMENT "",
                                                `d` Double NULL COMMENT "",
@@ -42,8 +42,8 @@ suite("test_javaudf_agg_map") {
             "replication_allocation" = "tag.location.default: 1",
             "storage_format" = "V2");
         """
-        sql """ INSERT INTO db VALUES(1, 
10,1.1,{1:1,10:1,100:1},{1:1.1,11:11.1});   """
-        sql """ INSERT INTO db VALUES(2, 
20,2.2,{2:2,20:2,200:2},{2:2.2,22:22.2});   """
+        sql """ INSERT INTO db_agg_map VALUES(1, 
10,1.1,{1:1,10:1,100:1},{1:1.1,11:11.1});   """
+        sql """ INSERT INTO db_agg_map VALUES(2, 
20,2.2,{2:2,20:2,200:2},{2:2.2,22:22.2});   """
 
         sql """
           
@@ -66,13 +66,13 @@ suite("test_javaudf_agg_map") {
         """
 
 
-        qt_select_1 """ select mapid(mid) from db; """
+        qt_select_1 """ select mapid(mid) from db_agg_map; """
 
-        qt_select_2 """ select mapii(mii) from db; """
+        qt_select_2 """ select mapii(mii) from db_agg_map; """
 
     } finally {
         try_sql("DROP FUNCTION IF EXISTS mapii(Map<Int,Int>);")
         try_sql("DROP FUNCTION IF EXISTS mapid(Map<Int,Double>);")
-        try_sql("DROP TABLE IF EXISTS db")
+        try_sql("DROP TABLE IF EXISTS db_agg_map")
     }
 }
diff --git a/regression-test/suites/javaudf_p0/test_javaudf_with_decimal.groovy 
b/regression-test/suites/javaudf_p0/test_javaudf_with_decimal.groovy
new file mode 100644
index 0000000000..bf28872831
--- /dev/null
+++ b/regression-test/suites/javaudf_p0/test_javaudf_with_decimal.groovy
@@ -0,0 +1,97 @@
+// 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.
+
+import org.codehaus.groovy.runtime.IOGroovyMethods
+
+import java.nio.charset.StandardCharsets
+import java.nio.file.Files
+import java.nio.file.Paths
+
+suite("test_javaudf_with_decimal") {
+    def jarPath = 
"""${context.file.parent}/jars/java-udf-case-jar-with-dependencies.jar"""
+    log.info("Jar path: ${jarPath}".toString())
+    try {
+        try_sql("drop function IF EXISTS getarrscale(Array<Decimal(15,3)>);")
+        try_sql("drop function IF EXISTS 
getmapscale(Map<Decimal(15,3),Decimal(15,6)>);")
+        try_sql("drop function IF EXISTS retscale(int);")
+        try_sql("drop table IF EXISTS dbwithDecimal;")
+        sql """
+             CREATE TABLE IF NOT EXISTS dbwithDecimal (
+            `id` INT(11) NULL COMMENT "" ,
+            `arr` Array<Decimal(15,3)> NULL COMMENT ""   ,
+            `mp` Map<Decimal(15,3),Decimal(15,6)> NULL COMMENT ""
+                        ) ENGINE=OLAP
+                        DUPLICATE KEY(`id`)
+                        DISTRIBUTED BY HASH(`id`) BUCKETS 1
+                        PROPERTIES (
+                        "replication_allocation" = "tag.location.default: 1",
+                        "storage_format" = "V2"
+            );
+        """
+        sql """ INSERT INTO dbwithDecimal 
VALUES(1,[1.123,1.123456],{1.123:1.123456789});   """
+        sql """ INSERT INTO dbwithDecimal 
VALUES(2,[2.123,2.123456],{2.123:2.123456789});   """
+
+
+        sql """
+          
+        CREATE FUNCTION getarrscale(Array<Decimal(15,3)>) RETURNS int 
PROPERTIES (
+            "file"="file://${jarPath}",
+            "symbol"="org.apache.doris.udf.MyArrayDecimal",
+            "always_nullable"="true",
+            "type"="JAVA_UDF"
+        ); 
+        
+        """
+        
+        sql """
+          
+        CREATE FUNCTION getmapscale(Map<Decimal(15,3),Decimal(15,6)>) RETURNS 
int PROPERTIES (
+            "file"="file://${jarPath}",
+            "symbol"="org.apache.doris.udf.MyMapDecimal",
+            "always_nullable"="true",
+            "type"="JAVA_UDF"
+        );
+        
+        """
+
+
+        sql """
+          
+        CREATE FUNCTION retscale(int) RETURNS 
Map<Decimal(15,10),Decimal(15,10)> PROPERTIES (
+            "file"="file://${jarPath}",
+            "symbol"="org.apache.doris.udf.MyMapRetDecimal",
+            "always_nullable"="true",
+            "type"="JAVA_UDF"
+        );
+        """
+
+        sql """
+            set enable_nereids_planner=false;
+        """
+
+        qt_select_1 """ select arr,getarrscale(arr) from dbwithDecimal order 
by id; """
+
+        qt_select_2 """ select mp,getmapscale(mp) from dbwithDecimal order by 
id ; """
+
+        qt_select_3 """ select id,retscale(id) from dbwithDecimal order by id; 
"""
+    } finally {
+        try_sql("drop function IF EXISTS getarrscale(Array<Decimal(15,3)>);")
+        try_sql("drop function IF EXISTS 
getmapscale(Map<Decimal(15,3),Decimal(15,6)>);")
+        try_sql("drop function IF EXISTS retscale(int);")
+        try_sql("drop table IF EXISTS dbwithDecimal;")
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org


Reply via email to