This is an automated email from the ASF dual-hosted git repository. chenyz pushed a commit to branch refactor_interface in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 9492b7ae242fd7b8ab4019654541ca3d953f5e61 Author: Chen YZ <[email protected]> AuthorDate: Sat Jan 4 17:48:49 2025 +0800 done --- .../apache/iotdb/udf/AggregateFunctionExample.java | 31 ++++++----- .../apache/iotdb/udf/ScalarFunctionExample.java | 57 ++++++++++---------- .../db/query/udf/example/relational/AllSum.java | 49 +++++++++-------- .../query/udf/example/relational/ContainNull.java | 21 ++++---- .../relational/{DatePlusOne.java => DatePlus.java} | 31 +++++------ .../query/udf/example/relational/FirstTwoSum.java | 33 ++++++------ .../db/query/udf/example/relational/MyAvg.java | 32 +++++------ .../db/query/udf/example/relational/MyCount.java | 19 +++---- .../it/db/it/udf/IoTDBSQLFunctionManagementIT.java | 19 ++++--- .../it/udf/IoTDBUserDefinedScalarFunctionIT.java | 2 +- .../analysis/AggregateFunctionAnalysis.java | 62 ++++++++++++++++++++++ .../api/customizer/analysis/FunctionAnalysis.java | 26 +++++++++ .../analysis/ScalarFunctionAnalysis.java | 51 ++++++++++++++++++ ...ctionParameters.java => FunctionArguments.java} | 6 +-- .../exception/UDFArgumentNotValidException.java | 27 ++++++++++ .../udf/api/relational/AggregateFunction.java | 48 +++++++++-------- .../iotdb/udf/api/relational/ScalarFunction.java | 47 ++++++++-------- .../relational/aggregation/AccumulatorFactory.java | 18 +++---- .../UserDefinedAggregateFunctionAccumulator.java | 27 +++++++++- .../relational/ColumnTransformerBuilder.java | 14 ++--- .../relational/metadata/TableMetadataImpl.java | 29 +++++----- 21 files changed, 426 insertions(+), 223 deletions(-) diff --git a/example/udf/src/main/java/org/apache/iotdb/udf/AggregateFunctionExample.java b/example/udf/src/main/java/org/apache/iotdb/udf/AggregateFunctionExample.java index 40a13a6d205..c7aca21275c 100644 --- a/example/udf/src/main/java/org/apache/iotdb/udf/AggregateFunctionExample.java +++ b/example/udf/src/main/java/org/apache/iotdb/udf/AggregateFunctionExample.java @@ -20,10 +20,9 @@ package org.apache.iotdb.udf; import org.apache.iotdb.udf.api.State; -import org.apache.iotdb.udf.api.customizer.config.AggregateFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; -import org.apache.iotdb.udf.api.exception.UDFException; -import org.apache.iotdb.udf.api.exception.UDFParameterNotValidException; +import org.apache.iotdb.udf.api.customizer.analysis.AggregateFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.relational.AggregateFunction; import org.apache.iotdb.udf.api.relational.access.Record; import org.apache.iotdb.udf.api.type.Type; @@ -78,15 +77,15 @@ public class AggregateFunctionExample implements AggregateFunction { } @Override - public void validate(FunctionParameters parameters) throws UDFException { - if (parameters.getChildExpressionsSize() != 1) { - throw new UDFParameterNotValidException("Only one parameter is required."); + public AggregateFunctionAnalysis analyze(FunctionArguments arguments) + throws UDFArgumentNotValidException { + if (arguments.getChildExpressionsSize() != 1) { + throw new UDFArgumentNotValidException("Only one parameter is required."); } - } - - @Override - public void beforeStart(FunctionParameters parameters, AggregateFunctionConfig configurations) { - configurations.setOutputDataType(Type.INT64); + return new AggregateFunctionAnalysis.Builder() + .outputDataType(Type.INT64) + .removable(true) + .build(); } @Override @@ -114,4 +113,12 @@ public class AggregateFunctionExample implements AggregateFunction { CountState countState = (CountState) state; resultValue.setLong(countState.count); } + + @Override + public void remove(State state, Record input) { + CountState countState = (CountState) state; + if (!input.isNull(0)) { + countState.count--; + } + } } diff --git a/example/udf/src/main/java/org/apache/iotdb/udf/ScalarFunctionExample.java b/example/udf/src/main/java/org/apache/iotdb/udf/ScalarFunctionExample.java index ab6367f7810..0777c076bc9 100644 --- a/example/udf/src/main/java/org/apache/iotdb/udf/ScalarFunctionExample.java +++ b/example/udf/src/main/java/org/apache/iotdb/udf/ScalarFunctionExample.java @@ -19,43 +19,42 @@ package org.apache.iotdb.udf; -import org.apache.iotdb.udf.api.customizer.config.ScalarFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; +import org.apache.iotdb.udf.api.customizer.analysis.ScalarFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.exception.UDFException; -import org.apache.iotdb.udf.api.exception.UDFParameterNotValidException; import org.apache.iotdb.udf.api.relational.ScalarFunction; import org.apache.iotdb.udf.api.relational.access.Record; import org.apache.iotdb.udf.api.type.Type; -/** This is an internal example of the ScalarFunction implementation. */ +/** + * This is an internal example of the ScalarFunction implementation. + * + * <p>CREATE DATABASE test; + * + * <p>USE test; + * + * <p>CREATE TABLE t1(device_id STRING TAG, s1 TEXT FIELD, s2 INT32 FIELD); + * + * <p>INSERT INTO t1(time, device_id, s1, s2) VALUES (1, 'd1', 'a', 1), (2, 'd1', null, 2), (3, + * 'd1', 'c', null); + * + * <p>CREATE FUNCTION contain_null AS 'org.apache.iotdb.udf.ScalarFunctionExample'; + * + * <p>SHOW FUNCTIONS; + * + * <p>SELECT time, device_id, s1, s2, contain_null(s1, s2) as contain_null, contain_null(s1) as + * s1_isnull, contain_null(s2) as s2_isnull FROM t1; + */ public class ScalarFunctionExample implements ScalarFunction { - /** - * CREATE DATABASE test; - * - * <p>USE test; - * - * <p>CREATE TABLE t1(device_id STRING TAG, s1 TEXT FIELD, s2 INT32 FIELD); - * - * <p>INSERT INTO t1(time, device_id, s1, s2) VALUES (1, 'd1', 'a', 1), (2, 'd1', null, 2), (3, - * 'd1', 'c', null); - * - * <p>CREATE FUNCTION contain_null AS 'org.apache.iotdb.udf.ScalarFunctionExample'; - * - * <p>SHOW FUNCTIONS; - * - * <p>SELECT time, device_id, s1, s2, contain_null(s1, s2) as contain_null, contain_null(s1) as - * s1_isnull, contain_null(s2) as s2_isnull FROM t1; - */ - @Override - public void validate(FunctionParameters parameters) throws UDFException { - if (parameters.getChildExpressionsSize() < 1) { - throw new UDFParameterNotValidException("At least one parameter is required."); - } - } @Override - public void beforeStart(FunctionParameters parameters, ScalarFunctionConfig configurations) { - configurations.setOutputDataType(Type.BOOLEAN); + public ScalarFunctionAnalysis analyze(FunctionArguments arguments) + throws UDFArgumentNotValidException { + if (arguments.getChildExpressionsSize() < 1) { + throw new UDFArgumentNotValidException("At least one parameter is required."); + } + return new ScalarFunctionAnalysis.Builder().outputDataType(Type.BOOLEAN).build(); } @Override diff --git a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/AllSum.java b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/AllSum.java index d9754d954f4..8f51cbc0775 100644 --- a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/AllSum.java +++ b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/AllSum.java @@ -19,10 +19,10 @@ package org.apache.iotdb.db.query.udf.example.relational; -import org.apache.iotdb.udf.api.customizer.config.ScalarFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; +import org.apache.iotdb.udf.api.customizer.analysis.ScalarFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.exception.UDFException; -import org.apache.iotdb.udf.api.exception.UDFParameterNotValidException; import org.apache.iotdb.udf.api.relational.ScalarFunction; import org.apache.iotdb.udf.api.relational.access.Record; import org.apache.iotdb.udf.api.type.Type; @@ -30,43 +30,50 @@ import org.apache.iotdb.udf.api.type.Type; import java.util.HashSet; import java.util.Set; -/** Calculate the sum of all parameters. Only support inputs of INT32,INT64,DOUBLE,FLOAT type. */ +/** Calculate the sum of all arguments. Only support inputs of INT32,INT64,DOUBLE,FLOAT type. */ public class AllSum implements ScalarFunction { private Type outputDataType; @Override - public void validate(FunctionParameters parameters) throws UDFException { - if (parameters.getChildExpressionsSize() < 1) { - throw new UDFParameterNotValidException("At least one parameter is required."); + public ScalarFunctionAnalysis analyze(FunctionArguments arguments) + throws UDFArgumentNotValidException { + if (arguments.getChildExpressionsSize() < 1) { + throw new UDFArgumentNotValidException("At least one parameter is required."); } - for (int i = 0; i < parameters.getChildExpressionsSize(); i++) { - if (parameters.getDataType(i) != Type.INT32 - && parameters.getDataType(i) != Type.INT64 - && parameters.getDataType(i) != Type.FLOAT - && parameters.getDataType(i) != Type.DOUBLE) { - throw new UDFParameterNotValidException( + for (int i = 0; i < arguments.getChildExpressionsSize(); i++) { + if (arguments.getDataType(i) != Type.INT32 + && arguments.getDataType(i) != Type.INT64 + && arguments.getDataType(i) != Type.FLOAT + && arguments.getDataType(i) != Type.DOUBLE) { + throw new UDFArgumentNotValidException( "Only support inputs of INT32,INT64,DOUBLE,FLOAT type."); } } + return new ScalarFunctionAnalysis.Builder() + .outputDataType(inferOutputDataType(arguments)) + .build(); } @Override - public void beforeStart(FunctionParameters parameters, ScalarFunctionConfig configurations) { + public void beforeStart(FunctionArguments arguments) throws UDFException { + this.outputDataType = inferOutputDataType(arguments); + } + + private Type inferOutputDataType(FunctionArguments arguments) { Set<Type> inputTypeSet = new HashSet<>(); - for (int i = 0; i < parameters.getChildExpressionsSize(); i++) { - inputTypeSet.add(parameters.getDataType(i)); + for (int i = 0; i < arguments.getChildExpressionsSize(); i++) { + inputTypeSet.add(arguments.getDataType(i)); } if (inputTypeSet.contains(Type.DOUBLE)) { - outputDataType = Type.DOUBLE; + return Type.DOUBLE; } else if (inputTypeSet.contains(Type.FLOAT)) { - outputDataType = Type.FLOAT; + return Type.FLOAT; } else if (inputTypeSet.contains(Type.INT64)) { - outputDataType = Type.INT64; + return Type.INT64; } else { - outputDataType = Type.INT32; + return Type.INT32; } - configurations.setOutputDataType(outputDataType); } @Override diff --git a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/ContainNull.java b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/ContainNull.java index 463de569eec..eb0a92dd24a 100644 --- a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/ContainNull.java +++ b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/ContainNull.java @@ -19,25 +19,22 @@ package org.apache.iotdb.db.query.udf.example.relational; -import org.apache.iotdb.udf.api.customizer.config.ScalarFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; -import org.apache.iotdb.udf.api.exception.UDFException; -import org.apache.iotdb.udf.api.exception.UDFParameterNotValidException; +import org.apache.iotdb.udf.api.customizer.analysis.ScalarFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.relational.ScalarFunction; import org.apache.iotdb.udf.api.relational.access.Record; import org.apache.iotdb.udf.api.type.Type; public class ContainNull implements ScalarFunction { - @Override - public void validate(FunctionParameters parameters) throws UDFException { - if (parameters.getChildExpressionsSize() < 1) { - throw new UDFParameterNotValidException("At least one parameter is required."); - } - } @Override - public void beforeStart(FunctionParameters parameters, ScalarFunctionConfig configurations) { - configurations.setOutputDataType(Type.BOOLEAN); + public ScalarFunctionAnalysis analyze(FunctionArguments arguments) + throws UDFArgumentNotValidException { + if (arguments.getChildExpressionsSize() < 1) { + throw new UDFArgumentNotValidException("At least one parameter is required."); + } + return new ScalarFunctionAnalysis.Builder().outputDataType(Type.BOOLEAN).build(); } @Override diff --git a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/DatePlusOne.java b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/DatePlus.java similarity index 55% rename from integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/DatePlusOne.java rename to integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/DatePlus.java index 09d69ba3096..18354c10b9b 100644 --- a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/DatePlusOne.java +++ b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/DatePlus.java @@ -19,33 +19,30 @@ package org.apache.iotdb.db.query.udf.example.relational; -import org.apache.iotdb.udf.api.customizer.config.ScalarFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; -import org.apache.iotdb.udf.api.exception.UDFException; -import org.apache.iotdb.udf.api.exception.UDFParameterNotValidException; +import org.apache.iotdb.udf.api.customizer.analysis.ScalarFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.relational.ScalarFunction; import org.apache.iotdb.udf.api.relational.access.Record; import org.apache.iotdb.udf.api.type.Type; import java.time.LocalDate; -public class DatePlusOne implements ScalarFunction { +public class DatePlus implements ScalarFunction { + @Override - public void validate(FunctionParameters parameters) throws UDFException { - if (parameters.getChildExpressionsSize() != 2) { - throw new UDFParameterNotValidException("Only two parameter is required."); + public ScalarFunctionAnalysis analyze(FunctionArguments arguments) + throws UDFArgumentNotValidException { + if (arguments.getChildExpressionsSize() != 2) { + throw new UDFArgumentNotValidException("Only two parameter is required."); } - if (parameters.getDataType(0) != Type.DATE) { - throw new UDFParameterNotValidException("The first parameter should be DATE type."); + if (arguments.getDataType(0) != Type.DATE) { + throw new UDFArgumentNotValidException("The first parameter should be DATE type."); } - if (parameters.getDataType(1) != Type.INT32 && parameters.getDataType(1) != Type.INT64) { - throw new UDFParameterNotValidException("The second parameter should be INT type."); + if (arguments.getDataType(1) != Type.INT32 && arguments.getDataType(1) != Type.INT64) { + throw new UDFArgumentNotValidException("The second parameter should be INT type."); } - } - - @Override - public void beforeStart(FunctionParameters parameters, ScalarFunctionConfig configurations) { - configurations.setOutputDataType(Type.DATE); + return new ScalarFunctionAnalysis.Builder().outputDataType(Type.DATE).build(); } @Override diff --git a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/FirstTwoSum.java b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/FirstTwoSum.java index 041f3ca2c89..59cbf101317 100644 --- a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/FirstTwoSum.java +++ b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/FirstTwoSum.java @@ -20,8 +20,9 @@ package org.apache.iotdb.db.query.udf.example.relational; import org.apache.iotdb.udf.api.State; -import org.apache.iotdb.udf.api.customizer.config.AggregateFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; +import org.apache.iotdb.udf.api.customizer.analysis.AggregateFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.exception.UDFException; import org.apache.iotdb.udf.api.relational.AggregateFunction; import org.apache.iotdb.udf.api.relational.access.Record; @@ -67,27 +68,25 @@ public class FirstTwoSum implements AggregateFunction { } @Override - public void validate(FunctionParameters parameters) throws UDFException { - if (parameters.getChildExpressionsSize() != 3) { - throw new UDFException("FirstTwoSum should accept three column as input"); + public AggregateFunctionAnalysis analyze(FunctionArguments arguments) + throws UDFArgumentNotValidException { + if (arguments.getChildExpressionsSize() != 3) { + throw new UDFArgumentNotValidException("FirstTwoSum should accept three column as input"); } for (int i = 0; i < 2; i++) { - if (parameters.getDataType(i) != Type.INT32 - && parameters.getDataType(i) != Type.INT64 - && parameters.getDataType(i) != Type.FLOAT - && parameters.getDataType(i) != Type.DOUBLE) { - throw new UDFException( + if (arguments.getDataType(i) != Type.INT32 + && arguments.getDataType(i) != Type.INT64 + && arguments.getDataType(i) != Type.FLOAT + && arguments.getDataType(i) != Type.DOUBLE) { + throw new UDFArgumentNotValidException( "FirstTwoSum should accept INT32, INT64, FLOAT, DOUBLE as the first two inputs"); } } - if (parameters.getDataType(2) != Type.TIMESTAMP) { - throw new UDFException("FirstTwoSum should accept TIMESTAMP as the third input"); + if (arguments.getDataType(2) != Type.TIMESTAMP) { + throw new UDFArgumentNotValidException( + "FirstTwoSum should accept TIMESTAMP as the third input"); } - } - - @Override - public void beforeStart(FunctionParameters parameters, AggregateFunctionConfig configurations) { - configurations.setOutputDataType(Type.DOUBLE); + return new AggregateFunctionAnalysis.Builder().outputDataType(Type.DOUBLE).build(); } @Override diff --git a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MyAvg.java b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MyAvg.java index e8a41e97296..8f43f0119c1 100644 --- a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MyAvg.java +++ b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MyAvg.java @@ -20,8 +20,9 @@ package org.apache.iotdb.db.query.udf.example.relational; import org.apache.iotdb.udf.api.State; -import org.apache.iotdb.udf.api.customizer.config.AggregateFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; +import org.apache.iotdb.udf.api.customizer.analysis.AggregateFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.exception.UDFException; import org.apache.iotdb.udf.api.relational.AggregateFunction; import org.apache.iotdb.udf.api.relational.access.Record; @@ -60,21 +61,22 @@ public class MyAvg implements AggregateFunction { } @Override - public void validate(FunctionParameters parameters) throws UDFException { - if (parameters.getChildExpressionsSize() != 1) { - throw new UDFException("MyAvg only accepts one column as input"); + public AggregateFunctionAnalysis analyze(FunctionArguments arguments) + throws UDFArgumentNotValidException { + if (arguments.getChildExpressionsSize() != 1) { + throw new UDFArgumentNotValidException("MyAvg only accepts one column as input"); } - if (parameters.getDataType(0) != Type.INT32 - && parameters.getDataType(0) != Type.INT64 - && parameters.getDataType(0) != Type.FLOAT - && parameters.getDataType(0) != Type.DOUBLE) { - throw new UDFException("MyAvg only accepts INT32, INT64, FLOAT, DOUBLE as input"); + if (arguments.getDataType(0) != Type.INT32 + && arguments.getDataType(0) != Type.INT64 + && arguments.getDataType(0) != Type.FLOAT + && arguments.getDataType(0) != Type.DOUBLE) { + throw new UDFArgumentNotValidException( + "MyAvg only accepts INT32, INT64, FLOAT, DOUBLE as input"); } - } - - @Override - public void beforeStart(FunctionParameters parameters, AggregateFunctionConfig configurations) { - configurations.setOutputDataType(Type.DOUBLE); + return new AggregateFunctionAnalysis.Builder() + .outputDataType(Type.DOUBLE) + .removable(true) + .build(); } @Override diff --git a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MyCount.java b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MyCount.java index de9436bfd86..9a2ad17b92b 100644 --- a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MyCount.java +++ b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MyCount.java @@ -20,9 +20,9 @@ package org.apache.iotdb.db.query.udf.example.relational; import org.apache.iotdb.udf.api.State; -import org.apache.iotdb.udf.api.customizer.config.AggregateFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; -import org.apache.iotdb.udf.api.exception.UDFException; +import org.apache.iotdb.udf.api.customizer.analysis.AggregateFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.relational.AggregateFunction; import org.apache.iotdb.udf.api.relational.access.Record; import org.apache.iotdb.udf.api.type.Type; @@ -56,15 +56,12 @@ public class MyCount implements AggregateFunction { } @Override - public void validate(FunctionParameters parameters) throws UDFException { - if (parameters.getChildExpressionsSize() == 0) { - throw new UDFException("MyCount accepts at least one parameter"); + public AggregateFunctionAnalysis analyze(FunctionArguments arguments) + throws UDFArgumentNotValidException { + if (arguments.getChildExpressionsSize() == 0) { + throw new UDFArgumentNotValidException("MyCount accepts at least one parameter"); } - } - - @Override - public void beforeStart(FunctionParameters parameters, AggregateFunctionConfig configurations) { - configurations.setOutputDataType(Type.INT64); + return new AggregateFunctionAnalysis.Builder().outputDataType(Type.INT64).build(); } @Override diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBSQLFunctionManagementIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBSQLFunctionManagementIT.java index 93fc3070e67..2cce2fb319d 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBSQLFunctionManagementIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBSQLFunctionManagementIT.java @@ -25,6 +25,7 @@ import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.TableClusterIT; import org.apache.iotdb.itbase.category.TableLocalStandaloneIT; +import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -64,22 +65,26 @@ public class IoTDBSQLFunctionManagementIT { private static final String UDF_JAR_PREFIX = new File(UDF_LIB_PREFIX).toURI().toString(); @BeforeClass - public void setUp() throws Exception { + public static void setUp() throws Exception { EnvFactory.getEnv().initClusterEnvironment(); } @AfterClass - public void tearDown() { + public static void tearDown() { EnvFactory.getEnv().cleanClusterEnvironment(); } + @After + public void dropAll() { + SQLFunctionUtils.dropAllUDF(); + } + @Test public void testCreateShowDropScalarFunction() { try (Connection connection = EnvFactory.getEnv().getTableConnection(); Statement statement = connection.createStatement()) { statement.execute( "create function udsf as 'org.apache.iotdb.db.query.udf.example.relational.ContainNull'"); - try (ResultSet resultSet = statement.executeQuery("show functions")) { assertEquals(4, resultSet.getMetaData().getColumnCount()); int count = 0; @@ -128,8 +133,8 @@ public class IoTDBSQLFunctionManagementIT { public void testCreateShowDropAggregateFunction() { try (Connection connection = EnvFactory.getEnv().getTableConnection(); Statement statement = connection.createStatement()) { - statement.execute( - "create function udaf as 'org.apache.iotdb.db.query.udf.example.relational.MyCount'"); + SQLFunctionUtils.createUDF( + "udaf", "org.apache.iotdb.db.query.udf.example.relational.MyCount"); try (ResultSet resultSet = statement.executeQuery("show functions")) { assertEquals(4, resultSet.getMetaData().getColumnCount()); @@ -331,13 +336,15 @@ public class IoTDBSQLFunctionManagementIT { // ensure that abs is not dropped statement.execute("CREATE DATABASE db"); statement.execute("USE db"); - statement.execute("CREATE TABLE table0 (device string id, s1 INT32)"); + statement.execute("CREATE TABLE table0 (device string TAG, s1 INT32)"); statement.execute("INSERT INTO table0 (time, device, s1) VALUES (1, 'd1', -10)"); try (ResultSet rs = statement.executeQuery("SELECT time, ABS(s1) FROM table0")) { Assert.assertTrue(rs.next()); Assert.assertEquals(1, rs.getLong(1)); Assert.assertEquals(10, rs.getInt(2)); Assert.assertFalse(rs.next()); + } finally { + statement.execute("DROP DATABASE db"); } } } diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBUserDefinedScalarFunctionIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBUserDefinedScalarFunctionIT.java index 17d3170634c..2d1b741a7c6 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBUserDefinedScalarFunctionIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBUserDefinedScalarFunctionIT.java @@ -62,7 +62,7 @@ public class IoTDBUserDefinedScalarFunctionIT { "insert into t2(time, device_id, s1) values (1, 'd0', '2024-02-28')", "insert into t2(time, device_id, s1) values (2, 'd0', '2024-02-29')", "insert into t2(time, device_id, s1) values (3, 'd0', '2024-03-01')", - "CREATE FUNCTION date_plus as 'org.apache.iotdb.db.query.udf.example.relational.DatePlusOne'" + "CREATE FUNCTION date_plus as 'org.apache.iotdb.db.query.udf.example.relational.DatePlus'" }; @BeforeClass diff --git a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/analysis/AggregateFunctionAnalysis.java b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/analysis/AggregateFunctionAnalysis.java new file mode 100644 index 00000000000..2eb4ba76aac --- /dev/null +++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/analysis/AggregateFunctionAnalysis.java @@ -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.iotdb.udf.api.customizer.analysis; + +import org.apache.iotdb.udf.api.type.Type; + +public class AggregateFunctionAnalysis implements FunctionAnalysis { + private final Type outputDataType; + private final boolean removable; + + private AggregateFunctionAnalysis(Type outputDataType, boolean removable) { + this.outputDataType = outputDataType; + this.removable = removable; + } + + public Type getOutputDataType() { + return outputDataType; + } + + public boolean isRemovable() { + return removable; + } + + public static class Builder { + private Type outputDataType; + private boolean removable = false; + + public Builder outputDataType(Type outputDataType) { + this.outputDataType = outputDataType; + return this; + } + + public Builder removable(boolean removable) { + this.removable = removable; + return this; + } + + public AggregateFunctionAnalysis build() throws IllegalArgumentException { + if (outputDataType == null) { + throw new IllegalArgumentException("AggregateFunctionAnalysis outputDataType is not set."); + } + return new AggregateFunctionAnalysis(outputDataType, removable); + } + } +} diff --git a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/analysis/FunctionAnalysis.java b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/analysis/FunctionAnalysis.java new file mode 100644 index 00000000000..fec67233042 --- /dev/null +++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/analysis/FunctionAnalysis.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.udf.api.customizer.analysis; + +/** + * FunctionAnalysis is an interface for analysis configurations of UDFs. It stores runtime + * attributes of UDF. + */ +public interface FunctionAnalysis {} diff --git a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/analysis/ScalarFunctionAnalysis.java b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/analysis/ScalarFunctionAnalysis.java new file mode 100644 index 00000000000..dc633203ed2 --- /dev/null +++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/analysis/ScalarFunctionAnalysis.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.udf.api.customizer.analysis; + +import org.apache.iotdb.udf.api.type.Type; + +public class ScalarFunctionAnalysis implements FunctionAnalysis { + + private final Type outputDataType; + + private ScalarFunctionAnalysis(Type outputDataType) { + this.outputDataType = outputDataType; + } + + public Type getOutputDataType() { + return outputDataType; + } + + public static class Builder { + private Type outputDataType; + + public Builder outputDataType(Type outputDataType) { + this.outputDataType = outputDataType; + return this; + } + + public ScalarFunctionAnalysis build() throws IllegalArgumentException { + if (outputDataType == null) { + throw new IllegalArgumentException("ScalarFunctionAnalysis outputDataType is not set."); + } + return new ScalarFunctionAnalysis(outputDataType); + } + } +} diff --git a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/parameter/FunctionParameters.java b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/parameter/FunctionArguments.java similarity index 94% rename from iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/parameter/FunctionParameters.java rename to iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/parameter/FunctionArguments.java index c80ea478867..ea65984db0f 100644 --- a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/parameter/FunctionParameters.java +++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/customizer/parameter/FunctionArguments.java @@ -25,14 +25,14 @@ import java.util.List; import java.util.Map; /** - * FunctionParameters is used to provide the information of the function parameters to the UDF + * FunctionArguments is used to provide the information of the function parameters to the UDF * implementation. It contains the data types of the child expressions, system attributes, etc. */ -public class FunctionParameters { +public class FunctionArguments { private final List<Type> childExpressionDataTypes; private final Map<String, String> systemAttributes; - public FunctionParameters( + public FunctionArguments( List<Type> childExpressionDataTypes, Map<String, String> systemAttributes) { this.childExpressionDataTypes = childExpressionDataTypes; this.systemAttributes = systemAttributes; diff --git a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/exception/UDFArgumentNotValidException.java b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/exception/UDFArgumentNotValidException.java new file mode 100644 index 00000000000..defa0826e0f --- /dev/null +++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/exception/UDFArgumentNotValidException.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.udf.api.exception; + +public class UDFArgumentNotValidException extends UDFException { + + public UDFArgumentNotValidException(String message) { + super(message); + } +} diff --git a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/AggregateFunction.java b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/AggregateFunction.java index 6a3ec6b0886..6c9d385ac24 100644 --- a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/AggregateFunction.java +++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/AggregateFunction.java @@ -20,8 +20,9 @@ package org.apache.iotdb.udf.api.relational; import org.apache.iotdb.udf.api.State; -import org.apache.iotdb.udf.api.customizer.config.AggregateFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; +import org.apache.iotdb.udf.api.customizer.analysis.AggregateFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.exception.UDFException; import org.apache.iotdb.udf.api.relational.access.Record; import org.apache.iotdb.udf.api.utils.ResultValue; @@ -29,30 +30,33 @@ import org.apache.iotdb.udf.api.utils.ResultValue; public interface AggregateFunction extends SQLFunction { /** - * This method is used to validate {@linkplain FunctionParameters}. - * - * @param parameters parameters used to validate - * @throws UDFException if any parameter is not valid - */ - void validate(FunctionParameters parameters) throws UDFException; - - /** - * This method is mainly used to initialize {@linkplain AggregateFunction} and set the output data - * type. In this method, the user need to do the following things: + * In this method, the user need to do the following things: * * <ul> - * <li>Use {@linkplain FunctionParameters} to get input data types and infer output data type. - * <li>Use {@linkplain FunctionParameters} to get necessary attributes. - * <li>Set the output data type in {@linkplain AggregateFunctionConfig}. + * <li>Validate {@linkplain FunctionArguments}. Throw {@link UDFArgumentNotValidException} if + * any parameter is not valid. + * <li>Use {@linkplain FunctionArguments} to get input data types and infer output data type. + * <li>Construct and return a {@linkplain AggregateFunctionAnalysis} object. * </ul> * - * <p>This method is called after the AggregateFunction is instantiated and before the beginning - * of the transformation process. + * @param arguments arguments used to validate + * @throws UDFArgumentNotValidException if any parameter is not valid + * @return the analysis result of the scalar function + */ + AggregateFunctionAnalysis analyze(FunctionArguments arguments) + throws UDFArgumentNotValidException; + + /** + * This method is called after the AggregateFunction is instantiated and before the beginning of + * the transformation process. This method is mainly used to initialize the resources used in + * AggregateFunction. * - * @param parameters used to parse the input parameters entered by the user - * @param configurations used to set the required properties in the ScalarFunction + * @param arguments used to parse the input arguments entered by the user + * @throws UDFException the user can throw errors if necessary */ - void beforeStart(FunctionParameters parameters, AggregateFunctionConfig configurations); + default void beforeStart(FunctionArguments arguments) throws UDFException { + // do nothing + } /** Create and initialize state. You may bind some resource in this method. */ State createState(); @@ -83,8 +87,8 @@ public interface AggregateFunction extends SQLFunction { /** * Remove input data from state. This method is used to remove the data points that have been - * added to the state. Once it is implemented, {@linkplain AggregateFunctionConfig#setRemovable} - * should be set to true. + * added to the state. Once it is implemented, {@linkplain + * AggregateFunctionAnalysis.Builder#removable(boolean)} should be set to true. * * @param state state to be updated * @param input row to be removed diff --git a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/ScalarFunction.java b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/ScalarFunction.java index adea68e58e4..68d7793093d 100644 --- a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/ScalarFunction.java +++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/ScalarFunction.java @@ -19,38 +19,40 @@ package org.apache.iotdb.udf.api.relational; -import org.apache.iotdb.udf.api.customizer.config.ScalarFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; +import org.apache.iotdb.udf.api.customizer.analysis.ScalarFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; +import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException; import org.apache.iotdb.udf.api.exception.UDFException; import org.apache.iotdb.udf.api.relational.access.Record; public interface ScalarFunction extends SQLFunction { - - /** - * This method is used to validate {@linkplain FunctionParameters}. - * - * @param parameters parameters used to validate - * @throws UDFException if any parameter is not valid - */ - void validate(FunctionParameters parameters) throws UDFException; - /** - * This method is mainly used to initialize {@linkplain ScalarFunction} and set the output data - * type. In this method, the user need to do the following things: + * In this method, the user need to do the following things: * * <ul> - * <li>Use {@linkplain FunctionParameters} to get input data types and infer output data type. - * <li>Use {@linkplain FunctionParameters} to get necessary attributes. - * <li>Set the output data type in {@linkplain ScalarFunctionConfig}. + * <li>Validate {@linkplain FunctionArguments}. Throw {@link UDFArgumentNotValidException} if + * any parameter is not valid. + * <li>Use {@linkplain FunctionArguments} to get input data types and infer output data type. + * <li>Construct and return a {@linkplain ScalarFunctionAnalysis} object. * </ul> * - * <p>This method is called after the ScalarFunction is instantiated and before the beginning of - * the transformation process. + * @param arguments arguments used to validate + * @throws UDFArgumentNotValidException if any parameter is not valid + * @return the analysis result of the scalar function + */ + ScalarFunctionAnalysis analyze(FunctionArguments arguments) throws UDFArgumentNotValidException; + + /** + * This method is called after the ScalarFunction is instantiated and before the beginning of the + * transformation process. This method is mainly used to initialize the resources used in + * ScalarFunction. * - * @param parameters used to parse the input parameters entered by the user - * @param configurations used to set the required properties in the ScalarFunction + * @param arguments used to parse the input arguments entered by the user + * @throws UDFException the user can throw errors if necessary */ - void beforeStart(FunctionParameters parameters, ScalarFunctionConfig configurations); + default void beforeStart(FunctionArguments arguments) throws UDFException { + // do nothing + } /** * This method will be called to process the transformation. In a single UDF query, this method @@ -58,11 +60,10 @@ public interface ScalarFunction extends SQLFunction { * * @param input original input data row * @throws UDFException the user can throw errors if necessary - * @throws UnsupportedOperationException if the user does not override this method */ Object evaluate(Record input) throws UDFException; - /** This method is mainly used to release the resources used in the SQLFunction. */ + /** This method is mainly used to release the resources used in the ScalarFunction. */ default void beforeDestroy() { // do nothing } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/AccumulatorFactory.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/AccumulatorFactory.java index ed47c58ee28..70b7679fc90 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/AccumulatorFactory.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/AccumulatorFactory.java @@ -40,8 +40,7 @@ import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggr import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.GroupedUserDefinedAggregateAccumulator; import org.apache.iotdb.db.queryengine.execution.operator.source.relational.aggregation.grouped.GroupedVarianceAccumulator; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression; -import org.apache.iotdb.udf.api.customizer.config.AggregateFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; import org.apache.iotdb.udf.api.relational.AggregateFunction; import org.apache.tsfile.enums.TSDataType; @@ -123,12 +122,12 @@ public class AccumulatorFactory { private static TableAccumulator createUDAFAccumulator( String functionName, List<TSDataType> inputDataTypes, Map<String, String> inputAttributes) { AggregateFunction aggregateFunction = TableUDFUtils.getAggregateFunction(functionName); - FunctionParameters functionParameters = - new FunctionParameters( + FunctionArguments functionArguments = + new FunctionArguments( UDFDataTypeTransformer.transformToUDFDataTypeList(inputDataTypes), inputAttributes); - AggregateFunctionConfig config = new AggregateFunctionConfig(); - aggregateFunction.beforeStart(functionParameters, config); + aggregateFunction.beforeStart(functionArguments); return new UserDefinedAggregateFunctionAccumulator( + aggregateFunction.analyze(functionArguments), aggregateFunction, inputDataTypes.stream().map(TypeFactory::getType).collect(Collectors.toList())); } @@ -136,11 +135,10 @@ public class AccumulatorFactory { private static GroupedAccumulator createGroupedUDAFAccumulator( String functionName, List<TSDataType> inputDataTypes, Map<String, String> inputAttributes) { AggregateFunction aggregateFunction = TableUDFUtils.getAggregateFunction(functionName); - FunctionParameters functionParameters = - new FunctionParameters( + FunctionArguments functionArguments = + new FunctionArguments( UDFDataTypeTransformer.transformToUDFDataTypeList(inputDataTypes), inputAttributes); - AggregateFunctionConfig config = new AggregateFunctionConfig(); - aggregateFunction.beforeStart(functionParameters, config); + aggregateFunction.beforeStart(functionArguments); return new GroupedUserDefinedAggregateAccumulator( aggregateFunction, inputDataTypes.stream().map(TypeFactory::getType).collect(Collectors.toList())); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/UserDefinedAggregateFunctionAccumulator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/UserDefinedAggregateFunctionAccumulator.java index 1bd6d6430b4..822196a2bcd 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/UserDefinedAggregateFunctionAccumulator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/aggregation/UserDefinedAggregateFunctionAccumulator.java @@ -21,6 +21,7 @@ package org.apache.iotdb.db.queryengine.execution.operator.source.relational.agg import org.apache.iotdb.commons.udf.access.RecordIterator; import org.apache.iotdb.udf.api.State; +import org.apache.iotdb.udf.api.customizer.analysis.AggregateFunctionAnalysis; import org.apache.iotdb.udf.api.relational.AggregateFunction; import org.apache.iotdb.udf.api.utils.ResultValue; @@ -43,12 +44,16 @@ public class UserDefinedAggregateFunctionAccumulator implements TableAccumulator private static final long INSTANCE_SIZE = RamUsageEstimator.shallowSizeOfInstance(UserDefinedAggregateFunctionAccumulator.class); + private final AggregateFunctionAnalysis analysis; private final AggregateFunction aggregateFunction; private final List<Type> inputDataTypes; private final State state; public UserDefinedAggregateFunctionAccumulator( - AggregateFunction aggregateFunction, List<Type> inputDataTypes) { + AggregateFunctionAnalysis analysis, + AggregateFunction aggregateFunction, + List<Type> inputDataTypes) { + this.analysis = analysis; this.aggregateFunction = aggregateFunction; this.inputDataTypes = inputDataTypes; this.state = aggregateFunction.createState(); @@ -61,7 +66,7 @@ public class UserDefinedAggregateFunctionAccumulator implements TableAccumulator @Override public TableAccumulator copy() { - return new UserDefinedAggregateFunctionAccumulator(aggregateFunction, inputDataTypes); + return new UserDefinedAggregateFunctionAccumulator(analysis, aggregateFunction, inputDataTypes); } @Override @@ -121,6 +126,24 @@ public class UserDefinedAggregateFunctionAccumulator implements TableAccumulator state.reset(); } + @Override + public void removeInput(Column[] arguments) { + if (!analysis.isRemovable()) { + throw new UnsupportedOperationException("This Accumulator does not support removing inputs!"); + } + RecordIterator iterator = + new RecordIterator( + Arrays.asList(arguments), inputDataTypes, arguments[0].getPositionCount()); + while (iterator.hasNext()) { + aggregateFunction.remove(state, iterator.next()); + } + } + + @Override + public boolean removable() { + return analysis.isRemovable(); + } + @Override public void close() { aggregateFunction.beforeDestroy(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java index 142aef70199..e2acc16987a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java @@ -157,8 +157,8 @@ import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.scalar.Tr import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.scalar.TrimColumnTransformer; import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.scalar.TryCastFunctionColumnTransformer; import org.apache.iotdb.db.queryengine.transformation.dag.column.unary.scalar.UpperColumnTransformer; -import org.apache.iotdb.udf.api.customizer.config.ScalarFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; +import org.apache.iotdb.udf.api.customizer.analysis.ScalarFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; import org.apache.iotdb.udf.api.relational.ScalarFunction; import org.apache.tsfile.common.conf.TSFileConfig; @@ -1019,16 +1019,16 @@ public class ColumnTransformerBuilder ScalarFunction scalarFunction = TableUDFUtils.getScalarFunction(functionName); List<ColumnTransformer> childrenColumnTransformer = children.stream().map(child -> process(child, context)).collect(Collectors.toList()); - FunctionParameters parameters = - new FunctionParameters( + FunctionArguments parameters = + new FunctionArguments( childrenColumnTransformer.stream() .map(i -> UDFDataTypeTransformer.transformReadTypeToUDFDataType(i.getType())) .collect(Collectors.toList()), Collections.emptyMap()); - ScalarFunctionConfig config = new ScalarFunctionConfig(); - scalarFunction.beforeStart(parameters, config); + ScalarFunctionAnalysis analysis = scalarFunction.analyze(parameters); + scalarFunction.beforeStart(parameters); Type returnType = - UDFDataTypeTransformer.transformUDFDataTypeToReadType(config.getOutputDataType()); + UDFDataTypeTransformer.transformUDFDataTypeToReadType(analysis.getOutputDataType()); return new UserDefineScalarFunctionTransformer( returnType, scalarFunction, childrenColumnTransformer); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java index e544c212a28..aab998339f3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java @@ -49,9 +49,9 @@ import org.apache.iotdb.db.queryengine.plan.relational.type.TypeNotFoundExceptio import org.apache.iotdb.db.queryengine.plan.relational.type.TypeSignature; import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache; import org.apache.iotdb.db.utils.constant.SqlConstant; -import org.apache.iotdb.udf.api.customizer.config.AggregateFunctionConfig; -import org.apache.iotdb.udf.api.customizer.config.ScalarFunctionConfig; -import org.apache.iotdb.udf.api.customizer.parameter.FunctionParameters; +import org.apache.iotdb.udf.api.customizer.analysis.AggregateFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.analysis.ScalarFunctionAnalysis; +import org.apache.iotdb.udf.api.customizer.parameter.FunctionArguments; import org.apache.iotdb.udf.api.relational.AggregateFunction; import org.apache.iotdb.udf.api.relational.ScalarFunction; @@ -643,17 +643,16 @@ public class TableMetadataImpl implements Metadata { // User-defined scalar function if (TableUDFUtils.isScalarFunction(functionName)) { ScalarFunction scalarFunction = TableUDFUtils.getScalarFunction(functionName); - FunctionParameters functionParameters = - new FunctionParameters( + FunctionArguments functionArguments = + new FunctionArguments( argumentTypes.stream() .map(UDFDataTypeTransformer::transformReadTypeToUDFDataType) .collect(Collectors.toList()), Collections.emptyMap()); try { - scalarFunction.validate(functionParameters); - ScalarFunctionConfig config = new ScalarFunctionConfig(); - scalarFunction.beforeStart(functionParameters, config); - return UDFDataTypeTransformer.transformUDFDataTypeToReadType(config.getOutputDataType()); + ScalarFunctionAnalysis scalarFunctionAnalysis = scalarFunction.analyze(functionArguments); + return UDFDataTypeTransformer.transformUDFDataTypeToReadType( + scalarFunctionAnalysis.getOutputDataType()); } catch (Exception e) { throw new SemanticException("Invalid function parameters: " + e.getMessage()); } finally { @@ -661,17 +660,17 @@ public class TableMetadataImpl implements Metadata { } } else if (TableUDFUtils.isAggregateFunction(functionName)) { AggregateFunction aggregateFunction = TableUDFUtils.getAggregateFunction(functionName); - FunctionParameters functionParameters = - new FunctionParameters( + FunctionArguments functionArguments = + new FunctionArguments( argumentTypes.stream() .map(UDFDataTypeTransformer::transformReadTypeToUDFDataType) .collect(Collectors.toList()), Collections.emptyMap()); try { - aggregateFunction.validate(functionParameters); - AggregateFunctionConfig config = new AggregateFunctionConfig(); - aggregateFunction.beforeStart(functionParameters, config); - return UDFDataTypeTransformer.transformUDFDataTypeToReadType(config.getOutputDataType()); + AggregateFunctionAnalysis aggregateFunctionAnalysis = + aggregateFunction.analyze(functionArguments); + return UDFDataTypeTransformer.transformUDFDataTypeToReadType( + aggregateFunctionAnalysis.getOutputDataType()); } catch (Exception e) { throw new SemanticException("Invalid function parameters: " + e.getMessage()); } finally {
