[vectorized](udaf) java udaf support with map type (#22397)

[vectorized](udaf) java udaf support with map type (#22397)
* test
* remove some unused
* update
* add case
This commit is contained in:
Mryange
2023-08-02 15:03:44 +08:00
committed by GitHub
parent 16461fdc1c
commit ddd90855a9
11 changed files with 915 additions and 683 deletions

View File

@ -25,6 +25,7 @@ import org.apache.doris.common.jni.utils.UdfUtils;
import org.apache.doris.common.jni.utils.UdfUtils.JavaUdfDataType;
import org.apache.doris.thrift.TJavaUdfExecutorCtorParams;
import com.esotericsoftware.reflectasm.MethodAccess;
import com.google.common.base.Preconditions;
import org.apache.log4j.Logger;
import org.apache.thrift.TDeserializer;
@ -33,6 +34,7 @@ import org.apache.thrift.protocol.TBinaryProtocol;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
@ -42,6 +44,8 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public abstract class BaseExecutor {
private static final Logger LOG = Logger.getLogger(BaseExecutor.class);
@ -88,12 +92,14 @@ public abstract class BaseExecutor {
protected final long outputArrayStringOffsetsPtr;
protected final long outputIntermediateStatePtr;
protected Class[] argClass;
protected MethodAccess methodAccess;
/**
* Create a UdfExecutor, using parameters from a serialized thrift object. Used
* by
* the backend.
*/
public BaseExecutor(byte[] thriftParams) throws Exception {
TJavaUdfExecutorCtorParams request = new TJavaUdfExecutorCtorParams();
TDeserializer deserializer = new TDeserializer(PROTOCOL_FACTORY);
@ -1320,4 +1326,498 @@ public abstract class BaseExecutor {
}
return argument;
}
public Object[] buildHashMap(PrimitiveType keyType, PrimitiveType valueType, Object[] keyCol, Object[] valueCol) {
switch (keyType) {
case BOOLEAN: {
return new HashMapBuilder<Boolean>().get(keyCol, valueCol, valueType);
}
case TINYINT: {
return new HashMapBuilder<Byte>().get(keyCol, valueCol, valueType);
}
case SMALLINT: {
return new HashMapBuilder<Short>().get(keyCol, valueCol, valueType);
}
case INT: {
return new HashMapBuilder<Integer>().get(keyCol, valueCol, valueType);
}
case BIGINT: {
return new HashMapBuilder<Long>().get(keyCol, valueCol, valueType);
}
case LARGEINT: {
return new HashMapBuilder<BigInteger>().get(keyCol, valueCol, valueType);
}
case FLOAT: {
return new HashMapBuilder<Float>().get(keyCol, valueCol, valueType);
}
case DOUBLE: {
return new HashMapBuilder<Double>().get(keyCol, valueCol, valueType);
}
case CHAR:
case VARCHAR:
case STRING: {
return new HashMapBuilder<String>().get(keyCol, valueCol, valueType);
}
case DATEV2:
case DATE: {
return new HashMapBuilder<LocalDate>().get(keyCol, valueCol, valueType);
}
case DATETIMEV2:
case DATETIME: {
return new HashMapBuilder<LocalDateTime>().get(keyCol, valueCol, valueType);
}
case DECIMAL32:
case DECIMAL64:
case DECIMALV2:
case DECIMAL128: {
return new HashMapBuilder<BigDecimal>().get(keyCol, valueCol, valueType);
}
default: {
LOG.info("Not support: " + keyType);
Preconditions.checkState(false, "Not support type " + keyType.toString());
break;
}
}
return null;
}
public static class HashMapBuilder<keyType> {
public Object[] get(Object[] keyCol, Object[] valueCol, PrimitiveType valueType) {
switch (valueType) {
case BOOLEAN: {
return new BuildMapFromType<keyType, Boolean>().get(keyCol, valueCol);
}
case TINYINT: {
return new BuildMapFromType<keyType, Byte>().get(keyCol, valueCol);
}
case SMALLINT: {
return new BuildMapFromType<keyType, Short>().get(keyCol, valueCol);
}
case INT: {
return new BuildMapFromType<keyType, Integer>().get(keyCol, valueCol);
}
case BIGINT: {
return new BuildMapFromType<keyType, Long>().get(keyCol, valueCol);
}
case LARGEINT: {
return new BuildMapFromType<keyType, BigInteger>().get(keyCol, valueCol);
}
case FLOAT: {
return new BuildMapFromType<keyType, Float>().get(keyCol, valueCol);
}
case DOUBLE: {
return new BuildMapFromType<keyType, Double>().get(keyCol, valueCol);
}
case CHAR:
case VARCHAR:
case STRING: {
return new BuildMapFromType<keyType, String>().get(keyCol, valueCol);
}
case DATEV2:
case DATE: {
return new BuildMapFromType<keyType, LocalDate>().get(keyCol, valueCol);
}
case DATETIMEV2:
case DATETIME: {
return new BuildMapFromType<keyType, LocalDateTime>().get(keyCol, valueCol);
}
case DECIMAL32:
case DECIMAL64:
case DECIMALV2:
case DECIMAL128: {
return new BuildMapFromType<keyType, BigDecimal>().get(keyCol, valueCol);
}
default: {
LOG.info("Not support: " + valueType);
Preconditions.checkState(false, "Not support type " + valueType.toString());
break;
}
}
return null;
}
}
public static class BuildMapFromType<T1, T2> {
public Object[] get(Object[] keyCol, Object[] valueCol) {
Object[] retHashMap = new HashMap[keyCol.length];
for (int colIdx = 0; colIdx < keyCol.length; colIdx++) {
HashMap<T1, T2> hashMap = new HashMap<>();
ArrayList<T1> keys = (ArrayList<T1>) (keyCol[colIdx]);
ArrayList<T2> values = (ArrayList<T2>) (valueCol[colIdx]);
for (int i = 0; i < keys.size(); i++) {
T1 key = keys.get(i);
T2 value = values.get(i);
if (!hashMap.containsKey(key)) {
hashMap.put(key, value);
}
}
retHashMap[colIdx] = hashMap;
}
return retHashMap;
}
}
public void copyBatchBasicResultImpl(boolean isNullable, int numRows, Object[] result, long nullMapAddr,
long resColumnAddr, long strOffsetAddr, Method method) {
switch (retType) {
case BOOLEAN: {
UdfConvert.copyBatchBooleanResult(isNullable, numRows, (Boolean[]) result, nullMapAddr, resColumnAddr);
break;
}
case TINYINT: {
UdfConvert.copyBatchTinyIntResult(isNullable, numRows, (Byte[]) result, nullMapAddr, resColumnAddr);
break;
}
case SMALLINT: {
UdfConvert.copyBatchSmallIntResult(isNullable, numRows, (Short[]) result, nullMapAddr, resColumnAddr);
break;
}
case INT: {
UdfConvert.copyBatchIntResult(isNullable, numRows, (Integer[]) result, nullMapAddr, resColumnAddr);
break;
}
case BIGINT: {
UdfConvert.copyBatchBigIntResult(isNullable, numRows, (Long[]) result, nullMapAddr, resColumnAddr);
break;
}
case LARGEINT: {
UdfConvert.copyBatchLargeIntResult(isNullable, numRows, (BigInteger[]) result, nullMapAddr,
resColumnAddr);
break;
}
case FLOAT: {
UdfConvert.copyBatchFloatResult(isNullable, numRows, (Float[]) result, nullMapAddr, resColumnAddr);
break;
}
case DOUBLE: {
UdfConvert.copyBatchDoubleResult(isNullable, numRows, (Double[]) result, nullMapAddr, resColumnAddr);
break;
}
case CHAR:
case VARCHAR:
case STRING: {
UdfConvert.copyBatchStringResult(isNullable, numRows, (String[]) result, nullMapAddr, resColumnAddr,
strOffsetAddr);
break;
}
case DATE: {
UdfConvert.copyBatchDateResult(method.getReturnType(), isNullable, numRows, result,
nullMapAddr, resColumnAddr);
break;
}
case DATETIME: {
UdfConvert
.copyBatchDateTimeResult(method.getReturnType(), isNullable, numRows, result,
nullMapAddr,
resColumnAddr);
break;
}
case DATEV2: {
UdfConvert.copyBatchDateV2Result(method.getReturnType(), isNullable, numRows, result,
nullMapAddr,
resColumnAddr);
break;
}
case DATETIMEV2: {
UdfConvert.copyBatchDateTimeV2Result(method.getReturnType(), isNullable, numRows,
result, nullMapAddr,
resColumnAddr);
break;
}
case DECIMALV2:
case DECIMAL128: {
UdfConvert.copyBatchDecimal128Result(retType.getScale(), isNullable, numRows, (BigDecimal[]) result,
nullMapAddr,
resColumnAddr);
break;
}
case DECIMAL32: {
UdfConvert.copyBatchDecimal32Result(retType.getScale(), isNullable, numRows, (BigDecimal[]) result,
nullMapAddr,
resColumnAddr);
break;
}
case DECIMAL64: {
UdfConvert.copyBatchDecimal64Result(retType.getScale(), isNullable, numRows, (BigDecimal[]) result,
nullMapAddr,
resColumnAddr);
break;
}
default: {
LOG.info("Not support return type: " + retType);
Preconditions.checkState(false, "Not support type: " + retType.toString());
break;
}
}
}
public void copyBatchArrayResultImpl(boolean isNullable, int numRows, Object[] result, long nullMapAddr,
long offsetsAddr, long nestedNullMapAddr, long dataAddr, long strOffsetAddr,
PrimitiveType type) {
long hasPutElementNum = 0;
for (int row = 0; row < numRows; ++row) {
switch (type) {
case BOOLEAN: {
hasPutElementNum = UdfConvert
.copyBatchArrayBooleanResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case TINYINT: {
hasPutElementNum = UdfConvert
.copyBatchArrayTinyIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case SMALLINT: {
hasPutElementNum = UdfConvert
.copyBatchArraySmallIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case INT: {
hasPutElementNum = UdfConvert
.copyBatchArrayIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case BIGINT: {
hasPutElementNum = UdfConvert
.copyBatchArrayBigIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case LARGEINT: {
hasPutElementNum = UdfConvert
.copyBatchArrayLargeIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case FLOAT: {
hasPutElementNum = UdfConvert
.copyBatchArrayFloatResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DOUBLE: {
hasPutElementNum = UdfConvert
.copyBatchArrayDoubleResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case CHAR:
case VARCHAR:
case STRING: {
hasPutElementNum = UdfConvert
.copyBatchArrayStringResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr, strOffsetAddr);
break;
}
case DATE: {
hasPutElementNum = UdfConvert
.copyBatchArrayDateResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DATETIME: {
hasPutElementNum = UdfConvert
.copyBatchArrayDateTimeResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DATEV2: {
hasPutElementNum = UdfConvert
.copyBatchArrayDateV2Result(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DATETIMEV2: {
hasPutElementNum = UdfConvert
.copyBatchArrayDateTimeV2Result(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DECIMALV2: {
hasPutElementNum = UdfConvert
.copyBatchArrayDecimalResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DECIMAL32: {
hasPutElementNum = UdfConvert
.copyBatchArrayDecimalV3Result(retType.getScale(), 4L, hasPutElementNum, isNullable, row,
result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DECIMAL64: {
hasPutElementNum = UdfConvert
.copyBatchArrayDecimalV3Result(retType.getScale(), 8L, hasPutElementNum, isNullable, row,
result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DECIMAL128: {
hasPutElementNum = UdfConvert
.copyBatchArrayDecimalV3Result(retType.getScale(), 16L, hasPutElementNum, isNullable, row,
result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
default: {
Preconditions.checkState(false, "Not support type in array: " + retType);
break;
}
}
}
}
public void buildArrayListFromHashMap(Object[] result, PrimitiveType keyType, PrimitiveType valueType,
Object[] keyCol, Object[] valueCol) {
switch (keyType) {
case BOOLEAN: {
new ArrayListBuilder<Boolean>().get(result, keyCol, valueCol, valueType);
break;
}
case TINYINT: {
new ArrayListBuilder<Byte>().get(result, keyCol, valueCol, valueType);
break;
}
case SMALLINT: {
new ArrayListBuilder<Short>().get(result, keyCol, valueCol, valueType);
break;
}
case INT: {
new ArrayListBuilder<Integer>().get(result, keyCol, valueCol, valueType);
break;
}
case BIGINT: {
new ArrayListBuilder<Long>().get(result, keyCol, valueCol, valueType);
break;
}
case LARGEINT: {
new ArrayListBuilder<BigInteger>().get(result, keyCol, valueCol, valueType);
break;
}
case FLOAT: {
new ArrayListBuilder<Float>().get(result, keyCol, valueCol, valueType);
break;
}
case DOUBLE: {
new ArrayListBuilder<Double>().get(result, keyCol, valueCol, valueType);
break;
}
case CHAR:
case VARCHAR:
case STRING: {
new ArrayListBuilder<String>().get(result, keyCol, valueCol, valueType);
break;
}
case DATEV2:
case DATE: {
new ArrayListBuilder<LocalDate>().get(result, keyCol, valueCol, valueType);
break;
}
case DATETIMEV2:
case DATETIME: {
new ArrayListBuilder<LocalDateTime>().get(result, keyCol, valueCol, valueType);
break;
}
case DECIMAL32:
case DECIMAL64:
case DECIMALV2:
case DECIMAL128: {
new ArrayListBuilder<BigDecimal>().get(result, keyCol, valueCol, valueType);
break;
}
default: {
LOG.info("Not support: " + keyType);
Preconditions.checkState(false, "Not support type " + keyType.toString());
break;
}
}
}
public static class ArrayListBuilder<keyType> {
public void get(Object[] map, Object[] keyCol, Object[] valueCol, PrimitiveType valueType) {
switch (valueType) {
case BOOLEAN: {
new BuildArrayFromType<keyType, Boolean>().get(map, keyCol, valueCol);
break;
}
case TINYINT: {
new BuildArrayFromType<keyType, Byte>().get(map, keyCol, valueCol);
break;
}
case SMALLINT: {
new BuildArrayFromType<keyType, Short>().get(map, keyCol, valueCol);
break;
}
case INT: {
new BuildArrayFromType<keyType, Integer>().get(map, keyCol, valueCol);
break;
}
case BIGINT: {
new BuildArrayFromType<keyType, Long>().get(map, keyCol, valueCol);
break;
}
case LARGEINT: {
new BuildArrayFromType<keyType, BigInteger>().get(map, keyCol, valueCol);
break;
}
case FLOAT: {
new BuildArrayFromType<keyType, Float>().get(map, keyCol, valueCol);
break;
}
case DOUBLE: {
new BuildArrayFromType<keyType, Double>().get(map, keyCol, valueCol);
break;
}
case CHAR:
case VARCHAR:
case STRING: {
new BuildArrayFromType<keyType, String>().get(map, keyCol, valueCol);
break;
}
case DATEV2:
case DATE: {
new BuildArrayFromType<keyType, LocalDate>().get(map, keyCol, valueCol);
break;
}
case DATETIMEV2:
case DATETIME: {
new BuildArrayFromType<keyType, LocalDateTime>().get(map, keyCol, valueCol);
break;
}
case DECIMAL32:
case DECIMAL64:
case DECIMALV2:
case DECIMAL128: {
new BuildArrayFromType<keyType, BigDecimal>().get(map, keyCol, valueCol);
break;
}
default: {
LOG.info("Not support: " + valueType);
Preconditions.checkState(false, "Not support type " + valueType.toString());
break;
}
}
}
}
public static class BuildArrayFromType<T1, T2> {
public void get(Object[] map, Object[] keyCol, Object[] valueCol) {
for (int colIdx = 0; colIdx < map.length; colIdx++) {
HashMap<T1, T2> hashMap = (HashMap<T1, T2>) map[colIdx];
ArrayList<T1> keys = new ArrayList<>();
ArrayList<T2> values = new ArrayList<>();
for (Map.Entry<T1, T2> entry : hashMap.entrySet()) {
keys.add(entry.getKey());
values.add(entry.getValue());
}
keyCol[colIdx] = keys;
valueCol[colIdx] = values;
}
}
}
}

View File

@ -17,6 +17,7 @@
package org.apache.doris.udf;
import org.apache.doris.catalog.PrimitiveType;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.Pair;
import org.apache.doris.common.exception.UdfRuntimeException;
@ -52,7 +53,6 @@ public class UdafExecutor extends BaseExecutor {
private HashMap<Long, Object> stateObjMap;
private Class retClass;
private int addIndex;
private MethodAccess methodAccess;
/**
* Constructor to create an object.
@ -81,6 +81,21 @@ public class UdafExecutor extends BaseExecutor {
dataAddr, strOffsetAddr);
}
public Object[] convertMapArguments(int argIdx, boolean isNullable, int rowStart, int rowEnd, long nullMapAddr,
long offsetsAddr, long keyNestedNullMapAddr, long keyDataAddr, long keyStrOffsetAddr,
long valueNestedNullMapAddr, long valueDataAddr, long valueStrOffsetAddr) {
PrimitiveType keyType = argTypes[argIdx].getKeyType().getPrimitiveType();
PrimitiveType valueType = argTypes[argIdx].getValueType().getPrimitiveType();
Object[] keyCol = convertMapArg(keyType, argIdx, isNullable, rowStart, rowEnd, nullMapAddr, offsetsAddr,
keyNestedNullMapAddr, keyDataAddr,
keyStrOffsetAddr);
Object[] valueCol = convertMapArg(valueType, argIdx, isNullable, rowStart, rowEnd, nullMapAddr, offsetsAddr,
valueNestedNullMapAddr,
valueDataAddr,
valueStrOffsetAddr);
return buildHashMap(keyType, valueType, keyCol, valueCol);
}
public void addBatch(boolean isSinglePlace, int rowStart, int rowEnd, long placeAddr, int offset, Object[] column)
throws UdfRuntimeException {
if (isSinglePlace) {
@ -111,7 +126,7 @@ public class UdafExecutor extends BaseExecutor {
methodAccess.invoke(udf, addIndex, inputArgs);
}
} catch (Exception e) {
LOG.warn("invoke add function meet some error: " + e.getCause().toString());
LOG.info("invoke add function meet some error: " + e.getCause().toString());
throw new UdfRuntimeException("UDAF failed to addBatchSingle: ", e);
}
}
@ -143,7 +158,7 @@ public class UdafExecutor extends BaseExecutor {
methodAccess.invoke(udf, addIndex, inputArgs);
}
} catch (Exception e) {
LOG.warn("invoke add function meet some error: " + Arrays.toString(e.getStackTrace()));
LOG.info("invoke add function meet some error: " + Arrays.toString(e.getStackTrace()));
throw new UdfRuntimeException("UDAF failed to addBatchPlaces: ", e);
}
}

View File

@ -34,14 +34,8 @@ import org.apache.log4j.Logger;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class UdfExecutor extends BaseExecutor {
// private static final java.util.logging.Logger LOG =
@ -60,7 +54,6 @@ public class UdfExecutor extends BaseExecutor {
private long batchSizePtr;
private int evaluateIndex;
private MethodAccess methodAccess;
/**
* Create a UdfExecutor, using parameters from a serialized thrift object. Used by
@ -147,57 +140,7 @@ public class UdfExecutor extends BaseExecutor {
Object[] valueCol = convertMapArg(valueType, argIdx, isNullable, 0, numRows, nullMapAddr, offsetsAddr,
valueNestedNullMapAddr, valueDataAddr,
valueStrOffsetAddr);
switch (keyType) {
case BOOLEAN: {
return new HashMapBuilder<Boolean>().get(keyCol, valueCol, valueType);
}
case TINYINT: {
return new HashMapBuilder<Byte>().get(keyCol, valueCol, valueType);
}
case SMALLINT: {
return new HashMapBuilder<Short>().get(keyCol, valueCol, valueType);
}
case INT: {
return new HashMapBuilder<Integer>().get(keyCol, valueCol, valueType);
}
case BIGINT: {
return new HashMapBuilder<Long>().get(keyCol, valueCol, valueType);
}
case LARGEINT: {
return new HashMapBuilder<BigInteger>().get(keyCol, valueCol, valueType);
}
case FLOAT: {
return new HashMapBuilder<Float>().get(keyCol, valueCol, valueType);
}
case DOUBLE: {
return new HashMapBuilder<Double>().get(keyCol, valueCol, valueType);
}
case CHAR:
case VARCHAR:
case STRING: {
return new HashMapBuilder<String>().get(keyCol, valueCol, valueType);
}
case DATEV2:
case DATE: {
return new HashMapBuilder<LocalDate>().get(keyCol, valueCol, valueType);
}
case DATETIMEV2:
case DATETIME: {
return new HashMapBuilder<LocalDateTime>().get(keyCol, valueCol, valueType);
}
case DECIMAL32:
case DECIMAL64:
case DECIMALV2:
case DECIMAL128: {
return new HashMapBuilder<BigDecimal>().get(keyCol, valueCol, valueType);
}
default: {
LOG.info("Not support: " + keyType);
Preconditions.checkState(false, "Not support type " + keyType.toString());
break;
}
}
return null;
return buildHashMap(keyType, valueType, keyCol, valueCol);
}
/**
@ -223,217 +166,7 @@ public class UdfExecutor extends BaseExecutor {
public void copyBatchBasicResult(boolean isNullable, int numRows, Object[] result, long nullMapAddr,
long resColumnAddr, long strOffsetAddr) {
switch (retType) {
case BOOLEAN: {
UdfConvert.copyBatchBooleanResult(isNullable, numRows, (Boolean[]) result, nullMapAddr, resColumnAddr);
break;
}
case TINYINT: {
UdfConvert.copyBatchTinyIntResult(isNullable, numRows, (Byte[]) result, nullMapAddr, resColumnAddr);
break;
}
case SMALLINT: {
UdfConvert.copyBatchSmallIntResult(isNullable, numRows, (Short[]) result, nullMapAddr, resColumnAddr);
break;
}
case INT: {
UdfConvert.copyBatchIntResult(isNullable, numRows, (Integer[]) result, nullMapAddr, resColumnAddr);
break;
}
case BIGINT: {
UdfConvert.copyBatchBigIntResult(isNullable, numRows, (Long[]) result, nullMapAddr, resColumnAddr);
break;
}
case LARGEINT: {
UdfConvert.copyBatchLargeIntResult(isNullable, numRows, (BigInteger[]) result, nullMapAddr,
resColumnAddr);
break;
}
case FLOAT: {
UdfConvert.copyBatchFloatResult(isNullable, numRows, (Float[]) result, nullMapAddr, resColumnAddr);
break;
}
case DOUBLE: {
UdfConvert.copyBatchDoubleResult(isNullable, numRows, (Double[]) result, nullMapAddr, resColumnAddr);
break;
}
case CHAR:
case VARCHAR:
case STRING: {
UdfConvert.copyBatchStringResult(isNullable, numRows, (String[]) result, nullMapAddr, resColumnAddr,
strOffsetAddr);
break;
}
case DATE: {
UdfConvert.copyBatchDateResult(method.getReturnType(), isNullable, numRows, result,
nullMapAddr, resColumnAddr);
break;
}
case DATETIME: {
UdfConvert
.copyBatchDateTimeResult(method.getReturnType(), isNullable, numRows, result,
nullMapAddr,
resColumnAddr);
break;
}
case DATEV2: {
UdfConvert.copyBatchDateV2Result(method.getReturnType(), isNullable, numRows, result,
nullMapAddr,
resColumnAddr);
break;
}
case DATETIMEV2: {
UdfConvert.copyBatchDateTimeV2Result(method.getReturnType(), isNullable, numRows,
result, nullMapAddr,
resColumnAddr);
break;
}
case DECIMALV2:
case DECIMAL128: {
UdfConvert.copyBatchDecimal128Result(retType.getScale(), isNullable, numRows, (BigDecimal[]) result,
nullMapAddr,
resColumnAddr);
break;
}
case DECIMAL32: {
UdfConvert.copyBatchDecimal32Result(retType.getScale(), isNullable, numRows, (BigDecimal[]) result,
nullMapAddr,
resColumnAddr);
break;
}
case DECIMAL64: {
UdfConvert.copyBatchDecimal64Result(retType.getScale(), isNullable, numRows, (BigDecimal[]) result,
nullMapAddr,
resColumnAddr);
break;
}
default: {
LOG.info("Not support return type: " + retType);
Preconditions.checkState(false, "Not support type: " + retType.toString());
break;
}
}
}
public void copyBatchArrayResultImpl(boolean isNullable, int numRows, Object[] result, long nullMapAddr,
long offsetsAddr, long nestedNullMapAddr, long dataAddr, long strOffsetAddr,
PrimitiveType type) {
long hasPutElementNum = 0;
for (int row = 0; row < numRows; ++row) {
switch (type) {
case BOOLEAN: {
hasPutElementNum = UdfConvert
.copyBatchArrayBooleanResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case TINYINT: {
hasPutElementNum = UdfConvert
.copyBatchArrayTinyIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case SMALLINT: {
hasPutElementNum = UdfConvert
.copyBatchArraySmallIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case INT: {
hasPutElementNum = UdfConvert
.copyBatchArrayIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case BIGINT: {
hasPutElementNum = UdfConvert
.copyBatchArrayBigIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case LARGEINT: {
hasPutElementNum = UdfConvert
.copyBatchArrayLargeIntResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case FLOAT: {
hasPutElementNum = UdfConvert
.copyBatchArrayFloatResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DOUBLE: {
hasPutElementNum = UdfConvert
.copyBatchArrayDoubleResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case CHAR:
case VARCHAR:
case STRING: {
hasPutElementNum = UdfConvert
.copyBatchArrayStringResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr, strOffsetAddr);
break;
}
case DATE: {
hasPutElementNum = UdfConvert
.copyBatchArrayDateResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DATETIME: {
hasPutElementNum = UdfConvert
.copyBatchArrayDateTimeResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DATEV2: {
hasPutElementNum = UdfConvert
.copyBatchArrayDateV2Result(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DATETIMEV2: {
hasPutElementNum = UdfConvert
.copyBatchArrayDateTimeV2Result(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DECIMALV2: {
hasPutElementNum = UdfConvert
.copyBatchArrayDecimalResult(hasPutElementNum, isNullable, row, result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DECIMAL32: {
hasPutElementNum = UdfConvert
.copyBatchArrayDecimalV3Result(retType.getScale(), 4L, hasPutElementNum, isNullable, row,
result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DECIMAL64: {
hasPutElementNum = UdfConvert
.copyBatchArrayDecimalV3Result(retType.getScale(), 8L, hasPutElementNum, isNullable, row,
result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
case DECIMAL128: {
hasPutElementNum = UdfConvert
.copyBatchArrayDecimalV3Result(retType.getScale(), 16L, hasPutElementNum, isNullable, row,
result, nullMapAddr,
offsetsAddr, nestedNullMapAddr, dataAddr);
break;
}
default: {
Preconditions.checkState(false, "Not support type in array: " + retType);
break;
}
}
}
copyBatchBasicResultImpl(isNullable, numRows, result, nullMapAddr, resColumnAddr, strOffsetAddr, getMethod());
}
public void copyBatchArrayResult(boolean isNullable, int numRows, Object[] result, long nullMapAddr,
@ -453,68 +186,7 @@ public class UdfExecutor extends BaseExecutor {
PrimitiveType valueType = retType.getValueType().getPrimitiveType();
Object[] keyCol = new Object[result.length];
Object[] valueCol = new Object[result.length];
switch (keyType) {
case BOOLEAN: {
new ArrayListBuilder<Boolean>().get(result, keyCol, valueCol, valueType);
break;
}
case TINYINT: {
new ArrayListBuilder<Byte>().get(result, keyCol, valueCol, valueType);
break;
}
case SMALLINT: {
new ArrayListBuilder<Short>().get(result, keyCol, valueCol, valueType);
break;
}
case INT: {
new ArrayListBuilder<Integer>().get(result, keyCol, valueCol, valueType);
break;
}
case BIGINT: {
new ArrayListBuilder<Long>().get(result, keyCol, valueCol, valueType);
break;
}
case LARGEINT: {
new ArrayListBuilder<BigInteger>().get(result, keyCol, valueCol, valueType);
break;
}
case FLOAT: {
new ArrayListBuilder<Float>().get(result, keyCol, valueCol, valueType);
break;
}
case DOUBLE: {
new ArrayListBuilder<Double>().get(result, keyCol, valueCol, valueType);
break;
}
case CHAR:
case VARCHAR:
case STRING: {
new ArrayListBuilder<String>().get(result, keyCol, valueCol, valueType);
break;
}
case DATEV2:
case DATE: {
new ArrayListBuilder<LocalDate>().get(result, keyCol, valueCol, valueType);
break;
}
case DATETIMEV2:
case DATETIME: {
new ArrayListBuilder<LocalDateTime>().get(result, keyCol, valueCol, valueType);
break;
}
case DECIMAL32:
case DECIMAL64:
case DECIMALV2:
case DECIMAL128: {
new ArrayListBuilder<BigDecimal>().get(result, keyCol, valueCol, valueType);
break;
}
default: {
LOG.info("Not support: " + keyType);
Preconditions.checkState(false, "Not support type " + keyType.toString());
break;
}
}
buildArrayListFromHashMap(result, keyType, valueType, keyCol, valueCol);
copyBatchArrayResultImpl(isNullable, numRows, valueCol, nullMapAddr, offsetsAddr, valueNsestedNullMapAddr,
valueDataAddr,
@ -522,7 +194,6 @@ public class UdfExecutor extends BaseExecutor {
copyBatchArrayResultImpl(isNullable, numRows, keyCol, nullMapAddr, offsetsAddr, keyNsestedNullMapAddr,
keyDataAddr,
keyStrOffsetAddr, keyType);
}
/**
@ -669,163 +340,4 @@ public class UdfExecutor extends BaseExecutor {
}
}
public static class HashMapBuilder<keyType> {
public Object[] get(Object[] keyCol, Object[] valueCol, PrimitiveType valueType) {
switch (valueType) {
case BOOLEAN: {
return new BuildMapFromType<keyType, Boolean>().get(keyCol, valueCol);
}
case TINYINT: {
return new BuildMapFromType<keyType, Byte>().get(keyCol, valueCol);
}
case SMALLINT: {
return new BuildMapFromType<keyType, Short>().get(keyCol, valueCol);
}
case INT: {
return new BuildMapFromType<keyType, Integer>().get(keyCol, valueCol);
}
case BIGINT: {
return new BuildMapFromType<keyType, Long>().get(keyCol, valueCol);
}
case LARGEINT: {
return new BuildMapFromType<keyType, BigInteger>().get(keyCol, valueCol);
}
case FLOAT: {
return new BuildMapFromType<keyType, Float>().get(keyCol, valueCol);
}
case DOUBLE: {
return new BuildMapFromType<keyType, Double>().get(keyCol, valueCol);
}
case CHAR:
case VARCHAR:
case STRING: {
return new BuildMapFromType<keyType, String>().get(keyCol, valueCol);
}
case DATEV2:
case DATE: {
return new BuildMapFromType<keyType, LocalDate>().get(keyCol, valueCol);
}
case DATETIMEV2:
case DATETIME: {
return new BuildMapFromType<keyType, LocalDateTime>().get(keyCol, valueCol);
}
case DECIMAL32:
case DECIMAL64:
case DECIMALV2:
case DECIMAL128: {
return new BuildMapFromType<keyType, BigDecimal>().get(keyCol, valueCol);
}
default: {
LOG.info("Not support: " + valueType);
Preconditions.checkState(false, "Not support type " + valueType.toString());
break;
}
}
return null;
}
}
public static class BuildMapFromType<T1, T2> {
public Object[] get(Object[] keyCol, Object[] valueCol) {
Object[] retHashMap = new HashMap[keyCol.length];
for (int colIdx = 0; colIdx < keyCol.length; colIdx++) {
HashMap<T1, T2> hashMap = new HashMap<>();
ArrayList<T1> keys = (ArrayList<T1>) (keyCol[colIdx]);
ArrayList<T2> values = (ArrayList<T2>) (valueCol[colIdx]);
for (int i = 0; i < keys.size(); i++) {
T1 key = keys.get(i);
T2 value = values.get(i);
if (!hashMap.containsKey(key)) {
hashMap.put(key, value);
}
}
retHashMap[colIdx] = hashMap;
}
return retHashMap;
}
}
public static class ArrayListBuilder<keyType> {
public void get(Object[] map, Object[] keyCol, Object[] valueCol, PrimitiveType valueType) {
switch (valueType) {
case BOOLEAN: {
new BuildArrayFromType<keyType, Boolean>().get(map, keyCol, valueCol);
break;
}
case TINYINT: {
new BuildArrayFromType<keyType, Byte>().get(map, keyCol, valueCol);
break;
}
case SMALLINT: {
new BuildArrayFromType<keyType, Short>().get(map, keyCol, valueCol);
break;
}
case INT: {
new BuildArrayFromType<keyType, Integer>().get(map, keyCol, valueCol);
break;
}
case BIGINT: {
new BuildArrayFromType<keyType, Long>().get(map, keyCol, valueCol);
break;
}
case LARGEINT: {
new BuildArrayFromType<keyType, BigInteger>().get(map, keyCol, valueCol);
break;
}
case FLOAT: {
new BuildArrayFromType<keyType, Float>().get(map, keyCol, valueCol);
break;
}
case DOUBLE: {
new BuildArrayFromType<keyType, Double>().get(map, keyCol, valueCol);
break;
}
case CHAR:
case VARCHAR:
case STRING: {
new BuildArrayFromType<keyType, String>().get(map, keyCol, valueCol);
break;
}
case DATEV2:
case DATE: {
new BuildArrayFromType<keyType, LocalDate>().get(map, keyCol, valueCol);
break;
}
case DATETIMEV2:
case DATETIME: {
new BuildArrayFromType<keyType, LocalDateTime>().get(map, keyCol, valueCol);
break;
}
case DECIMAL32:
case DECIMAL64:
case DECIMALV2:
case DECIMAL128: {
new BuildArrayFromType<keyType, BigDecimal>().get(map, keyCol, valueCol);
break;
}
default: {
LOG.info("Not support: " + valueType);
Preconditions.checkState(false, "Not support type " + valueType.toString());
break;
}
}
}
}
public static class BuildArrayFromType<T1, T2> {
public void get(Object[] map, Object[] keyCol, Object[] valueCol) {
for (int colIdx = 0; colIdx < map.length; colIdx++) {
HashMap<T1, T2> hashMap = (HashMap<T1, T2>) map[colIdx];
ArrayList<T1> keys = new ArrayList<>();
ArrayList<T2> values = new ArrayList<>();
for (Map.Entry<T1, T2> entry : hashMap.entrySet()) {
keys.add(entry.getKey());
values.add(entry.getValue());
}
keyCol[colIdx] = keys;
valueCol[colIdx] = values;
}
}
}
}