[Bug](udf) fix java-udaf process string type error and add some tests (#14106)
This commit is contained in:
@ -70,6 +70,7 @@ public:
|
||||
RETURN_IF_STATUS_ERROR(status, JniUtil::GetJNIEnv(&env));
|
||||
env->CallNonvirtualVoidMethod(executor_obj, executor_cl, executor_close_id);
|
||||
RETURN_IF_STATUS_ERROR(status, JniUtil::GetJniExceptionMsg(env));
|
||||
env->DeleteGlobalRef(executor_cl);
|
||||
env->DeleteGlobalRef(executor_obj);
|
||||
}
|
||||
|
||||
@ -161,6 +162,9 @@ public:
|
||||
jbyteArray arr = env->NewByteArray(len);
|
||||
env->SetByteArrayRegion(arr, 0, len, reinterpret_cast<jbyte*>(serialize_data.data()));
|
||||
env->CallNonvirtualVoidMethod(executor_obj, executor_cl, executor_merge_id, place, arr);
|
||||
jbyte* pBytes = env->GetByteArrayElements(arr, nullptr);
|
||||
env->ReleaseByteArrayElements(arr, pBytes, JNI_ABORT);
|
||||
env->DeleteLocalRef(arr);
|
||||
return JniUtil::GetJniExceptionMsg(env);
|
||||
}
|
||||
|
||||
@ -175,6 +179,9 @@ public:
|
||||
serialize_data.resize(len);
|
||||
env->GetByteArrayRegion(arr, 0, len, reinterpret_cast<jbyte*>(serialize_data.data()));
|
||||
write_binary(serialize_data, buf);
|
||||
jbyte* pBytes = env->GetByteArrayElements(arr, nullptr);
|
||||
env->ReleaseByteArrayElements(arr, pBytes, JNI_ABORT);
|
||||
env->DeleteLocalRef(arr);
|
||||
return JniUtil::GetJniExceptionMsg(env);
|
||||
}
|
||||
|
||||
@ -205,16 +212,18 @@ public:
|
||||
ColumnString::Offsets& offsets = \
|
||||
const_cast<ColumnString::Offsets&>(str_col->get_offsets()); \
|
||||
int increase_buffer_size = 0; \
|
||||
int32_t buffer_size = JniUtil::IncreaseReservedBufferSize(increase_buffer_size); \
|
||||
chars.resize(buffer_size); \
|
||||
*output_value_buffer = reinterpret_cast<int64_t>(chars.data()); \
|
||||
*output_offsets_ptr = reinterpret_cast<int64_t>(offsets.data()); \
|
||||
*output_intermediate_state_ptr = chars.size(); \
|
||||
jboolean res = env->CallNonvirtualBooleanMethod(executor_obj, executor_cl, \
|
||||
executor_result_id, to.size() - 1, place); \
|
||||
while (res != JNI_TRUE) { \
|
||||
int32_t buffer_size = JniUtil::IncreaseReservedBufferSize(increase_buffer_size); \
|
||||
increase_buffer_size++; \
|
||||
chars.reserve(chars.size() + buffer_size); \
|
||||
chars.resize(chars.size() + buffer_size); \
|
||||
int32_t buffer_size = JniUtil::IncreaseReservedBufferSize(increase_buffer_size); \
|
||||
chars.resize(buffer_size); \
|
||||
*output_value_buffer = reinterpret_cast<int64_t>(chars.data()); \
|
||||
*output_intermediate_state_ptr = chars.size(); \
|
||||
res = env->CallNonvirtualBooleanMethod(executor_obj, executor_cl, executor_result_id, \
|
||||
to.size() - 1, place); \
|
||||
@ -231,11 +240,8 @@ public:
|
||||
EVALUATE_JAVA_UDAF;
|
||||
} else {
|
||||
*output_null_value = -1;
|
||||
*output_value_buffer = reinterpret_cast<int64_t>(to.get_raw_data().data);
|
||||
auto& data_col = to;
|
||||
EVALUATE_JAVA_UDAF;
|
||||
env->CallNonvirtualBooleanMethod(executor_obj, executor_cl, executor_result_id,
|
||||
to.size() - 1, place);
|
||||
}
|
||||
return JniUtil::GetJniExceptionMsg(env);
|
||||
}
|
||||
|
||||
@ -75,17 +75,21 @@ Instructions:
|
||||
1. `symbol` in properties represents the class name containing UDF classes. This parameter must be set.
|
||||
2. The jar package containing UDF represented by `file` in properties must be set.
|
||||
3. The UDF call type represented by `type` in properties is native by default. When using java UDF, it is transferred to `Java_UDF`.
|
||||
4. `name`: A function belongs to a DB and name is of the form`dbName`.`funcName`. When `dbName` is not explicitly specified, the db of the current session is used`dbName`.
|
||||
4. In PROPERTIES `always_nullable` indicates whether there may be a NULL value in the UDF return result. It is an optional parameter. The default value is true.
|
||||
5. `name`: A function belongs to a DB and name is of the form`dbName`.`funcName`. When `dbName` is not explicitly specified, the db of the current session is used`dbName`.
|
||||
|
||||
Sample:
|
||||
```sql
|
||||
CREATE FUNCTION java_udf_add_one(int) RETURNS int PROPERTIES (
|
||||
"file"="file:///path/to/java-udf-demo-jar-with-dependencies.jar",
|
||||
"symbol"="org.apache.doris.udf.AddOne",
|
||||
"always_nullable"="true",
|
||||
"type"="JAVA_UDF"
|
||||
);
|
||||
```
|
||||
* "file"=" http://IP:port/udf -code. Jar ", you can also use http to download jar packages in a multi machine environment.
|
||||
|
||||
* The "always_nullable" is optional attribute, if there is special treatment for the NULL value in the calculation, it is determined that the result will not return NULL, and it can be set to false, so that the performance may be better in the whole calculation process.
|
||||
## Create UDAF
|
||||
<br/>
|
||||
When using Java code to write UDAF, there are some functions that must be implemented (mark required) and an inner class State, which will be explained with a specific example below.
|
||||
@ -155,6 +159,7 @@ public class SimpleDemo {
|
||||
CREATE AGGREGATE FUNCTION simple_sum(INT) RETURNS INT PROPERTIES (
|
||||
"file"="file:///pathTo/java-udaf.jar",
|
||||
"symbol"="org.apache.doris.udf.SimpleDemo",
|
||||
"always_nullable"="true",
|
||||
"type"="JAVA_UDF"
|
||||
);
|
||||
```
|
||||
|
||||
@ -74,16 +74,20 @@ PROPERTIES (["key"="value"][,...])
|
||||
1. PROPERTIES中`symbol`表示的是包含UDF类的类名,这个参数是必须设定的。
|
||||
2. PROPERTIES中`file`表示的包含用户UDF的jar包,这个参数是必须设定的。
|
||||
3. PROPERTIES中`type`表示的 UDF 调用类型,默认为 Native,使用 Java UDF时传 JAVA_UDF。
|
||||
4. name: 一个function是要归属于某个DB的,name的形式为`dbName`.`funcName`。当`dbName`没有明确指定的时候,就是使用当前session所在的db作为`dbName`。
|
||||
4. PROPERTIES中`always_nullable`表示的 UDF 返回结果中是否有可能出现NULL值,是可选参数,默认值为true。
|
||||
5. name: 一个function是要归属于某个DB的,name的形式为`dbName`.`funcName`。当`dbName`没有明确指定的时候,就是使用当前session所在的db作为`dbName`。
|
||||
|
||||
示例:
|
||||
```sql
|
||||
CREATE FUNCTION java_udf_add_one(int) RETURNS int PROPERTIES (
|
||||
"file"="file:///path/to/java-udf-demo-jar-with-dependencies.jar",
|
||||
"symbol"="org.apache.doris.udf.AddOne",
|
||||
"always_nullable"="true",
|
||||
"type"="JAVA_UDF"
|
||||
);
|
||||
```
|
||||
* "file"="http://IP:port/udf-code.jar", 当在多机环境时,也可以使用http的方式下载jar包
|
||||
* "always_nullable"可选属性, 如果在计算中对出现的NULL值有特殊处理,确定结果中不会返回NULL,可以设为false,这样在整个查询计算过程中性能可能更好些。
|
||||
|
||||
## 编写 UDAF 函数
|
||||
<br/>
|
||||
@ -154,6 +158,7 @@ public class SimpleDemo {
|
||||
CREATE AGGREGATE FUNCTION simple_sum(int) RETURNS int PROPERTIES (
|
||||
"file"="file:///pathTo/java-udaf.jar",
|
||||
"symbol"="org.apache.doris.udf.SimpleDemo",
|
||||
"always_nullable"="true",
|
||||
"type"="JAVA_UDF"
|
||||
);
|
||||
```
|
||||
|
||||
@ -21,6 +21,7 @@ import org.apache.doris.catalog.AggregateFunction;
|
||||
import org.apache.doris.catalog.AliasFunction;
|
||||
import org.apache.doris.catalog.Env;
|
||||
import org.apache.doris.catalog.Function;
|
||||
import org.apache.doris.catalog.Function.NullableMode;
|
||||
import org.apache.doris.catalog.PrimitiveType;
|
||||
import org.apache.doris.catalog.ScalarFunction;
|
||||
import org.apache.doris.catalog.ScalarType;
|
||||
@ -96,6 +97,8 @@ public class CreateFunctionStmt extends DdlStmt {
|
||||
public static final String MERGE_METHOD_NAME = "merge";
|
||||
public static final String GETVALUE_METHOD_NAME = "getValue";
|
||||
public static final String STATE_CLASS_NAME = "State";
|
||||
// add for java udf check return type nullable mode, always_nullable or always_not_nullable
|
||||
public static final String IS_RETURN_NULL = "always_nullable";
|
||||
private static final Logger LOG = LogManager.getLogger(CreateFunctionStmt.class);
|
||||
|
||||
private final FunctionName functionName;
|
||||
@ -113,12 +116,16 @@ public class CreateFunctionStmt extends DdlStmt {
|
||||
private String userFile;
|
||||
private Function function;
|
||||
private String checksum = "";
|
||||
// now set udf default NullableMode is ALWAYS_NULLABLE
|
||||
// if not, will core dump when input is not null column, but need return null
|
||||
// like https://github.com/apache/doris/pull/14002/files
|
||||
private NullableMode returnNullMode = NullableMode.ALWAYS_NULLABLE;
|
||||
|
||||
// timeout for both connection and read. 10 seconds is long enough.
|
||||
private static final int HTTP_TIMEOUT_MS = 10000;
|
||||
|
||||
public CreateFunctionStmt(boolean isAggregate, FunctionName functionName, FunctionArgsDef argsDef,
|
||||
TypeDef returnType, TypeDef intermediateType, Map<String, String> properties) {
|
||||
TypeDef returnType, TypeDef intermediateType, Map<String, String> properties) {
|
||||
this.functionName = functionName;
|
||||
this.isAggregate = isAggregate;
|
||||
this.argsDef = argsDef;
|
||||
@ -135,7 +142,7 @@ public class CreateFunctionStmt extends DdlStmt {
|
||||
}
|
||||
|
||||
public CreateFunctionStmt(FunctionName functionName, FunctionArgsDef argsDef,
|
||||
List<String> parameters, Expr originFunction) {
|
||||
List<String> parameters, Expr originFunction) {
|
||||
this.functionName = functionName;
|
||||
this.isAlias = true;
|
||||
this.argsDef = argsDef;
|
||||
@ -221,6 +228,19 @@ public class CreateFunctionStmt extends DdlStmt {
|
||||
throw new AnalysisException("library's checksum is not equal with input, checksum=" + checksum);
|
||||
}
|
||||
}
|
||||
if (binaryType == TFunctionBinaryType.JAVA_UDF) {
|
||||
String returnNullModeStr = properties.get(IS_RETURN_NULL);
|
||||
if (returnNullModeStr == null) {
|
||||
return;
|
||||
}
|
||||
if (!returnNullModeStr.equalsIgnoreCase("false") && !returnNullModeStr.equalsIgnoreCase("true")) {
|
||||
throw new AnalysisException("'always_nullable' in properties, you should set it false or true");
|
||||
}
|
||||
|
||||
if (!Boolean.parseBoolean(returnNullModeStr)) {
|
||||
returnNullMode = NullableMode.ALWAYS_NOT_NULLABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void computeObjectChecksum() throws IOException, NoSuchAlgorithmException {
|
||||
@ -302,6 +322,7 @@ public class CreateFunctionStmt extends DdlStmt {
|
||||
function.setLocation(location);
|
||||
function.setBinaryType(binaryType);
|
||||
function.setChecksum(checksum);
|
||||
function.setNullableMode(returnNullMode);
|
||||
}
|
||||
|
||||
private void analyzeUdf() throws AnalysisException {
|
||||
@ -327,6 +348,7 @@ public class CreateFunctionStmt extends DdlStmt {
|
||||
returnType.getType(), argsDef.isVariadic(),
|
||||
location, symbol, prepareFnSymbol, closeFnSymbol);
|
||||
function.setChecksum(checksum);
|
||||
function.setNullableMode(returnNullMode);
|
||||
}
|
||||
|
||||
private void analyzeJavaUdaf(String clazz) throws AnalysisException {
|
||||
|
||||
@ -796,6 +796,10 @@ public class Function implements Writable {
|
||||
return vectorized;
|
||||
}
|
||||
|
||||
public void setNullableMode(NullableMode nullableMode) {
|
||||
this.nullableMode = nullableMode;
|
||||
}
|
||||
|
||||
public NullableMode getNullableMode() {
|
||||
return nullableMode;
|
||||
}
|
||||
|
||||
@ -339,7 +339,6 @@ public class ScalarFunction extends Function {
|
||||
fn.prepareFnSymbol = prepareFnSymbol;
|
||||
fn.closeFnSymbol = closeFnSymbol;
|
||||
fn.setLocation(location);
|
||||
fn.nullableMode = NullableMode.ALWAYS_NULLABLE;
|
||||
return fn;
|
||||
}
|
||||
|
||||
|
||||
@ -232,6 +232,9 @@ public class UdafExecutor {
|
||||
private boolean storeUdfResult(Object obj, long row) throws UdfRuntimeException {
|
||||
if (obj == null) {
|
||||
// If result is null, return true directly when row == 0 as we have already inserted default value.
|
||||
if (UdfUtils.UNSAFE.getLong(null, outputNullPtr) == -1) {
|
||||
throw new UdfRuntimeException("UDAF failed to store null data to not null column");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (UdfUtils.UNSAFE.getLong(null, outputNullPtr) != -1) {
|
||||
@ -332,12 +335,11 @@ public class UdafExecutor {
|
||||
}
|
||||
case CHAR:
|
||||
case VARCHAR:
|
||||
case STRING:
|
||||
case STRING: {
|
||||
long bufferSize = UdfUtils.UNSAFE.getLong(null, outputIntermediateStatePtr);
|
||||
byte[] bytes = ((String) obj).getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
long offset = Integer.toUnsignedLong(
|
||||
UdfUtils.UNSAFE.getInt(null, UdfUtils.UNSAFE.getLong(null, outputOffsetsPtr) + 4L * row));
|
||||
UdfUtils.UNSAFE.getInt(null, UdfUtils.UNSAFE.getLong(null, outputOffsetsPtr) + 4L * (row - 1)));
|
||||
if (offset + bytes.length > bufferSize) {
|
||||
return false;
|
||||
}
|
||||
@ -347,6 +349,7 @@ public class UdafExecutor {
|
||||
UdfUtils.copyMemory(bytes, UdfUtils.BYTE_ARRAY_OFFSET, null,
|
||||
UdfUtils.UNSAFE.getLong(null, outputBufferPtr) + offset - bytes.length, bytes.length);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
throw new UdfRuntimeException("Unsupported return type: " + retType);
|
||||
}
|
||||
@ -394,25 +397,25 @@ public class UdafExecutor {
|
||||
case DATE: {
|
||||
long data = UdfUtils.UNSAFE.getLong(null,
|
||||
UdfUtils.UNSAFE.getLong(null, UdfUtils.getAddressAtOffset(inputBufferPtrs, i)) + 8L * row);
|
||||
inputObjects[i] = UdfUtils.convertDateToJavaDate(data, argClass[i]);
|
||||
inputObjects[i] = UdfUtils.convertDateToJavaDate(data, argClass[i + 1]);
|
||||
break;
|
||||
}
|
||||
case DATETIME: {
|
||||
long data = UdfUtils.UNSAFE.getLong(null,
|
||||
UdfUtils.UNSAFE.getLong(null, UdfUtils.getAddressAtOffset(inputBufferPtrs, i)) + 8L * row);
|
||||
inputObjects[i] = UdfUtils.convertDateTimeToJavaDateTime(data, argClass[i]);
|
||||
inputObjects[i] = UdfUtils.convertDateTimeToJavaDateTime(data, argClass[i + 1]);
|
||||
break;
|
||||
}
|
||||
case DATEV2: {
|
||||
int data = UdfUtils.UNSAFE.getInt(null,
|
||||
UdfUtils.UNSAFE.getLong(null, UdfUtils.getAddressAtOffset(inputBufferPtrs, i)) + 4L * row);
|
||||
inputObjects[i] = UdfUtils.convertDateV2ToJavaDate(data, argClass[i]);
|
||||
inputObjects[i] = UdfUtils.convertDateV2ToJavaDate(data, argClass[i + 1]);
|
||||
break;
|
||||
}
|
||||
case DATETIMEV2: {
|
||||
long data = UdfUtils.UNSAFE.getLong(null,
|
||||
UdfUtils.UNSAFE.getLong(null, UdfUtils.getAddressAtOffset(inputBufferPtrs, i)) + 8L * row);
|
||||
inputObjects[i] = UdfUtils.convertDateTimeV2ToJavaDateTime(data, argClass[i]);
|
||||
inputObjects[i] = UdfUtils.convertDateTimeV2ToJavaDateTime(data, argClass[i + 1]);
|
||||
break;
|
||||
}
|
||||
case LARGEINT: {
|
||||
@ -436,21 +439,22 @@ public class UdafExecutor {
|
||||
}
|
||||
case CHAR:
|
||||
case VARCHAR:
|
||||
case STRING:
|
||||
case STRING: {
|
||||
long offset = Integer.toUnsignedLong(UdfUtils.UNSAFE.getInt(null,
|
||||
UdfUtils.UNSAFE.getLong(null, UdfUtils.getAddressAtOffset(inputOffsetsPtrs, i))
|
||||
+ 4L * row));
|
||||
long numBytes = row == 0 ? offset - 1 : offset - Integer.toUnsignedLong(UdfUtils.UNSAFE.getInt(null,
|
||||
long numBytes = row == 0 ? offset : offset - Integer.toUnsignedLong(UdfUtils.UNSAFE.getInt(null,
|
||||
UdfUtils.UNSAFE.getLong(null, UdfUtils.getAddressAtOffset(inputOffsetsPtrs, i)) + 4L * (row
|
||||
- 1))) - 1;
|
||||
- 1)));
|
||||
long base = row == 0 ? UdfUtils.UNSAFE.getLong(null,
|
||||
UdfUtils.getAddressAtOffset(inputBufferPtrs, i))
|
||||
: UdfUtils.UNSAFE.getLong(null, UdfUtils.getAddressAtOffset(inputBufferPtrs, i)) + offset
|
||||
- numBytes - 1;
|
||||
- numBytes;
|
||||
byte[] bytes = new byte[(int) numBytes];
|
||||
UdfUtils.copyMemory(null, base, bytes, UdfUtils.BYTE_ARRAY_OFFSET, numBytes);
|
||||
inputObjects[i] = new String(bytes, StandardCharsets.UTF_8);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new UdfRuntimeException("Unsupported argument type: " + argTypes[i]);
|
||||
}
|
||||
|
||||
@ -215,7 +215,9 @@ public class UdfExecutor {
|
||||
// Sets the result object 'obj' into the outputBufferPtr and outputNullPtr_
|
||||
private boolean storeUdfResult(Object obj, long row) throws UdfRuntimeException {
|
||||
if (obj == null) {
|
||||
assert (UdfUtils.UNSAFE.getLong(null, outputNullPtr) != -1);
|
||||
if (UdfUtils.UNSAFE.getLong(null, outputNullPtr) == -1) {
|
||||
throw new UdfRuntimeException("UDF failed to store null data to not null column");
|
||||
}
|
||||
UdfUtils.UNSAFE.putByte(null, UdfUtils.UNSAFE.getLong(null, outputNullPtr) + row, (byte) 1);
|
||||
if (retType.equals(JavaUdfDataType.STRING)) {
|
||||
UdfUtils.UNSAFE.putInt(null, UdfUtils.UNSAFE.getLong(null, outputOffsetsPtr)
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
-- This file is automatically generated. You should know what you did if you want to edit this
|
||||
-- !select_default --
|
||||
1 2022-01-01 2022-01-01T11:11:11 2022-01-01 2022-01-01T11:11:11
|
||||
1 2022-01-01 2022-01-01T11:11:11 2022-01-01 2022-01-01T11:11:11
|
||||
1 2022-01-01 2022-01-01T11:11:11 2022-01-01 2022-01-01T11:11:11
|
||||
1 2022-01-01 2022-01-01T11:11:11 2022-01-01 2022-01-01T11:11:11
|
||||
1 2022-01-01 2022-01-01T11:11:11 2022-01-01 2022-01-01T11:11:11
|
||||
1 2022-01-01 2022-01-01T11:11:11 2022-01-01 2022-01-01T11:11:11
|
||||
1 2022-01-01 2022-01-01T11:11:11 2022-01-01 2022-01-01T11:11:11
|
||||
1 2022-01-01 2022-01-01T11:11:11 2022-01-01 2022-01-01T11:11:11
|
||||
1 2022-01-01 2022-01-01T11:11:11 2022-01-01 2022-01-01T11:11:11
|
||||
|
||||
-- !select1 --
|
||||
2022-01-11
|
||||
|
||||
-- !select2 --
|
||||
1 2022-01-10
|
||||
|
||||
-- !select3 --
|
||||
2022-01-11
|
||||
|
||||
-- !select4 --
|
||||
1 2022-01-10
|
||||
|
||||
-- !select5 --
|
||||
2022-01-01T03:00
|
||||
|
||||
-- !select6 --
|
||||
1 2022-01-05T03:00
|
||||
|
||||
-- !select5 --
|
||||
2022-01-01T03:00
|
||||
|
||||
-- !select6 --
|
||||
1 2022-01-05T03:00
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
-- This file is automatically generated. You should know what you did if you want to edit this
|
||||
-- !select_default --
|
||||
1 1 abcdefg1 poiuytre1abcdefg
|
||||
2 2 abcdefg2 poiuytre2abcdefg
|
||||
0 3 abcdefg3 poiuytre3abcdefg
|
||||
1 4 abcdefg4 poiuytre4abcdefg
|
||||
2 5 abcdefg5 poiuytre5abcdefg
|
||||
0 6 abcdefg6 poiuytre6abcdefg
|
||||
1 7 abcdefg7 poiuytre7abcdefg
|
||||
2 8 abcdefg8 poiuytre8abcdefg
|
||||
9 9 abcdefg9 poiuytre9abcdefg
|
||||
|
||||
-- !select1 --
|
||||
0 abcdefg3-abcdefg6
|
||||
1 abcdefg1-abcdefg4-abcdefg7
|
||||
2 abcdefg2-abcdefg5-abcdefg8
|
||||
9 abcdefg9
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
-- This file is automatically generated. You should know what you did if you want to edit this
|
||||
-- !select_default --
|
||||
111 11111.111110000 222222.333333300
|
||||
112 1234556.111110000 222222.333333300
|
||||
113 87654321.111110000 \N
|
||||
|
||||
-- !select1 --
|
||||
88899988.333330000
|
||||
|
||||
-- !select2 --
|
||||
111 11111.111110000
|
||||
112 1234556.111110000
|
||||
113 87654321.111110000
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
-- This file is automatically generated. You should know what you did if you want to edit this
|
||||
-- !select_default --
|
||||
1 11.1 1.111 poiuytre1abcdefg
|
||||
2 22.2 2.222 poiuytre2abcdefg
|
||||
0 33.3 3.333 poiuytre3abcdefg
|
||||
1 44.4 4.444 poiuytre4abcdefg
|
||||
2 55.5 5.555 poiuytre5abcdefg
|
||||
0 66.6 6.666 poiuytre6abcdefg
|
||||
1 77.7 7.777 poiuytre7abcdefg
|
||||
2 88.8 8.888 poiuytre8abcdefg
|
||||
9 99.9 10.89 poiuytre9abcdefg
|
||||
|
||||
-- !select --
|
||||
101.77200000000002
|
||||
|
||||
-- !select --
|
||||
0 19.997999999999998
|
||||
1 26.664
|
||||
2 33.33
|
||||
9 21.78
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
-- This file is automatically generated. You should know what you did if you want to edit this
|
||||
-- !select_default --
|
||||
1 11.1 1.111 poiuytre1abcdefg
|
||||
2 22.2 2.222 poiuytre2abcdefg
|
||||
0 33.3 3.333 poiuytre3abcdefg
|
||||
1 44.4 4.444 poiuytre4abcdefg
|
||||
2 55.5 5.555 poiuytre5abcdefg
|
||||
0 66.6 6.666 poiuytre6abcdefg
|
||||
1 77.7 7.777 poiuytre7abcdefg
|
||||
2 88.8 8.888 poiuytre8abcdefg
|
||||
9 99.9 10.89 poiuytre9abcdefg
|
||||
|
||||
-- !select1 --
|
||||
101.77199999999999
|
||||
|
||||
-- !select2 --
|
||||
0 19.997999999999998
|
||||
1 26.664
|
||||
2 33.33
|
||||
9 21.78
|
||||
|
||||
-- !select3 --
|
||||
499.5
|
||||
|
||||
-- !select4 --
|
||||
0 99.899994
|
||||
1 133.2
|
||||
2 166.5
|
||||
9 99.9
|
||||
|
||||
21
regression-test/data/javaudf_p0/test_javaudaf_mysum_int.out
Normal file
21
regression-test/data/javaudf_p0/test_javaudaf_mysum_int.out
Normal file
@ -0,0 +1,21 @@
|
||||
-- This file is automatically generated. You should know what you did if you want to edit this
|
||||
-- !select_default --
|
||||
1 1 abcdefg1 poiuytre1abcdefg
|
||||
2 2 abcdefg2 poiuytre2abcdefg
|
||||
0 3 abcdefg3 poiuytre3abcdefg
|
||||
1 4 abcdefg4 poiuytre4abcdefg
|
||||
2 5 abcdefg5 poiuytre5abcdefg
|
||||
0 6 abcdefg6 poiuytre6abcdefg
|
||||
1 7 abcdefg7 poiuytre7abcdefg
|
||||
2 8 abcdefg8 poiuytre8abcdefg
|
||||
9 9 abcdefg9 poiuytre9abcdefg
|
||||
|
||||
-- !select1 --
|
||||
18
|
||||
|
||||
-- !select2 --
|
||||
0 0
|
||||
1 3
|
||||
2 6
|
||||
9 9
|
||||
|
||||
24
regression-test/data/javaudf_p0/test_javaudaf_null_test.out
Normal file
24
regression-test/data/javaudf_p0/test_javaudaf_null_test.out
Normal file
@ -0,0 +1,24 @@
|
||||
-- This file is automatically generated. You should know what you did if you want to edit this
|
||||
-- !select_default --
|
||||
1 1 abcdefg1 poiuytre1abcdefg
|
||||
2 2 abcdefg2 poiuytre2abcdefg
|
||||
0 3 abcdefg3 poiuytre3abcdefg
|
||||
1 4 abcdefg4 poiuytre4abcdefg
|
||||
2 5 abcdefg5 poiuytre5abcdefg
|
||||
0 6 abcdefg6 poiuytre6abcdefg
|
||||
1 7 abcdefg7 poiuytre7abcdefg
|
||||
2 8 abcdefg8 poiuytre8abcdefg
|
||||
9 9 abcdefg9 poiuytre9abcdefg
|
||||
|
||||
-- !select1 --
|
||||
\N
|
||||
|
||||
-- !select2 --
|
||||
0 \N
|
||||
1 \N
|
||||
2 \N
|
||||
9 \N
|
||||
|
||||
-- !select3 --
|
||||
\N
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
// 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 org.apache.log4j.Logger;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class MyDayDate {
|
||||
private static final Logger LOG = Logger.getLogger(MyDayDate.class);
|
||||
public static class State {
|
||||
public LocalDate counter = LocalDate.of(2022,01,01);
|
||||
}
|
||||
|
||||
public State create() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
public void destroy(State state) {
|
||||
}
|
||||
|
||||
public void add(State state, LocalDate val1) {
|
||||
if (val1 == null) return;
|
||||
state.counter = state.counter.plusDays(val1.getDayOfMonth());
|
||||
}
|
||||
|
||||
public void serialize(State state, DataOutputStream out) throws IOException {
|
||||
out.writeInt(state.counter.getYear());
|
||||
out.writeInt(state.counter.getMonthValue());
|
||||
out.writeInt(state.counter.getDayOfMonth());
|
||||
}
|
||||
|
||||
public void deserialize(State state, DataInputStream in) throws IOException {
|
||||
state.counter = LocalDate.of(in.readInt(),in.readInt(),in.readInt());
|
||||
}
|
||||
|
||||
public void merge(State state, State rhs) {
|
||||
state.counter = state.counter.plusDays(rhs.counter.getDayOfMonth());
|
||||
}
|
||||
|
||||
public LocalDate getValue(State state) {
|
||||
return state.counter;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
// 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 org.apache.log4j.Logger;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MyGroupConcatString {
|
||||
private static final Logger LOG = Logger.getLogger(MyGroupConcatString.class);
|
||||
public static class State {
|
||||
public String data = new String();
|
||||
public String separator = "-";
|
||||
public boolean inited = false;
|
||||
}
|
||||
|
||||
public State create() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
public void destroy(State state) {
|
||||
|
||||
}
|
||||
|
||||
public void add(State state, String val) {
|
||||
if (val == null) return;
|
||||
if (state.inited) {
|
||||
state.data += state.separator;
|
||||
} else {
|
||||
state.inited = true;
|
||||
}
|
||||
state.data += val;
|
||||
}
|
||||
|
||||
public void serialize(State state, DataOutputStream out) throws IOException {
|
||||
out.writeBoolean(state.inited);
|
||||
out.writeInt(state.data.length());
|
||||
out.writeBytes(state.data);
|
||||
}
|
||||
|
||||
public void deserialize(State state, DataInputStream in) throws IOException {
|
||||
state.inited = in.readBoolean();
|
||||
int len = in.readInt();
|
||||
byte[] bytes = new byte[len];
|
||||
in.read(bytes);
|
||||
state.data = new String(bytes);
|
||||
}
|
||||
|
||||
public void merge(State state, State rhs) {
|
||||
if (!rhs.inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.inited) {
|
||||
state.inited = true;
|
||||
state.data = rhs.data;
|
||||
} else {
|
||||
state.data += state.separator;
|
||||
state.data +=rhs.data;
|
||||
}
|
||||
}
|
||||
|
||||
public String getValue(State state) {
|
||||
return state.data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
// 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 org.apache.log4j.Logger;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class MyHourDateTime {
|
||||
private static final Logger LOG = Logger.getLogger(MyHourDateTime.class);
|
||||
public static class State {
|
||||
public LocalDateTime counter = LocalDateTime.of(2022,01,01,00,00,00);
|
||||
}
|
||||
|
||||
public State create() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
public void destroy(State state) {
|
||||
}
|
||||
|
||||
public void add(State state, LocalDateTime val1) {
|
||||
if (val1 == null) return;
|
||||
state.counter = state.counter.plusHours(val1.getHour());
|
||||
}
|
||||
|
||||
public void serialize(State state, DataOutputStream out) throws IOException {
|
||||
out.writeInt(state.counter.getYear());
|
||||
out.writeInt(state.counter.getMonthValue());
|
||||
out.writeInt(state.counter.getDayOfMonth());
|
||||
out.writeInt(state.counter.getHour());
|
||||
out.writeInt(state.counter.getMinute());
|
||||
out.writeInt(state.counter.getSecond());
|
||||
}
|
||||
|
||||
public void deserialize(State state, DataInputStream in) throws IOException {
|
||||
state.counter = LocalDateTime.of(in.readInt(),in.readInt(),in.readInt(),in.readInt(),in.readInt(),in.readInt());
|
||||
}
|
||||
|
||||
public void merge(State state, State rhs) {
|
||||
state.counter = state.counter.plusHours(rhs.counter.getHour());
|
||||
}
|
||||
|
||||
public LocalDateTime getValue(State state) {
|
||||
return state.counter;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
// 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 org.apache.log4j.Logger;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class MySumDecimal {
|
||||
private static final Logger LOG = Logger.getLogger(MySumDecimal.class);
|
||||
public static class State {
|
||||
public BigDecimal counter = new BigDecimal(0);
|
||||
}
|
||||
|
||||
public State create() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
public void destroy(State state) {
|
||||
}
|
||||
|
||||
public void add(State state, BigDecimal val1) {
|
||||
if (val1 == null) return;
|
||||
state.counter = state.counter.add(val1);
|
||||
}
|
||||
|
||||
public void serialize(State state, DataOutputStream out) throws IOException {
|
||||
String val = state.counter.toString();
|
||||
out.writeUTF(val);
|
||||
}
|
||||
|
||||
public void deserialize(State state, DataInputStream in) throws IOException {
|
||||
String val = in.readUTF();
|
||||
state.counter = new BigDecimal(val);
|
||||
}
|
||||
|
||||
public void merge(State state, State rhs) {
|
||||
state.counter = state.counter.add(rhs.counter);
|
||||
}
|
||||
|
||||
public BigDecimal getValue(State state) {
|
||||
return state.counter;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
// 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.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MySumDouble {
|
||||
public static class State {
|
||||
public double counter = 0.0;
|
||||
}
|
||||
|
||||
public State create() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
public void destroy(State state) {
|
||||
}
|
||||
|
||||
public void add(State state, Double val1, Double val2) {
|
||||
if (val1 == null || val2 == null) return;
|
||||
state.counter += val1;
|
||||
state.counter += val2;
|
||||
}
|
||||
|
||||
public void serialize(State state, DataOutputStream out) throws IOException {
|
||||
out.writeDouble(state.counter);
|
||||
}
|
||||
|
||||
public void deserialize(State state, DataInputStream in) throws IOException {
|
||||
state.counter = in.readDouble();
|
||||
}
|
||||
|
||||
public void merge(State state, State rhs) {
|
||||
state.counter += rhs.counter;
|
||||
}
|
||||
|
||||
public Double getValue(State state) {
|
||||
return state.counter;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
// 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.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MySumFloat {
|
||||
public static class State {
|
||||
public float counter = 0;
|
||||
}
|
||||
|
||||
public State create() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
public void destroy(State state) {
|
||||
}
|
||||
|
||||
public void add(State state, Float val1) {
|
||||
if (val1 == null) return;
|
||||
state.counter += val1;
|
||||
}
|
||||
|
||||
public void serialize(State state, DataOutputStream out) throws IOException {
|
||||
out.writeFloat(state.counter);
|
||||
}
|
||||
|
||||
public void deserialize(State state, DataInputStream in) throws IOException {
|
||||
state.counter = in.readFloat();
|
||||
}
|
||||
|
||||
public void merge(State state, State rhs) {
|
||||
state.counter += rhs.counter;
|
||||
}
|
||||
|
||||
public Float getValue(State state) {
|
||||
return state.counter;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
// 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.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MySumInt {
|
||||
public static class State {
|
||||
public long counter = 0;
|
||||
}
|
||||
|
||||
public State create() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
public void destroy(State state) {
|
||||
}
|
||||
|
||||
public void add(State state, Integer val) {
|
||||
if (val == null) return;
|
||||
state.counter += val;
|
||||
}
|
||||
|
||||
public void serialize(State state, DataOutputStream out) throws IOException {
|
||||
out.writeLong(state.counter);
|
||||
}
|
||||
|
||||
public void deserialize(State state, DataInputStream in) throws IOException {
|
||||
state.counter = in.readLong();
|
||||
}
|
||||
|
||||
public void merge(State state, State rhs) {
|
||||
state.counter += rhs.counter;
|
||||
}
|
||||
|
||||
public long getValue(State state) {
|
||||
return state.counter;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
// 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 org.apache.log4j.Logger;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class UdafNullTest {
|
||||
private static final Logger LOG = Logger.getLogger(UdafNullTest.class);
|
||||
public static class State {
|
||||
public long counter = 0;
|
||||
}
|
||||
|
||||
public State create() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
public void destroy(State state) {
|
||||
}
|
||||
|
||||
public void add(State state, Integer val) {
|
||||
if (val == null) return;
|
||||
state.counter += val;
|
||||
}
|
||||
|
||||
public void serialize(State state, DataOutputStream out) throws IOException {
|
||||
out.writeLong(state.counter);
|
||||
}
|
||||
|
||||
public void deserialize(State state, DataInputStream in) throws IOException {
|
||||
state.counter = in.readLong();
|
||||
}
|
||||
|
||||
public void merge(State state, State rhs) {
|
||||
state.counter += rhs.counter;
|
||||
}
|
||||
|
||||
public Long getValue(State state) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,119 @@
|
||||
// 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_javaudaf_my_date_datetime") {
|
||||
def tableName = "test_javaudaf_my_date_datetime"
|
||||
def jarPath = """${context.file.parent}/jars/java-udf-case-jar-with-dependencies.jar"""
|
||||
|
||||
log.info("Jar path: ${jarPath}".toString())
|
||||
try {
|
||||
sql """ DROP TABLE IF EXISTS ${tableName} """
|
||||
sql """
|
||||
CREATE TABLE IF NOT EXISTS ${tableName} (
|
||||
`user_id` INT NOT NULL COMMENT "用户id",
|
||||
`date_col` date NOT NULL,
|
||||
`datetime_col` datetime NOT NULL,
|
||||
`datev2_col` datev2 NOT NULL,
|
||||
`datetimev2_col` datetimev2 NOT NULL
|
||||
)
|
||||
DISTRIBUTED BY HASH(user_id) PROPERTIES("replication_num" = "1");
|
||||
"""
|
||||
StringBuilder sb = new StringBuilder()
|
||||
int i = 1
|
||||
for (; i < 9; i ++) {
|
||||
sb.append("""
|
||||
(1, '2022-01-01', '2022-01-01 11:11:11', '2022-01-01', '2022-01-01 11:11:11'),
|
||||
""")
|
||||
}
|
||||
sb.append("""
|
||||
(1, '2022-01-01', '2022-01-01 11:11:11', '2022-01-01', '2022-01-01 11:11:11')
|
||||
""")
|
||||
sql """ INSERT INTO ${tableName} VALUES
|
||||
${sb.toString()}
|
||||
"""
|
||||
qt_select_default """ SELECT * FROM ${tableName} t ORDER BY user_id; """
|
||||
|
||||
File path = new File(jarPath)
|
||||
if (!path.exists()) {
|
||||
throw new IllegalStateException("""${jarPath} doesn't exist! """)
|
||||
}
|
||||
// test datev2
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_my_day_datev2(datev2) RETURNS datev2 PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.MyDayDate",
|
||||
"always_nullable"="false",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select1 """ SELECT udaf_my_day_datev2(datev2_col) result FROM ${tableName}; """
|
||||
|
||||
qt_select2 """ select user_id, udaf_my_day_datev2(datev2_col) from ${tableName} group by user_id order by user_id; """
|
||||
|
||||
sql """ DROP FUNCTION udaf_my_day_datev2(datev2); """
|
||||
|
||||
// test date
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_my_day_date(date) RETURNS date PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.MyDayDate",
|
||||
"always_nullable"="false",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select3 """ SELECT udaf_my_day_date(date_col) result FROM ${tableName}; """
|
||||
|
||||
qt_select4 """ select user_id, udaf_my_day_date(date_col) from ${tableName} group by user_id order by user_id; """
|
||||
|
||||
sql """ DROP FUNCTION udaf_my_day_date(date); """
|
||||
|
||||
// test datetimev2
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_my_hour_datetimev2(datetimev2) RETURNS datetimev2 PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.MyHourDateTime",
|
||||
"always_nullable"="false",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select5 """ SELECT udaf_my_hour_datetimev2(datetimev2_col) result FROM ${tableName}; """
|
||||
|
||||
qt_select6 """ select user_id, udaf_my_hour_datetimev2(datetimev2_col) from ${tableName} group by user_id order by user_id; """
|
||||
|
||||
sql """ DROP FUNCTION udaf_my_hour_datetimev2(datetimev2); """
|
||||
|
||||
// test datetime
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_my_hour_datetime(datetime) RETURNS datetime PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.MyHourDateTime",
|
||||
"always_nullable"="false",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select5 """ SELECT udaf_my_hour_datetime(datetime_col) result FROM ${tableName}; """
|
||||
|
||||
qt_select6 """ select user_id, udaf_my_hour_datetime(datetime_col) from ${tableName} group by user_id order by user_id; """
|
||||
|
||||
sql """ DROP FUNCTION udaf_my_hour_datetime(datetime); """
|
||||
|
||||
} finally {
|
||||
try_sql("DROP TABLE IF EXISTS ${tableName}")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
// 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_javaudaf_mygroupconcat_string") {
|
||||
def tableName = "test_javaudaf_mygroupconcat_string"
|
||||
def jarPath = """${context.file.parent}/jars/java-udf-case-jar-with-dependencies.jar"""
|
||||
|
||||
log.info("Jar path: ${jarPath}".toString())
|
||||
try {
|
||||
sql """ DROP TABLE IF EXISTS ${tableName} """
|
||||
sql """
|
||||
CREATE TABLE IF NOT EXISTS ${tableName} (
|
||||
`user_id` INT NOT NULL COMMENT "用户id",
|
||||
`char_col` CHAR NOT NULL COMMENT "",
|
||||
`varchar_col` VARCHAR(10) NOT NULL COMMENT "",
|
||||
`string_col` STRING NOT NULL COMMENT ""
|
||||
)
|
||||
DISTRIBUTED BY HASH(user_id) PROPERTIES("replication_num" = "1");
|
||||
"""
|
||||
StringBuilder sb = new StringBuilder()
|
||||
int i = 1
|
||||
for (; i < 9; i ++) {
|
||||
sb.append("""
|
||||
(${i % 3}, '${i}','abcdefg${i}','poiuytre${i}abcdefg'),
|
||||
""")
|
||||
}
|
||||
sb.append("""
|
||||
(${i}, '${i}','abcdefg${i}','poiuytre${i}abcdefg')
|
||||
""")
|
||||
sql """ INSERT INTO ${tableName} VALUES
|
||||
${sb.toString()}
|
||||
"""
|
||||
qt_select_default """ SELECT * FROM ${tableName} t ORDER BY char_col; """
|
||||
|
||||
File path = new File(jarPath)
|
||||
if (!path.exists()) {
|
||||
throw new IllegalStateException("""${jarPath} doesn't exist! """)
|
||||
}
|
||||
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_mygroupconcat_string(string) RETURNS string PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.MyGroupConcatString",
|
||||
"always_nullable"="false",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select1 """ SELECT user_id, udaf_mygroupconcat_string(varchar_col) result FROM ${tableName} GROUP BY user_id order by user_id; """
|
||||
|
||||
sql """ DROP FUNCTION udaf_mygroupconcat_string(string); """
|
||||
} finally {
|
||||
try_sql("DROP TABLE IF EXISTS ${tableName}")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
// 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_javaudaf_mysum_decimal") {
|
||||
def tableName = "test_javaudaf_mysum_decimal"
|
||||
def jarPath = """${context.file.parent}/jars/java-udf-case-jar-with-dependencies.jar"""
|
||||
|
||||
log.info("Jar path: ${jarPath}".toString())
|
||||
try {
|
||||
sql """ DROP TABLE IF EXISTS ${tableName} """
|
||||
sql """
|
||||
CREATE TABLE IF NOT EXISTS ${tableName} (
|
||||
`user_id` INT NOT NULL COMMENT "",
|
||||
`cost_1` decimal(27,9) NOT NULL COMMENT "",
|
||||
`cost_2` decimal(27,9) COMMENT ""
|
||||
)
|
||||
DISTRIBUTED BY HASH(user_id) PROPERTIES("replication_num" = "1");
|
||||
"""
|
||||
|
||||
|
||||
sql """ INSERT INTO ${tableName} (`user_id`,`cost_1`,`cost_2`) VALUES
|
||||
(111,11111.11111,222222.3333333),
|
||||
(112,1234556.11111,222222.3333333),
|
||||
(113,87654321.11111,null)
|
||||
"""
|
||||
qt_select_default """ SELECT * FROM ${tableName} t ORDER BY user_id; """
|
||||
|
||||
File path = new File(jarPath)
|
||||
if (!path.exists()) {
|
||||
throw new IllegalStateException("""${jarPath} doesn't exist! """)
|
||||
}
|
||||
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_my_sum_decimal(decimal(27,9)) RETURNS decimal(27,9) PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.MySumDecimal",
|
||||
"always_nullable"="false",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select1 """ SELECT udaf_my_sum_decimal(cost_1) result FROM ${tableName}; """
|
||||
|
||||
qt_select2 """ select user_id, udaf_my_sum_decimal(cost_1) from ${tableName} group by user_id order by user_id; """
|
||||
|
||||
|
||||
sql """ DROP FUNCTION udaf_my_sum_decimal(decimal(27,9)); """
|
||||
} finally {
|
||||
try_sql("DROP TABLE IF EXISTS ${tableName}")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
// 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_javaudaf_mysum_float_double") {
|
||||
def tableName = "test_javaudaf_mysum_float_double"
|
||||
def jarPath = """${context.file.parent}/jars/java-udf-case-jar-with-dependencies.jar"""
|
||||
|
||||
log.info("Jar path: ${jarPath}".toString())
|
||||
try {
|
||||
sql """ DROP TABLE IF EXISTS ${tableName} """
|
||||
sql """
|
||||
CREATE TABLE IF NOT EXISTS ${tableName} (
|
||||
`user_id` INT NOT NULL COMMENT "用户id",
|
||||
`float_col` float NOT NULL COMMENT "",
|
||||
`double_col` double NOT NULL COMMENT "",
|
||||
`string_col` STRING NOT NULL COMMENT ""
|
||||
)
|
||||
DISTRIBUTED BY HASH(user_id) PROPERTIES("replication_num" = "1");
|
||||
"""
|
||||
StringBuilder sb = new StringBuilder()
|
||||
int i = 1
|
||||
for (; i < 9; i ++) {
|
||||
sb.append("""
|
||||
(${i % 3}, '${i*111/10}','${i*111/100+i/1000}','poiuytre${i}abcdefg'),
|
||||
""")
|
||||
}
|
||||
sb.append("""
|
||||
(${i}, '${i*111/10}','${i*111/100+i/10}','poiuytre${i}abcdefg')
|
||||
""")
|
||||
sql """ INSERT INTO ${tableName} VALUES
|
||||
${sb.toString()}
|
||||
"""
|
||||
qt_select_default """ SELECT * FROM ${tableName} t ORDER BY float_col; """
|
||||
|
||||
File path = new File(jarPath)
|
||||
if (!path.exists()) {
|
||||
throw new IllegalStateException("""${jarPath} doesn't exist! """)
|
||||
}
|
||||
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_my_sum_double(double,double) RETURNS double PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.MySumDouble",
|
||||
"always_nullable"="false",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select1 """ SELECT udaf_my_sum_double(double_col,double_col) result FROM ${tableName}; """
|
||||
|
||||
qt_select2 """ select user_id, udaf_my_sum_double(double_col,double_col) from ${tableName} group by user_id order by user_id; """
|
||||
|
||||
sql """ DROP FUNCTION udaf_my_sum_double(double,double); """
|
||||
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_my_sum_float(float) RETURNS float PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.MySumFloat",
|
||||
"always_nullable"="false",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select3 """ SELECT udaf_my_sum_float(float_col) result FROM ${tableName}; """
|
||||
|
||||
qt_select4 """ select user_id, udaf_my_sum_float(float_col) from ${tableName} group by user_id order by user_id; """
|
||||
|
||||
sql """ DROP FUNCTION udaf_my_sum_float(float); """
|
||||
|
||||
} finally {
|
||||
try_sql("DROP TABLE IF EXISTS ${tableName}")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
// 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_javaudaf_mysum_int") {
|
||||
def tableName = "test_javaudaf_mysum_int"
|
||||
def jarPath = """${context.file.parent}/jars/java-udf-case-jar-with-dependencies.jar"""
|
||||
|
||||
log.info("Jar path: ${jarPath}".toString())
|
||||
try {
|
||||
sql """ DROP TABLE IF EXISTS ${tableName} """
|
||||
sql """
|
||||
CREATE TABLE IF NOT EXISTS ${tableName} (
|
||||
`user_id` INT NOT NULL COMMENT "用户id",
|
||||
`char_col` CHAR NOT NULL COMMENT "",
|
||||
`varchar_col` VARCHAR(10) NOT NULL COMMENT "",
|
||||
`string_col` STRING NOT NULL COMMENT ""
|
||||
)
|
||||
DISTRIBUTED BY HASH(user_id) PROPERTIES("replication_num" = "1");
|
||||
"""
|
||||
StringBuilder sb = new StringBuilder()
|
||||
int i = 1
|
||||
for (; i < 9; i ++) {
|
||||
sb.append("""
|
||||
(${i % 3}, '${i}','abcdefg${i}','poiuytre${i}abcdefg'),
|
||||
""")
|
||||
}
|
||||
sb.append("""
|
||||
(${i}, '${i}','abcdefg${i}','poiuytre${i}abcdefg')
|
||||
""")
|
||||
sql """ INSERT INTO ${tableName} VALUES
|
||||
${sb.toString()}
|
||||
"""
|
||||
qt_select_default """ SELECT * FROM ${tableName} t ORDER BY char_col; """
|
||||
|
||||
File path = new File(jarPath)
|
||||
if (!path.exists()) {
|
||||
throw new IllegalStateException("""${jarPath} doesn't exist! """)
|
||||
}
|
||||
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_my_sum_int(int) RETURNS BigInt PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.MySumInt",
|
||||
"always_nullable"="false",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select1 """ SELECT udaf_my_sum_int(user_id) result FROM ${tableName}; """
|
||||
|
||||
qt_select2 """ select user_id, udaf_my_sum_int(user_id) from ${tableName} group by user_id order by user_id; """
|
||||
|
||||
sql """ DROP FUNCTION udaf_my_sum_int(int); """
|
||||
} finally {
|
||||
try_sql("DROP TABLE IF EXISTS ${tableName}")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
// 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_javaudaf_null_test") {
|
||||
def tableName = "test_javaudaf_null_test"
|
||||
def jarPath = """${context.file.parent}/jars/java-udf-case-jar-with-dependencies.jar"""
|
||||
|
||||
log.info("Jar path: ${jarPath}".toString())
|
||||
try {
|
||||
sql """ DROP TABLE IF EXISTS ${tableName} """
|
||||
sql """
|
||||
CREATE TABLE IF NOT EXISTS ${tableName} (
|
||||
`user_id` INT NOT NULL COMMENT "用户id",
|
||||
`char_col` CHAR NOT NULL COMMENT "",
|
||||
`varchar_col` VARCHAR(10) NOT NULL COMMENT "",
|
||||
`string_col` STRING NOT NULL COMMENT ""
|
||||
)
|
||||
DISTRIBUTED BY HASH(user_id) PROPERTIES("replication_num" = "1");
|
||||
"""
|
||||
StringBuilder sb = new StringBuilder()
|
||||
int i = 1
|
||||
for (; i < 9; i ++) {
|
||||
sb.append("""
|
||||
(${i % 3}, '${i}','abcdefg${i}','poiuytre${i}abcdefg'),
|
||||
""")
|
||||
}
|
||||
sb.append("""
|
||||
(${i}, '${i}','abcdefg${i}','poiuytre${i}abcdefg')
|
||||
""")
|
||||
sql """ INSERT INTO ${tableName} VALUES
|
||||
${sb.toString()}
|
||||
"""
|
||||
qt_select_default """ SELECT * FROM ${tableName} t ORDER BY char_col; """
|
||||
|
||||
File path = new File(jarPath)
|
||||
if (!path.exists()) {
|
||||
throw new IllegalStateException("""${jarPath} doesn't exist! """)
|
||||
}
|
||||
|
||||
sql """ CREATE AGGREGATE FUNCTION udaf_null_test_int(int) RETURNS BigInt PROPERTIES (
|
||||
"file"="file://${jarPath}",
|
||||
"symbol"="org.apache.doris.udf.UdafNullTest",
|
||||
"always_nullable"="true",
|
||||
"type"="JAVA_UDF"
|
||||
); """
|
||||
|
||||
qt_select1 """ SELECT udaf_null_test_int(user_id) result FROM ${tableName}; """
|
||||
|
||||
qt_select2 """ select user_id, udaf_null_test_int(user_id) from ${tableName} group by user_id order by user_id; """
|
||||
|
||||
qt_select3 """ SELECT udaf_null_test_int(1) result FROM ${tableName}; """
|
||||
sql """ DROP FUNCTION udaf_null_test_int(int); """
|
||||
} finally {
|
||||
try_sql("DROP TABLE IF EXISTS ${tableName}")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user