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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]