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 {

Reply via email to