You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ja...@apache.org on 2021/01/06 12:11:01 UTC

[iotdb] branch master updated: [IOTDB-1073] Built-in UDTFs (#2417)

This is an automated email from the ASF dual-hosted git repository.

jackietien pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new b0083ea  [IOTDB-1073] Built-in UDTFs (#2417)
b0083ea is described below

commit b0083ea934c4df25ea4136b24d4da81c1eb1f74c
Author: Steve Yurong Su <st...@outlook.com>
AuthorDate: Wed Jan 6 20:10:40 2021 +0800

    [IOTDB-1073] Built-in UDTFs (#2417)
    
    Built-in UDTFs
---
 docs/UserGuide/Operation Manual/Administration.md  |   2 +
 .../DML Data Manipulation Language.md              | 155 ++++++++++++-
 .../Operation Manual/UDF User Defined Function.md  |  14 ++
 .../UserGuide/Operation Manual/Administration.md   |   2 +
 .../DML Data Manipulation Language.md              | 156 ++++++++++++-
 .../Operation Manual/UDF User Defined Function.md  |  16 +-
 .../apache/iotdb/db/qp/executor/PlanExecutor.java  |   2 +-
 .../api/customizer/parameter/UDFParameters.java    |   6 +-
 .../db/query/udf/builtin/BuiltinFunction.java      |  39 +++-
 .../iotdb/db/query/udf/builtin/UDTFAbs.java}       |  64 +++---
 .../{BuiltinFunction.java => UDTFAcos.java}        |  23 +-
 .../{BuiltinFunction.java => UDTFAsin.java}        |  23 +-
 .../{BuiltinFunction.java => UDTFAtan.java}        |  23 +-
 .../iotdb/db/query/udf/builtin/UDTFBottomK.java    | 105 +++++++++
 .../{BuiltinFunction.java => UDTFCeil.java}        |  23 +-
 .../db/query/udf/builtin/UDTFCommonDerivative.java |  62 +++++
 .../udf/builtin/UDTFCommonValueDifference.java     |  60 +++++
 .../iotdb/db/query/udf/builtin/UDTFContains.java}  | 118 +++++-----
 .../builtin/{BuiltinFunction.java => UDTFCos.java} |  23 +-
 .../{BuiltinFunction.java => UDTFDegrees.java}     |  23 +-
 .../db/query/udf/builtin/UDTFDerivative.java}      |  45 ++--
 .../builtin/{BuiltinFunction.java => UDTFExp.java} |  23 +-
 .../{BuiltinFunction.java => UDTFFloor.java}       |  23 +-
 .../builtin/{BuiltinFunction.java => UDTFLog.java} |  23 +-
 .../{BuiltinFunction.java => UDTFLog10.java}       |  23 +-
 .../iotdb/db/query/udf/builtin/UDTFMatches.java}   | 119 +++++-----
 .../iotdb/db/query/udf/builtin/UDTFMath.java}      | 178 +++++++--------
 .../udf/builtin/UDTFNonNegativeDerivative.java     |  63 ++++++
 .../builtin/UDTFNonNegativeValueDifference.java    |  61 +++++
 .../{BuiltinFunction.java => UDTFRadians.java}     |  23 +-
 .../{BuiltinFunction.java => UDTFRound.java}       |  23 +-
 .../iotdb/db/query/udf/builtin/UDTFSelectK.java    | 156 +++++++++++++
 .../{BuiltinFunction.java => UDTFSign.java}        |  23 +-
 .../builtin/{BuiltinFunction.java => UDTFSin.java} |  23 +-
 .../{BuiltinFunction.java => UDTFSqrt.java}        |  23 +-
 .../builtin/{BuiltinFunction.java => UDTFTan.java} |  23 +-
 .../db/query/udf/builtin/UDTFTimeDifference.java}  |  40 ++--
 .../iotdb/db/query/udf/builtin/UDTFTopK.java       | 103 +++++++++
 .../db/query/udf/builtin/UDTFValueDifference.java} |  45 ++--
 .../iotdb/db/query/udf/builtin/UDTFValueTrend.java |  73 ++++++
 .../query/udf/service/UDFRegistrationService.java  |  20 +-
 .../iotdb/db/integration/IoTDBUDFManagementIT.java |  21 +-
 .../db/integration/IoTDBUDTFBuiltinFunctionIT.java | 250 +++++++++++++++++++++
 .../iotdb/db/query/udf/example/Accumulator.java    |   6 -
 .../apache/iotdb/db/query/udf/example/Adder.java   |   6 -
 .../apache/iotdb/db/query/udf/example/Counter.java |   6 -
 .../org/apache/iotdb/db/query/udf/example/Max.java |   6 -
 .../iotdb/db/query/udf/example/Multiplier.java     |   6 -
 .../SlidingSizeWindowConstructorTester0.java       |   6 -
 .../SlidingSizeWindowConstructorTester1.java       |   6 -
 .../SlidingTimeWindowConstructionTester.java       |   6 -
 .../db/query/udf/example/TerminateTester.java      |   6 -
 52 files changed, 1684 insertions(+), 713 deletions(-)

diff --git a/docs/UserGuide/Operation Manual/Administration.md b/docs/UserGuide/Operation Manual/Administration.md
index e8d0bce..266d757 100644
--- a/docs/UserGuide/Operation Manual/Administration.md	
+++ b/docs/UserGuide/Operation Manual/Administration.md	
@@ -141,6 +141,8 @@ At the same time, changes to roles are immediately reflected on all users who ow
 |LIST\_ROLE|list all roles; list the privileges of a role; list the three kinds of operation privileges of all users owning a role; path independent|
 |GRANT\_ROLE\_PRIVILEGE|grant role privileges; path independent|
 |REVOKE\_ROLE\_PRIVILEGE|revoke role privileges; path independent|
+|CREATE_FUNCTION|register UDFs; path independent|
+|DROP_FUNCTION|deregister UDFs; path independent|
 </center>
 
 ### Username Restrictions
diff --git a/docs/UserGuide/Operation Manual/DML Data Manipulation Language.md b/docs/UserGuide/Operation Manual/DML Data Manipulation Language.md
index 35b8830..0ce9898 100644
--- a/docs/UserGuide/Operation Manual/DML Data Manipulation Language.md	
+++ b/docs/UserGuide/Operation Manual/DML Data Manipulation Language.md	
@@ -222,7 +222,160 @@ Total line number = 10
 It costs 0.016s
 ```
 
+### Time Series Generating Functions
+
+The time series generating function takes several time series as input and outputs one time series. Unlike the aggregation function, the result set of the time series generating function has a timestamp column.
+
+All time series generating functions can accept * as input.
+
+IoTDB supports hybrid queries of time series generating function queries and raw data queries.
+
+#### Mathematical Functions
+
+Currently IoTDB supports the following mathematical functions. The behavior of these mathematical functions is consistent with the behavior of these functions in the Java Math standard library.
+
+| Function Name | Allowed Input Series Data Types | Output Series Data Type       | Corresponding Implementation in the Java Standard Library    |
+| ------------- | ------------------------------- | ----------------------------- | ------------------------------------------------------------ |
+| SIN           | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#sin(double)                                             |
+| COS           | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#cos(double)                                             |
+| TAN           | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#tan(double)                                             |
+| ASIN          | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#asin(double)                                            |
+| ACOS          | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#acos(double)                                            |
+| ATAN          | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#atan(double)                                            |
+| DEGREES       | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#toDegrees(double)                                       |
+| RADIANS       | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#toRadians(double)                                       |
+| ABS           | INT32 / INT64 / FLOAT / DOUBLE  | Same type as the input series | Math#abs(int) / Math#abs(long) /Math#abs(float) /Math#abs(double) |
+| SIGN          | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#signum(double)                                          |
+| CEIL          | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#ceil(double)                                            |
+| FLOOR         | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#floor(double)                                           |
+| ROUND         | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#rint(double)                                            |
+| EXP           | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#exp(double)                                             |
+| LN            | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#log(double)                                             |
+| LOG10         | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#log10(double)                                           |
+| SQRT          | INT32 / INT64 / FLOAT / DOUBLE  | DOUBLE                        | Math#sqrt(double)                                            |
+
+Example:
+
+```   sql
+select s1, sin(s1), cos(s1), tan(s1) from root.sg1.d1 limit 5 offset 1000;
+```
+
+Result:
+
+```
++-----------------------------+-------------------+-------------------+--------------------+-------------------+
+|                         Time|     root.sg1.d1.s1|sin(root.sg1.d1.s1)| cos(root.sg1.d1.s1)|tan(root.sg1.d1.s1)|
++-----------------------------+-------------------+-------------------+--------------------+-------------------+
+|2020-12-10T17:11:49.037+08:00|7360723084922759782| 0.8133527237573284|  0.5817708713544664| 1.3980636773094157|
+|2020-12-10T17:11:49.038+08:00|4377791063319964531|-0.8938962705202537|  0.4482738644511651| -1.994085181866842|
+|2020-12-10T17:11:49.039+08:00|7972485567734642915| 0.9627757585308978|-0.27030138509681073|-3.5618602479083545|
+|2020-12-10T17:11:49.040+08:00|2508858212791964081|-0.6073417341629443| -0.7944406950452296| 0.7644897069734913|
+|2020-12-10T17:11:49.041+08:00|2817297431185141819|-0.8419358900502509| -0.5395775727782725| 1.5603611649667768|
++-----------------------------+-------------------+-------------------+--------------------+-------------------+
+Total line number = 5
+It costs 0.008s
+```
+
+#### String Processing Functions
+
+Currently IoTDB supports the following string processing functions:
+
+| Function Name   | Allowed Input Series Data Types | Required Attributes                                          | Output Series Data Type | Description                                            |
+| --------------- | ------------------------------- | ------------------------------------------------------------ | ----------------------- | ------------------------------------------------------ |
+| STRING_CONTAINS | TEXT                            | `s`: the sequence to search for                              | BOOLEAN                 | Determine whether `s` is in the string                 |
+| STRING_MATCHES  | TEXT                            | `regex`: the regular expression to which the string is to be matched | BOOLEAN                 | Determine whether the string can be matched by `regex` |
+
+Example:
+
+```   sql
+select s1, string_contains(s1, "s"="warn"), string_matches(s1, "regex"="[^\\s]+37229") from root.sg1.d4;
+```
+
+Result:
+
+``` 
++-----------------------------+--------------+-------------------------------------------+------------------------------------------------------+
+|                         Time|root.sg1.d4.s1|string_contains(root.sg1.d4.s1, "s"="warn")|string_matches(root.sg1.d4.s1, "regex"="[^\\s]+37229")|
++-----------------------------+--------------+-------------------------------------------+------------------------------------------------------+
+|1970-01-01T08:00:00.001+08:00|    warn:-8721|                                       true|                                                 false|
+|1970-01-01T08:00:00.002+08:00|  error:-37229|                                      false|                                                  true|
+|1970-01-01T08:00:00.003+08:00|     warn:1731|                                       true|                                                 false|
++-----------------------------+--------------+-------------------------------------------+------------------------------------------------------+
+Total line number = 3
+It costs 0.007s
+```
+
+#### Selector Functions
+
+Currently IoTDB supports the following selector functions:
+
+| Function Name | Allowed Input Series Data Types       | Required Attributes                                          | Output Series Data Type       | Description                                                  |
+| ------------- | ------------------------------------- | ------------------------------------------------------------ | ----------------------------- | ------------------------------------------------------------ |
+| TOP_K         | INT32 / INT64 / FLOAT / DOUBLE / TEXT | `k`: the maximum number of selected data points, must be greater than 0 and less than or equal to 1000 | Same type as the input series | Returns `k` data points with the largest values in a time series. |
+| BOTTOM_K      | INT32 / INT64 / FLOAT / DOUBLE / TEXT | `k`: the maximum number of selected data points, must be greater than 0 and less than or equal to 1000 | Same type as the input series | Returns `k` data points with the smallest values in a time series. |
+
+Example:
+
+```   sql
+select s1, top_k(s1, "k"="2"), bottom_k(s1, "k"="2") from root.sg1.d2 where time > 2020-12-10T20:36:15.530+08:00;
+```
+
+Result:
+
+``` 
++-----------------------------+--------------------+------------------------------+---------------------------------+
+|                         Time|      root.sg1.d2.s1|top_k(root.sg1.d2.s1, "k"="2")|bottom_k(root.sg1.d2.s1, "k"="2")|
++-----------------------------+--------------------+------------------------------+---------------------------------+
+|2020-12-10T20:36:15.531+08:00| 1531604122307244742|           1531604122307244742|                             null|
+|2020-12-10T20:36:15.532+08:00|-7426070874923281101|                          null|                             null|
+|2020-12-10T20:36:15.533+08:00|-7162825364312197604|          -7162825364312197604|                             null|
+|2020-12-10T20:36:15.534+08:00|-8581625725655917595|                          null|             -8581625725655917595|
+|2020-12-10T20:36:15.535+08:00|-7667364751255535391|                          null|             -7667364751255535391|
++-----------------------------+--------------------+------------------------------+---------------------------------+
+Total line number = 5
+It costs 0.006s
+```
+
+#### Variation Trend Calculation Functions
+
+Currently IoTDB supports the following variation trend calculation functions:
+
+| Function Name           | Allowed Input Series Data Types                 | Output Series Data Type       | Description                                                  |
+| ----------------------- | ----------------------------------------------- | ----------------------------- | ------------------------------------------------------------ |
+| TIME_DIFFERENCE         | INT32 / INT64 / FLOAT / DOUBLE / BOOLEAN / TEXT | INT64                         | Calculates the difference between the time stamp of a data point and the time stamp of the previous data point. There is no corresponding output for the first data point. |
+| DIFFERENCE              | INT32 / INT64 / FLOAT / DOUBLE                  | Same type as the input series | Calculates the difference between the value of a data point and the value of the previous data point. There is no corresponding output for the first data point. |
+| NON_NEGATIVE_DIFFERENCE | INT32 / INT64 / FLOAT / DOUBLE                  | Same type as the input series | Calculates the absolute value of the difference between the value of a data point and the value of the previous data point. There is no corresponding output for the first data point. |
+| DERIVATIVE              | INT32 / INT64 / FLOAT / DOUBLE                  | DOUBLE                        | Calculates the rate of change of a data point compared to the previous data point, the result is equals to DIFFERENCE / TIME_DIFFERENCE. There is no corresponding output for the first data point. |
+| NON_NEGATIVE_DERIVATIVE | INT32 / INT64 / FLOAT / DOUBLE                  | DOUBLE                        | Calculates the absolute value of the rate of change of a data point compared to the previous data point, the result is equals to NON_NEGATIVE_DIFFERENCE / TIME_DIFFERENCE. There is no corresponding output for the first data point. |
+
+Example:
+
+```   sql
+select s1, time_difference(s1), difference(s1), non_negative_difference(s1), derivative(s1), non_negative_derivative(s1) from root.sg1.d1 limit 5 offset 1000; 
+```
+
+Result:
+
+``` 
++-----------------------------+-------------------+-------------------------------+--------------------------+---------------------------------------+--------------------------+---------------------------------------+
+|                         Time|     root.sg1.d1.s1|time_difference(root.sg1.d1.s1)|difference(root.sg1.d1.s1)|non_negative_difference(root.sg1.d1.s1)|derivative(root.sg1.d1.s1)|non_negative_derivative(root.sg1.d1.s1)|
++-----------------------------+-------------------+-------------------------------+--------------------------+---------------------------------------+--------------------------+---------------------------------------+
+|2020-12-10T17:11:49.037+08:00|7360723084922759782|                              1|      -8431715764844238876|                    8431715764844238876|    -8.4317157648442388E18|                  8.4317157648442388E18|
+|2020-12-10T17:11:49.038+08:00|4377791063319964531|                              1|      -2982932021602795251|                    2982932021602795251|     -2.982932021602795E18|                   2.982932021602795E18|
+|2020-12-10T17:11:49.039+08:00|7972485567734642915|                              1|       3594694504414678384|                    3594694504414678384|     3.5946945044146785E18|                  3.5946945044146785E18|
+|2020-12-10T17:11:49.040+08:00|2508858212791964081|                              1|      -5463627354942678834|                    5463627354942678834|     -5.463627354942679E18|                   5.463627354942679E18|
+|2020-12-10T17:11:49.041+08:00|2817297431185141819|                              1|        308439218393177738|                     308439218393177738|     3.0843921839317773E17|                  3.0843921839317773E17|
++-----------------------------+-------------------+-------------------------------+--------------------------+---------------------------------------+--------------------------+---------------------------------------+
+Total line number = 5
+It costs 0.014s
+```
+
+#### User Defined Timeseries Generating Functions
+
+Please refer to [UDF (User Defined Function)](../Operation%20Manual/UDF%20User%20Defined%20Function.md).
+
 ### Aggregate Query
+
 This section mainly introduces the related examples of aggregate query.
 
 #### Count Points
@@ -686,7 +839,7 @@ using PREVIOUSUNTILLAST won't fill time after 2017-11-07T23:59.
 ### Last point Query
 
 In scenarios when IoT devices updates data in a fast manner, users are more interested in the most recent point of IoT devices.
- 
+
 The Last point query is to return the most recent data point of the given timeseries in a three column format.
 
 The SQL statement is defined as:
diff --git a/docs/UserGuide/Operation Manual/UDF User Defined Function.md b/docs/UserGuide/Operation Manual/UDF User Defined Function.md
index e744d8b..9ed06e8 100644
--- a/docs/UserGuide/Operation Manual/UDF User Defined Function.md	
+++ b/docs/UserGuide/Operation Manual/UDF User Defined Function.md	
@@ -407,6 +407,8 @@ CREATE FUNCTION example AS "org.apache.iotdb.udf.ExampleUDTF"
 
 Since UDF instances are dynamically loaded through reflection technology, you do not need to restart the server during the UDF registration process.
 
+Note: UDF function names are not case sensitive.
+
 Note: Please ensure that the function name given to the UDF is different from all built-in function names. A UDF with the same name as a built-in function cannot be registered.
 
 Note: We recommend that you do not use classes that have the same class name but different function logic in different JAR packages. For example, in `UDF(UDAF/UDTF): udf1, udf2`, the JAR package of udf1 is `udf1.jar` and the JAR package of udf2 is `udf2.jar`. Assume that both JAR packages contain the `org.apache.iotdb.udf.ExampleUDTF` class. If you use two UDFs in the same SQL statement at the same time, the system will randomly load either of them and may cause inconsistency in UDF exec [...]
@@ -493,6 +495,18 @@ SHOW FUNCTIONS
 
 
 
+## User Permission Management
+
+There are 3 types of user permissions related to UDF:
+
+* `CREATE_FUNCTION`: Only users with this permission are allowed to register UDFs
+* `DROP_FUNCTION`: Only users with this permission are allowed to deregister UDFs
+* `READ_TIMESERIES`: Only users with this permission are allowed to use UDFs for queries
+
+For more user permissions related content, please refer to [Account Management Statements](../Operation%20Manual/Administration.md).
+
+
+
 ## Configurable Properties
 
 When querying by a UDF, IoTDB may prompt that there is insufficient memory. You can resolve the issue by configuring `udf_initial_byte_array_length_for_memory_control`, `udf_memory_budget_in_mb` and `udf_reader_transformer_collector_memory_proportion` in `iotdb-engine.properties` and restarting the server.
diff --git a/docs/zh/UserGuide/Operation Manual/Administration.md b/docs/zh/UserGuide/Operation Manual/Administration.md
index 9706b1a..10747a5 100644
--- a/docs/zh/UserGuide/Operation Manual/Administration.md	
+++ b/docs/zh/UserGuide/Operation Manual/Administration.md	
@@ -118,6 +118,8 @@ INSERT INTO root.ln.wf01.wt01(timestamp, status) values(1509465600000, true)
 |LIST\_ROLE|列出所有角色,列出某角色拥有的权限,列出拥有某角色的所有用户三种操作的权限。路径无关|
 |GRANT\_ROLE\_PRIVILEGE|grant role priviledges; path independent|
 |REVOKE\_ROLE\_PRIVILEGE|撤销角色权限。路径无关|
+|CREATE_FUNCTION|注册UDF。路径无关|
+|DROP_FUNCTION|卸载UDF。路径无关|
 </center>
 
 ### 用户名限制
diff --git a/docs/zh/UserGuide/Operation Manual/DML Data Manipulation Language.md b/docs/zh/UserGuide/Operation Manual/DML Data Manipulation Language.md
index 3a2e032..a7502d3 100644
--- a/docs/zh/UserGuide/Operation Manual/DML Data Manipulation Language.md	
+++ b/docs/zh/UserGuide/Operation Manual/DML Data Manipulation Language.md	
@@ -281,7 +281,158 @@ It costs 0.018s
 
 更多语法请参照[SQL REFERENCE](../Operation%20Manual/SQL%20Reference.md)。
 
+### 时间序列生成函数查询
+
+时间序列生成函数可接受若干原始时间序列作为输入,产生一列时间序列输出。与聚合函数不同的是,时间序列生成函数的结果集带有时间戳列。
+
+所有的时间序列生成函数都可以接受 * 作为输入,都可以与原始查询混合进行。
+
+#### 数学函数
+
+目前IoTDB支持下列数学函数,这些数学函数的行为与这些函数在Java Math标准库中对应实现的行为一致。
+
+| 函数名  | 输入序列类型                   | 输出序列类型             | Java标准库中的对应实现                                       |
+| ------- | ------------------------------ | ------------------------ | ------------------------------------------------------------ |
+| SIN     | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#sin(double)                                             |
+| COS     | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#cos(double)                                             |
+| TAN     | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#tan(double)                                             |
+| ASIN    | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#asin(double)                                            |
+| ACOS    | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#acos(double)                                            |
+| ATAN    | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#atan(double)                                            |
+| DEGREES | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#toDegrees(double)                                       |
+| RADIANS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#toRadians(double)                                       |
+| ABS     | INT32 / INT64 / FLOAT / DOUBLE | 与输入序列的实际类型一致 | Math#abs(int) / Math#abs(long) /Math#abs(float) /Math#abs(double) |
+| SIGN    | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#signum(double)                                          |
+| CEIL    | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#ceil(double)                                            |
+| FLOOR   | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#floor(double)                                           |
+| ROUND   | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#rint(double)                                            |
+| EXP     | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#exp(double)                                             |
+| LN      | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#log(double)                                             |
+| LOG10   | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#log10(double)                                           |
+| SQRT    | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE                   | Math#sqrt(double)                                            |
+
+例如:
+
+```   sql
+select s1, sin(s1), cos(s1), tan(s1) from root.sg1.d1 limit 5 offset 1000;
+```
+
+结果:
+
+```
++-----------------------------+-------------------+-------------------+--------------------+-------------------+
+|                         Time|     root.sg1.d1.s1|sin(root.sg1.d1.s1)| cos(root.sg1.d1.s1)|tan(root.sg1.d1.s1)|
++-----------------------------+-------------------+-------------------+--------------------+-------------------+
+|2020-12-10T17:11:49.037+08:00|7360723084922759782| 0.8133527237573284|  0.5817708713544664| 1.3980636773094157|
+|2020-12-10T17:11:49.038+08:00|4377791063319964531|-0.8938962705202537|  0.4482738644511651| -1.994085181866842|
+|2020-12-10T17:11:49.039+08:00|7972485567734642915| 0.9627757585308978|-0.27030138509681073|-3.5618602479083545|
+|2020-12-10T17:11:49.040+08:00|2508858212791964081|-0.6073417341629443| -0.7944406950452296| 0.7644897069734913|
+|2020-12-10T17:11:49.041+08:00|2817297431185141819|-0.8419358900502509| -0.5395775727782725| 1.5603611649667768|
++-----------------------------+-------------------+-------------------+--------------------+-------------------+
+Total line number = 5
+It costs 0.008s
+```
+
+#### 字符串函数
+
+目前IoTDB支持下列字符串处理函数:
+
+| 函数名          | 输入序列类型 | 必要的属性参数                      | 输出序列类型 | 功能描述                                  |
+| --------------- | ------------ | ----------------------------------- | ------------ | ----------------------------------------- |
+| STRING_CONTAINS | TEXT         | `s`: 待搜寻的字符串                 | BOOLEAN      | 判断字符串中是否存在`s`                   |
+| STRING_MATCHES  | TEXT         | `regex`: Java标准库风格的正则表达式 | BOOLEAN      | 判断字符串是否能够被正则表达式`regex`匹配 |
+
+例如:
+
+```   sql
+select s1, string_contains(s1, "s"="warn"), string_matches(s1, "regex"="[^\\s]+37229") from root.sg1.d4;
+```
+
+结果:
+
+``` 
++-----------------------------+--------------+-------------------------------------------+------------------------------------------------------+
+|                         Time|root.sg1.d4.s1|string_contains(root.sg1.d4.s1, "s"="warn")|string_matches(root.sg1.d4.s1, "regex"="[^\\s]+37229")|
++-----------------------------+--------------+-------------------------------------------+------------------------------------------------------+
+|1970-01-01T08:00:00.001+08:00|    warn:-8721|                                       true|                                                 false|
+|1970-01-01T08:00:00.002+08:00|  error:-37229|                                      false|                                                  true|
+|1970-01-01T08:00:00.003+08:00|     warn:1731|                                       true|                                                 false|
++-----------------------------+--------------+-------------------------------------------+------------------------------------------------------+
+Total line number = 3
+It costs 0.007s
+```
+
+#### 选择函数
+
+目前IoTDB支持如下选择函数:
+
+| 函数名   | 输入序列类型                          | 必要的属性参数                                 | 输出序列类型             | 功能描述                                                     |
+| -------- | ------------------------------------- | ---------------------------------------------- | ------------------------ | ------------------------------------------------------------ |
+| TOP_K    | INT32 / INT64 / FLOAT / DOUBLE / TEXT | `k`: 最多选择的数据点数,必须大于0小于等于1000 | 与输入序列的实际类型一致 | 返回某时间序列中值最大的`k`个数据点。若多于`k`个数据点的值并列最大,则返回时间戳最小的数据点。 |
+| BOTTOM_K | INT32 / INT64 / FLOAT / DOUBLE / TEXT | `k`: 最多选择的数据点数,必须大于0小于等于1000 | 与输入序列的实际类型一致 | 返回某时间序列中值最小的`k`个数据点。若多于`k`个数据点的值并列最小,则返回时间戳最小的数据点。 |
+
+例如:
+
+```   sql
+select s1, top_k(s1, "k"="2"), bottom_k(s1, "k"="2") from root.sg1.d2 where time > 2020-12-10T20:36:15.530+08:00;
+```
+
+结果:
+
+``` 
++-----------------------------+--------------------+------------------------------+---------------------------------+
+|                         Time|      root.sg1.d2.s1|top_k(root.sg1.d2.s1, "k"="2")|bottom_k(root.sg1.d2.s1, "k"="2")|
++-----------------------------+--------------------+------------------------------+---------------------------------+
+|2020-12-10T20:36:15.531+08:00| 1531604122307244742|           1531604122307244742|                             null|
+|2020-12-10T20:36:15.532+08:00|-7426070874923281101|                          null|                             null|
+|2020-12-10T20:36:15.533+08:00|-7162825364312197604|          -7162825364312197604|                             null|
+|2020-12-10T20:36:15.534+08:00|-8581625725655917595|                          null|             -8581625725655917595|
+|2020-12-10T20:36:15.535+08:00|-7667364751255535391|                          null|             -7667364751255535391|
++-----------------------------+--------------------+------------------------------+---------------------------------+
+Total line number = 5
+It costs 0.006s
+```
+
+#### 趋势计算函数
+
+目前IoTDB支持如下趋势计算函数:
+
+| 函数名                  | 输入序列类型                                    | 输出序列类型             | 功能描述                                                     |
+| ----------------------- | ----------------------------------------------- | ------------------------ | ------------------------------------------------------------ |
+| TIME_DIFFERENCE         | INT32 / INT64 / FLOAT / DOUBLE / BOOLEAN / TEXT | INT64                    | 统计序列中某数据点的时间戳与前一数据点时间戳的差。范围内第一个数据点没有对应的结果输出。 |
+| DIFFERENCE              | INT32 / INT64 / FLOAT / DOUBLE                  | 与输入序列的实际类型一致 | 统计序列中某数据点的值与前一数据点的值的差。范围内第一个数据点没有对应的结果输出。 |
+| NON_NEGATIVE_DIFFERENCE | INT32 / INT64 / FLOAT / DOUBLE                  | 与输入序列的实际类型一致 | 统计序列中某数据点的值与前一数据点的值的差的绝对值。范围内第一个数据点没有对应的结果输出。 |
+| DERIVATIVE              | INT32 / INT64 / FLOAT / DOUBLE                  | DOUBLE                   | 统计序列中某数据点相对于前一数据点的变化率,数量上等同于 DIFFERENCE /  TIME_DIFFERENCE。范围内第一个数据点没有对应的结果输出。 |
+| NON_NEGATIVE_DERIVATIVE | INT32 / INT64 / FLOAT / DOUBLE                  | DOUBLE                   | 统计序列中某数据点相对于前一数据点的变化率的绝对值,数量上等同于 NON_NEGATIVE_DIFFERENCE /  TIME_DIFFERENCE。范围内第一个数据点没有对应的结果输出。 |
+
+例如:
+
+```   sql
+select s1, time_difference(s1), difference(s1), non_negative_difference(s1), derivative(s1), non_negative_derivative(s1) from root.sg1.d1 limit 5 offset 1000; 
+```
+
+结果:
+
+``` 
++-----------------------------+-------------------+-------------------------------+--------------------------+---------------------------------------+--------------------------+---------------------------------------+
+|                         Time|     root.sg1.d1.s1|time_difference(root.sg1.d1.s1)|difference(root.sg1.d1.s1)|non_negative_difference(root.sg1.d1.s1)|derivative(root.sg1.d1.s1)|non_negative_derivative(root.sg1.d1.s1)|
++-----------------------------+-------------------+-------------------------------+--------------------------+---------------------------------------+--------------------------+---------------------------------------+
+|2020-12-10T17:11:49.037+08:00|7360723084922759782|                              1|      -8431715764844238876|                    8431715764844238876|    -8.4317157648442388E18|                  8.4317157648442388E18|
+|2020-12-10T17:11:49.038+08:00|4377791063319964531|                              1|      -2982932021602795251|                    2982932021602795251|     -2.982932021602795E18|                   2.982932021602795E18|
+|2020-12-10T17:11:49.039+08:00|7972485567734642915|                              1|       3594694504414678384|                    3594694504414678384|     3.5946945044146785E18|                  3.5946945044146785E18|
+|2020-12-10T17:11:49.040+08:00|2508858212791964081|                              1|      -5463627354942678834|                    5463627354942678834|     -5.463627354942679E18|                   5.463627354942679E18|
+|2020-12-10T17:11:49.041+08:00|2817297431185141819|                              1|        308439218393177738|                     308439218393177738|     3.0843921839317773E17|                  3.0843921839317773E17|
++-----------------------------+-------------------+-------------------------------+--------------------------+---------------------------------------+--------------------------+---------------------------------------+
+Total line number = 5
+It costs 0.014s
+```
+
+#### 自定义序列生成函数
+
+请参考 [UDF (用户定义函数)](../Operation%20Manual/UDF%20User%20Defined%20Function.md)。
+
 ### 聚合查询
+
 本章节主要介绍聚合查询的相关示例,
 主要使用的是IoTDB SELECT语句的聚合查询函数。
 
@@ -1279,9 +1430,9 @@ It costs 0.012s
 ```
 
 “禁用对齐”指示结果集中每个时间序列都有3列。
- 
+
 SQL语句是:
- 
+
  ```
  select * from root.sg1 where time > 10 disable align
  ```
@@ -1458,3 +1609,4 @@ DELETE PARTITION root.ln 0,1,2
 手动地将一个时间戳转换为对应的id,其中的`partitionInterval`可以在IoTDB的配置文件中找到(如果您使用的版本支持时间分区)。
 
 请注意该功能目前只是实验性的,如果您不是开发者,使用时请务必谨慎。
+
diff --git a/docs/zh/UserGuide/Operation Manual/UDF User Defined Function.md b/docs/zh/UserGuide/Operation Manual/UDF User Defined Function.md
index 4ace6fe..53e67ff 100644
--- a/docs/zh/UserGuide/Operation Manual/UDF User Defined Function.md	
+++ b/docs/zh/UserGuide/Operation Manual/UDF User Defined Function.md	
@@ -388,7 +388,7 @@ UDTF的结束方法,您可以在此方法中进行一些资源释放等的操
 1. 实现一个完整的UDF类,假定这个类的全类名为`org.apache.iotdb.udf.ExampleUDTF`
 2. 将项目打成JAR包,如果您使用Maven管理项目,可以参考上述Maven项目示例的写法
 3. 将JAR包放置到目录 `iotdb-server-0.12.0-SNAPSHOT/ext/udf` (也可以是`iotdb-server-0.12.0-SNAPSHOT/ext/udf`的子目录)下。
-   
+    
     > 您可以通过修改配置文件中的`udf_root_dir`来指定UDF加载Jar的根路径。
 4. 使用SQL语句注册该UDF,假定赋予该UDF的名字为`example`
 
@@ -406,6 +406,8 @@ CREATE FUNCTION example AS "org.apache.iotdb.udf.ExampleUDTF"
 
 由于IoTDB的UDF是通过反射技术动态装载的,因此您在装载过程中无需启停服务器。
 
+注意:UDF函数名称是大小写不敏感的。
+
 注意:请不要给UDF函数注册一个内置函数的名字。使用内置函数的名字给UDF注册会失败。
 
 注意:不同的JAR包中最好不要有全类名相同但实现功能逻辑不一样的类。例如 UDF(UDAF/UDTF):`udf1`、`udf2`分别对应资源`udf1.jar`、`udf2.jar`。如果两个JAR包里都包含一个`org.apache.iotdb.udf.ExampleUDTF`类,当同一个SQL中同时使用到这两个UDF时,系统会随机加载其中一个类,导致UDF执行行为不一致。
@@ -494,6 +496,18 @@ SHOW FUNCTIONS
 
 
 
+## 用户权限管理
+
+用户在使用UDF时会涉及到3种权限:
+
+* `CREATE_FUNCTION`:具备该权限的用户才被允许执行UDF注册操作
+* `DROP_FUNCTION`:具备该权限的用户才被允许执行UDF卸载操作
+* `READ_TIMESERIES`:具备该权限的用户才被允许使用UDF进行查询
+
+更多用户权限相关的内容,请参考[权限管理语句](../Operation%20Manual/Administration.md)。
+
+
+
 ## 配置项
 
 在SQL语句中使用自定义函数时,可能提示内存不足。这种情况下,您可以通过更改配置文件`iotdb-engine.properties`中的`udf_initial_byte_array_length_for_memory_control`,`udf_memory_budget_in_mb`和`udf_reader_transformer_collector_memory_proportion`并重启服务来解决此问题。
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
index a8decd4..418ad7a 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
@@ -769,7 +769,7 @@ public class PlanExecutor implements IPlanExecutor {
     final Binary className = Binary.valueOf("");
     for (String functionName : SQLConstant.getNativeFunctionNames()) {
       RowRecord rowRecord = new RowRecord(0); // ignore timestamp
-      rowRecord.addField(Binary.valueOf(functionName), TSDataType.TEXT);
+      rowRecord.addField(Binary.valueOf(functionName.toUpperCase()), TSDataType.TEXT);
       rowRecord.addField(functionType, TSDataType.TEXT);
       rowRecord.addField(className, TSDataType.TEXT);
       listDataSet.putRecord(rowRecord);
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameters.java b/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameters.java
index da35cbf..1926095 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameters.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/api/customizer/parameter/UDFParameters.java
@@ -72,8 +72,10 @@ public class UDFParameters {
   }
 
   public TSDataType getDataType(int index) throws MetadataException {
-    return dataTypes != null ? dataTypes.get(index)
-        : SchemaUtils.getSeriesTypeByPath(paths.get(index));
+    if (dataTypes == null) {
+      dataTypes = SchemaUtils.getSeriesTypesByPaths(paths);
+    }
+    return dataTypes.get(index);
   }
 
   public TSDataType getDataType(String path) throws MetadataException {
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
index c8bb083..1168f08 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
@@ -20,23 +20,56 @@
 package org.apache.iotdb.db.query.udf.builtin;
 
 /**
- * All built-in UDFs need to register function names and full class names here.
+ * All built-in UDFs need to register their function names and classes here.
  */
 public enum BuiltinFunction {
+
+  SIN("SIN", UDTFSin.class),
+  COS("COS", UDTFCos.class),
+  TAN("TAN", UDTFTan.class),
+  ASIN("ASIN", UDTFAsin.class),
+  ACOS("ACOS", UDTFAcos.class),
+  ATAN("ATAN", UDTFAtan.class),
+  DEGREES("DEGREES", UDTFDegrees.class),
+  RADIANS("RADIANS", UDTFRadians.class),
+  ABS("ABS", UDTFAbs.class),
+  SIGN("SIGN", UDTFSign.class),
+  CEIL("CEIL", UDTFCeil.class),
+  FLOOR("FLOOR", UDTFFloor.class),
+  ROUND("ROUND", UDTFRound.class),
+  EXP("EXP", UDTFExp.class),
+  LN("LN", UDTFLog.class),
+  LOG10("LOG10", UDTFLog10.class),
+  SQRT("SQRT", UDTFSqrt.class),
+  STRING_CONTAINS("STRING_CONTAINS", UDTFContains.class),
+  STRING_MATCHES("STRING_MATCHES", UDTFMatches.class),
+  DIFFERENCE("DIFFERENCE", UDTFCommonValueDifference.class),
+  NON_NEGATIVE_DIFFERENCE("NON_NEGATIVE_DIFFERENCE", UDTFNonNegativeValueDifference.class),
+  TIME_DIFFERENCE("TIME_DIFFERENCE", UDTFTimeDifference.class),
+  DERIVATIVE("DERIVATIVE", UDTFCommonDerivative.class),
+  NON_NEGATIVE_DERIVATIVE("NON_NEGATIVE_DERIVATIVE", UDTFNonNegativeDerivative.class),
+  TOP_K("TOP_K", UDTFTopK.class),
+  BOTTOM_K("BOTTOM_K", UDTFBottomK.class),
   ;
 
   private final String functionName;
+  private final Class<?> functionClass;
   private final String className;
 
-  BuiltinFunction(String functionName, String className) {
+  BuiltinFunction(String functionName, Class<?> functionClass) {
     this.functionName = functionName;
-    this.className = className;
+    this.functionClass = functionClass;
+    this.className = functionClass.getName();
   }
 
   public String getFunctionName() {
     return functionName;
   }
 
+  public Class<?> getFunctionClass() {
+    return functionClass;
+  }
+
   public String getClassName() {
     return className;
   }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAbs.java
similarity index 51%
copy from server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAbs.java
index eea5abb..fff5147 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAbs.java
@@ -17,56 +17,54 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.query.udf.example;
+package org.apache.iotdb.db.query.udf.builtin;
 
 import java.io.IOException;
-import org.apache.iotdb.db.query.udf.api.UDTF;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
-import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 
-public class Max implements UDTF {
-
-  private Long time;
-  private int value;
+public class UDTFAbs extends UDTFMath {
 
   @Override
-  public void validate(UDFParameterValidator validator) throws Exception {
-    validator
-        .validateInputSeriesNumber(1)
-        .validateInputSeriesDataType(0, TSDataType.INT32);
-  }
-
-  @Override
-  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Max#beforeStart");
+  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations)
+      throws MetadataException {
+    dataType = parameters.getDataType(0);
     configurations
-        .setOutputDataType(TSDataType.INT32)
-        .setAccessStrategy(new RowByRowAccessStrategy());
+        .setAccessStrategy(new RowByRowAccessStrategy())
+        .setOutputDataType(dataType);
   }
 
   @Override
-  public void transform(Row row, PointCollector collector) {
-    int candidateValue = row.getInt(0);
-    if (time == null || value < candidateValue) {
-      time = row.getTime();
-      value = candidateValue;
+  public void transform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException {
+    long time = row.getTime();
+    switch (dataType) {
+      case INT32:
+        collector.putInt(time, Math.abs(row.getInt(0)));
+        break;
+      case INT64:
+        collector.putLong(time, Math.abs(row.getLong(0)));
+        break;
+      case FLOAT:
+        collector.putFloat(time, Math.abs(row.getFloat(0)));
+        break;
+      case DOUBLE:
+        collector.putDouble(time, Math.abs(row.getDouble(0)));
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE);
     }
   }
 
-  @Override
-  public void terminate(PointCollector collector) throws IOException {
-    if (time != null) {
-      collector.putInt(time, value);
-    }
-  }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Max#beforeDestroy");
+  protected void setTransformer() {
+    throw new UnsupportedOperationException("UDTFAbs#setTransformer()");
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAcos.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAcos.java
index c8bb083..dbcd5b5 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAcos.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFAcos extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::acos;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAsin.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAsin.java
index c8bb083..7e375da 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAsin.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFAsin extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::asin;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAtan.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAtan.java
index c8bb083..8f03ae8 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFAtan.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFAtan extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::atan;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFBottomK.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFBottomK.java
new file mode 100644
index 0000000..3d210b2
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFBottomK.java
@@ -0,0 +1,105 @@
+/*
+ * 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.db.query.udf.builtin;
+
+import java.util.Comparator;
+import java.util.PriorityQueue;
+import org.apache.commons.collections4.ComparatorUtils;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+public class UDTFBottomK extends UDTFSelectK {
+
+  protected void constructPQ() throws UDFInputSeriesDataTypeNotValidException {
+    switch (dataType) {
+      case INT32:
+        intPQ = new PriorityQueue<>(k, Comparator.comparing(o -> -o.right));
+        break;
+      case INT64:
+        longPQ = new PriorityQueue<>(k, Comparator.comparing(o -> -o.right));
+        break;
+      case FLOAT:
+        floatPQ = new PriorityQueue<>(k, Comparator.comparing(o -> -o.right));
+        break;
+      case DOUBLE:
+        doublePQ = new PriorityQueue<>(k, Comparator.comparing(o -> -o.right));
+        break;
+      case TEXT:
+        stringPQ = new PriorityQueue<>(k,
+            ComparatorUtils.reversedComparator(Comparator.comparing(o -> o.right)));
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE, TSDataType.TEXT);
+    }
+  }
+
+  @Override
+  protected void transformInt(long time, int value) {
+    if (intPQ.size() < k) {
+      intPQ.add(new Pair<>(time, value));
+    } else if (value < intPQ.peek().right) {
+      intPQ.poll();
+      intPQ.add(new Pair<>(time, value));
+    }
+  }
+
+  @Override
+  protected void transformLong(long time, long value) {
+    if (longPQ.size() < k) {
+      longPQ.add(new Pair<>(time, value));
+    } else if (value < longPQ.peek().right) {
+      longPQ.poll();
+      longPQ.add(new Pair<>(time, value));
+    }
+  }
+
+  @Override
+  protected void transformFloat(long time, float value) {
+    if (floatPQ.size() < k) {
+      floatPQ.add(new Pair<>(time, value));
+    } else if (value < floatPQ.peek().right) {
+      floatPQ.poll();
+      floatPQ.add(new Pair<>(time, value));
+    }
+  }
+
+  @Override
+  protected void transformDouble(long time, double value) {
+    if (doublePQ.size() < k) {
+      doublePQ.add(new Pair<>(time, value));
+    } else if (value < doublePQ.peek().right) {
+      doublePQ.poll();
+      doublePQ.add(new Pair<>(time, value));
+    }
+  }
+
+  @Override
+  protected void transformString(long time, String value) {
+    if (stringPQ.size() < k) {
+      stringPQ.add(new Pair<>(time, value));
+    } else if (value.compareTo(stringPQ.peek().right) < 0) {
+      stringPQ.poll();
+      stringPQ.add(new Pair<>(time, value));
+    }
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCeil.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCeil.java
index c8bb083..76b49b4 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCeil.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFCeil extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::ceil;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCommonDerivative.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCommonDerivative.java
new file mode 100644
index 0000000..b6425f4
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCommonDerivative.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.db.query.udf.builtin;
+
+import java.io.IOException;
+import org.apache.iotdb.db.query.udf.api.access.Row;
+import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class UDTFCommonDerivative extends UDTFDerivative {
+
+  protected void doTransform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException {
+    long currentTime = row.getTime();
+    double timeDelta = (double) currentTime - previousTime;
+    switch (dataType) {
+      case INT32:
+        int currentInt = row.getInt(0);
+        collector.putDouble(currentTime, (currentInt - previousInt) / timeDelta);
+        previousInt = currentInt;
+        break;
+      case INT64:
+        long currentLong = row.getLong(0);
+        collector.putDouble(currentTime, (currentLong - previousLong) / timeDelta);
+        previousLong = currentLong;
+        break;
+      case FLOAT:
+        float currentFloat = row.getFloat(0);
+        collector.putDouble(currentTime, (currentFloat - previousFloat) / timeDelta);
+        previousFloat = currentFloat;
+        break;
+      case DOUBLE:
+        double currentDouble = row.getDouble(0);
+        collector.putDouble(currentTime, (currentDouble - previousDouble) / timeDelta);
+        previousDouble = currentDouble;
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE);
+    }
+    previousTime = currentTime;
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCommonValueDifference.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCommonValueDifference.java
new file mode 100644
index 0000000..88f044e
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCommonValueDifference.java
@@ -0,0 +1,60 @@
+/*
+ * 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.db.query.udf.builtin;
+
+import java.io.IOException;
+import org.apache.iotdb.db.query.udf.api.access.Row;
+import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class UDTFCommonValueDifference extends UDTFValueDifference {
+
+  protected void doTransform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException {
+    long time = row.getTime();
+    switch (dataType) {
+      case INT32:
+        int currentInt = row.getInt(0);
+        collector.putInt(time, currentInt - previousInt);
+        previousInt = currentInt;
+        break;
+      case INT64:
+        long currentLong = row.getLong(0);
+        collector.putLong(time, currentLong - previousLong);
+        previousLong = currentLong;
+        break;
+      case FLOAT:
+        float currentFloat = row.getFloat(0);
+        collector.putFloat(time, currentFloat - previousFloat);
+        previousFloat = currentFloat;
+        break;
+      case DOUBLE:
+        double currentDouble = row.getDouble(0);
+        collector.putDouble(time, currentDouble - previousDouble);
+        previousDouble = currentDouble;
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE);
+    }
+  }
+}
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFContains.java
similarity index 69%
copy from server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFContains.java
index 75b9e21..09ee073 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFContains.java
@@ -1,62 +1,56 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.iotdb.db.query.udf.example;
-
-import org.apache.iotdb.db.query.udf.api.UDTF;
-import org.apache.iotdb.db.query.udf.api.access.Row;
-import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
-import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
-import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
-import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
-import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-
-public class Multiplier implements UDTF {
-
-  private long a;
-  private long b;
-
-  @Override
-  public void validate(UDFParameterValidator validator) throws Exception {
-    validator
-        .validateInputSeriesNumber(1)
-        .validateInputSeriesDataType(0, TSDataType.INT64);
-  }
-
-  @Override
-  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Multiplier#beforeStart");
-    a = parameters.getLongOrDefault("a", 0);
-    b = parameters.getLongOrDefault("b", 0);
-    configurations
-        .setOutputDataType(TSDataType.INT64)
-        .setAccessStrategy(new RowByRowAccessStrategy());
-  }
-
-  @Override
-  public void transform(Row row, PointCollector collector) throws Exception {
-    collector.putLong(row.getTime(), row.getLong(0) * a * b);
-  }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Multiplier#beforeDestroy");
-  }
-}
+/*
+ * 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.db.query.udf.builtin;
+
+import org.apache.iotdb.db.query.udf.api.UDTF;
+import org.apache.iotdb.db.query.udf.api.access.Row;
+import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
+import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
+import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
+import org.apache.iotdb.db.query.udf.api.exception.UDFException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class UDTFContains implements UDTF {
+
+  private String s;
+
+  @Override
+  public void validate(UDFParameterValidator validator) throws UDFException {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateRequiredAttribute("s")
+        .validateInputSeriesDataType(0, TSDataType.TEXT);
+  }
+
+  @Override
+  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
+    s = parameters.getString("s");
+    configurations
+        .setAccessStrategy(new RowByRowAccessStrategy())
+        .setOutputDataType(TSDataType.BOOLEAN);
+  }
+
+  @Override
+  public void transform(Row row, PointCollector collector) throws Exception {
+    collector.putBoolean(row.getTime(), row.getString(0).contains(s));
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCos.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCos.java
index c8bb083..0bfe245 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFCos.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFCos extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::cos;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFDegrees.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFDegrees.java
index c8bb083..712278a 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFDegrees.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFDegrees extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::toDegrees;
   }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFDerivative.java
similarity index 62%
copy from server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFDerivative.java
index d5d797f..71f888b 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFDerivative.java
@@ -17,48 +17,41 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.query.udf.example;
+package org.apache.iotdb.db.query.udf.builtin;
 
-import org.apache.iotdb.db.query.udf.api.UDTF;
+import java.io.IOException;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 
-public class TerminateTester implements UDTF {
+public abstract class UDTFDerivative extends UDTFValueTrend {
 
-  private Long maxTime;
-  private int count;
+  protected long previousTime;
 
   @Override
-  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("TerminateTester#beforeStart");
+  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations)
+      throws MetadataException {
+    dataType = parameters.getDataType(0);
     configurations
-        .setOutputDataType(TSDataType.INT32)
-        .setAccessStrategy(new RowByRowAccessStrategy());
-    maxTime = null;
-    count = 0;
+        .setAccessStrategy(new RowByRowAccessStrategy())
+        .setOutputDataType(TSDataType.DOUBLE);
   }
 
   @Override
-  public void transform(Row row, PointCollector collector) throws Exception {
-    maxTime = row.getTime();
-    ++count;
-
-    collector.putInt(maxTime, 1);
-  }
-
-  @Override
-  public void terminate(PointCollector collector) throws Exception {
-    if (maxTime != null) {
-      collector.putInt(maxTime + 1, count);
+  public void transform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException {
+    if (!hasPrevious) {
+      previousTime = row.getTime();
+      updatePreviousValue(row);
+      hasPrevious = true;
+      return;
     }
-  }
 
-  @Override
-  public void beforeDestroy() {
-    System.out.println("TerminateTester#beforeDestroy");
+    doTransform(row, collector);
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFExp.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFExp.java
index c8bb083..e0e16ef 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFExp.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFExp extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::exp;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFFloor.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFFloor.java
index c8bb083..92b6063 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFFloor.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFFloor extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::floor;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFLog.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFLog.java
index c8bb083..b968893 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFLog.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFLog extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::log;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFLog10.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFLog10.java
index c8bb083..80d3546 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFLog10.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFLog10 extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::log10;
   }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFMatches.java
similarity index 69%
copy from server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFMatches.java
index 75b9e21..0c47408 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFMatches.java
@@ -1,62 +1,57 @@
-/*
- * 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.db.query.udf.example;
-
-import org.apache.iotdb.db.query.udf.api.UDTF;
-import org.apache.iotdb.db.query.udf.api.access.Row;
-import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
-import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
-import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
-import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
-import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-
-public class Multiplier implements UDTF {
-
-  private long a;
-  private long b;
-
-  @Override
-  public void validate(UDFParameterValidator validator) throws Exception {
-    validator
-        .validateInputSeriesNumber(1)
-        .validateInputSeriesDataType(0, TSDataType.INT64);
-  }
-
-  @Override
-  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Multiplier#beforeStart");
-    a = parameters.getLongOrDefault("a", 0);
-    b = parameters.getLongOrDefault("b", 0);
-    configurations
-        .setOutputDataType(TSDataType.INT64)
-        .setAccessStrategy(new RowByRowAccessStrategy());
-  }
-
-  @Override
-  public void transform(Row row, PointCollector collector) throws Exception {
-    collector.putLong(row.getTime(), row.getLong(0) * a * b);
-  }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Multiplier#beforeDestroy");
-  }
-}
+/*
+ * 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.db.query.udf.builtin;
+
+import java.util.regex.Pattern;
+import org.apache.iotdb.db.query.udf.api.UDTF;
+import org.apache.iotdb.db.query.udf.api.access.Row;
+import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
+import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
+import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
+import org.apache.iotdb.db.query.udf.api.exception.UDFException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class UDTFMatches implements UDTF {
+
+  private Pattern pattern;
+
+  @Override
+  public void validate(UDFParameterValidator validator) throws UDFException {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateRequiredAttribute("regex")
+        .validateInputSeriesDataType(0, TSDataType.TEXT);
+  }
+
+  @Override
+  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
+    pattern = Pattern.compile(parameters.getString("regex"));
+    configurations
+        .setAccessStrategy(new RowByRowAccessStrategy())
+        .setOutputDataType(TSDataType.BOOLEAN);
+  }
+
+  @Override
+  public void transform(Row row, PointCollector collector) throws Exception {
+    collector.putBoolean(row.getTime(), pattern.matcher(row.getString(0)).matches());
+  }
+}
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFMath.java
similarity index 53%
copy from server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFMath.java
index 4b46425..ac5b5ed 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFMath.java
@@ -1,89 +1,89 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.iotdb.db.query.udf.example;
-
-import org.apache.iotdb.db.query.udf.api.UDTF;
-import org.apache.iotdb.db.query.udf.api.access.Row;
-import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
-import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
-import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
-import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
-import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
-import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-
-public class Adder implements UDTF {
-
-  private double addend;
-
-  @Override
-  public void validate(UDFParameterValidator validator) throws Exception {
-    validator
-        .validateInputSeriesNumber(2)
-        .validateInputSeriesDataType(0, TSDataType.INT32, TSDataType.INT64, TSDataType.FLOAT,
-            TSDataType.DOUBLE)
-        .validateInputSeriesDataType(1, TSDataType.INT32, TSDataType.INT64, TSDataType.FLOAT,
-            TSDataType.DOUBLE);
-  }
-
-  @Override
-  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Adder#beforeStart");
-    addend = parameters.getFloatOrDefault("addend", 0);
-    configurations
-        .setOutputDataType(TSDataType.INT64)
-        .setAccessStrategy(new RowByRowAccessStrategy());
-  }
-
-  @Override
-  public void transform(Row row, PointCollector collector) throws Exception {
-    if (row.isNull(0) || row.isNull(1)) {
-      return;
-    }
-    collector.putLong(row.getTime(),
-        (long) (extractDoubleValue(row, 0) + extractDoubleValue(row, 1) + addend));
-  }
-
-  private double extractDoubleValue(Row row, int index) {
-    double value;
-    switch (row.getDataType(index)) {
-      case INT32:
-        value = row.getInt(index);
-        break;
-      case INT64:
-        value = (double) row.getLong(index);
-        break;
-      case FLOAT:
-        value = row.getFloat(index);
-        break;
-      case DOUBLE:
-        value = row.getDouble(index);
-        break;
-      default:
-        throw new UnSupportedDataTypeException(row.getDataType(index).toString());
-    }
-    return value;
-  }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Adder#beforeDestroy");
-  }
-}
+/*
+ * 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.db.query.udf.builtin;
+
+import java.io.IOException;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.query.udf.api.UDTF;
+import org.apache.iotdb.db.query.udf.api.access.Row;
+import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
+import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
+import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
+import org.apache.iotdb.db.query.udf.api.exception.UDFException;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public abstract class UDTFMath implements UDTF {
+
+  protected interface Transformer {
+
+    double transform(double operand);
+  }
+
+  protected Transformer transformer;
+
+  protected TSDataType dataType;
+
+  @Override
+  public void validate(UDFParameterValidator validator) throws UDFException {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateInputSeriesDataType(0, TSDataType.INT32, TSDataType.INT64, TSDataType.FLOAT,
+            TSDataType.DOUBLE);
+  }
+
+  @Override
+  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations)
+      throws MetadataException {
+    dataType = parameters.getDataType(0);
+    configurations
+        .setAccessStrategy(new RowByRowAccessStrategy())
+        .setOutputDataType(TSDataType.DOUBLE);
+    setTransformer();
+  }
+
+  protected abstract void setTransformer();
+
+  @Override
+  public void transform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException {
+    long time = row.getTime();
+    switch (dataType) {
+      case INT32:
+        collector.putDouble(time, transformer.transform(row.getInt(0)));
+        break;
+      case INT64:
+        collector.putDouble(time, transformer.transform(row.getLong(0)));
+        break;
+      case FLOAT:
+        collector.putDouble(time, transformer.transform(row.getFloat(0)));
+        break;
+      case DOUBLE:
+        collector.putDouble(time, transformer.transform(row.getDouble(0)));
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE);
+    }
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFNonNegativeDerivative.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFNonNegativeDerivative.java
new file mode 100644
index 0000000..f78adeb
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFNonNegativeDerivative.java
@@ -0,0 +1,63 @@
+/*
+ * 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.db.query.udf.builtin;
+
+import java.io.IOException;
+import org.apache.iotdb.db.query.udf.api.access.Row;
+import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class UDTFNonNegativeDerivative extends UDTFDerivative {
+
+  @Override
+  protected void doTransform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException {
+    long currentTime = row.getTime();
+    double timeDelta = (double) currentTime - previousTime;
+    switch (dataType) {
+      case INT32:
+        int currentInt = row.getInt(0);
+        collector.putDouble(currentTime, Math.abs(currentInt - previousInt) / timeDelta);
+        previousInt = currentInt;
+        break;
+      case INT64:
+        long currentLong = row.getLong(0);
+        collector.putDouble(currentTime, Math.abs(currentLong - previousLong) / timeDelta);
+        previousLong = currentLong;
+        break;
+      case FLOAT:
+        float currentFloat = row.getFloat(0);
+        collector.putDouble(currentTime, Math.abs(currentFloat - previousFloat) / timeDelta);
+        previousFloat = currentFloat;
+        break;
+      case DOUBLE:
+        double currentDouble = row.getDouble(0);
+        collector.putDouble(currentTime, Math.abs(currentDouble - previousDouble) / timeDelta);
+        previousDouble = currentDouble;
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE);
+    }
+    previousTime = currentTime;
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFNonNegativeValueDifference.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFNonNegativeValueDifference.java
new file mode 100644
index 0000000..8b1ec5c
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFNonNegativeValueDifference.java
@@ -0,0 +1,61 @@
+/*
+ * 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.db.query.udf.builtin;
+
+import java.io.IOException;
+import org.apache.iotdb.db.query.udf.api.access.Row;
+import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class UDTFNonNegativeValueDifference extends UDTFValueDifference {
+
+  @Override
+  protected void doTransform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException {
+    long time = row.getTime();
+    switch (dataType) {
+      case INT32:
+        int currentInt = row.getInt(0);
+        collector.putInt(time, Math.abs(currentInt - previousInt));
+        previousInt = currentInt;
+        break;
+      case INT64:
+        long currentLong = row.getLong(0);
+        collector.putLong(time, Math.abs(currentLong - previousLong));
+        previousLong = currentLong;
+        break;
+      case FLOAT:
+        float currentFloat = row.getFloat(0);
+        collector.putFloat(time, Math.abs(currentFloat - previousFloat));
+        previousFloat = currentFloat;
+        break;
+      case DOUBLE:
+        double currentDouble = row.getDouble(0);
+        collector.putDouble(time, Math.abs(currentDouble - previousDouble));
+        previousDouble = currentDouble;
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE);
+    }
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFRadians.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFRadians.java
index c8bb083..150ad0e 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFRadians.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFRadians extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::toRadians;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFRound.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFRound.java
index c8bb083..6587f2a 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFRound.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFRound extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::rint;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSelectK.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSelectK.java
new file mode 100644
index 0000000..1024710
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSelectK.java
@@ -0,0 +1,156 @@
+/*
+ * 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.db.query.udf.builtin;
+
+import java.io.IOException;
+import java.util.Comparator;
+import java.util.PriorityQueue;
+import java.util.stream.Collectors;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.query.udf.api.UDTF;
+import org.apache.iotdb.db.query.udf.api.access.Row;
+import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
+import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
+import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
+import org.apache.iotdb.db.query.udf.api.exception.UDFException;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+public abstract class UDTFSelectK implements UDTF {
+
+  protected int k;
+  protected TSDataType dataType;
+  protected PriorityQueue<Pair<Long, Integer>> intPQ;
+  protected PriorityQueue<Pair<Long, Long>> longPQ;
+  protected PriorityQueue<Pair<Long, Float>> floatPQ;
+  protected PriorityQueue<Pair<Long, Double>> doublePQ;
+  protected PriorityQueue<Pair<Long, String>> stringPQ;
+
+  @Override
+  public void validate(UDFParameterValidator validator) throws UDFException {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateInputSeriesDataType(0, TSDataType.INT32, TSDataType.INT64, TSDataType.FLOAT,
+            TSDataType.DOUBLE, TSDataType.TEXT)
+        .validateRequiredAttribute("k")
+        .validate(k -> 0 < (int) k && (int) k <= 1000,
+            "k has to be greater than 0 and less than or equal to 1000.",
+            validator.getParameters().getInt("k"));
+  }
+
+  @Override
+  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations)
+      throws MetadataException, UDFInputSeriesDataTypeNotValidException {
+    k = parameters.getInt("k");
+    dataType = parameters.getDataType(0);
+    constructPQ();
+    configurations
+        .setAccessStrategy(new RowByRowAccessStrategy())
+        .setOutputDataType(dataType);
+  }
+
+  protected abstract void constructPQ() throws UDFInputSeriesDataTypeNotValidException;
+
+  @Override
+  public void transform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException {
+    switch (dataType) {
+      case INT32:
+        transformInt(row.getTime(), row.getInt(0));
+        break;
+      case INT64:
+        transformLong(row.getTime(), row.getLong(0));
+        break;
+      case FLOAT:
+        transformFloat(row.getTime(), row.getFloat(0));
+        break;
+      case DOUBLE:
+        transformDouble(row.getTime(), row.getDouble(0));
+        break;
+      case TEXT:
+        transformString(row.getTime(), row.getString(0));
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE, TSDataType.TEXT);
+    }
+  }
+
+  protected abstract void transformInt(long time, int value);
+
+  protected abstract void transformLong(long time, long value);
+
+  protected abstract void transformFloat(long time, float value);
+
+  protected abstract void transformDouble(long time, double value);
+
+  protected abstract void transformString(long time, String value);
+
+  @Override
+  public void terminate(PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException, QueryProcessException {
+    switch (dataType) {
+      case INT32:
+        for (Pair<Long, Integer> pair : intPQ.stream()
+            .sorted(Comparator.comparing(p -> p.left))
+            .collect(Collectors.toList())) {
+          collector.putInt(pair.left, pair.right);
+        }
+        break;
+      case INT64:
+        for (Pair<Long, Long> pair : longPQ.stream()
+            .sorted(Comparator.comparing(p -> p.left))
+            .collect(Collectors.toList())) {
+          collector.putLong(pair.left, pair.right);
+        }
+        break;
+      case FLOAT:
+        for (Pair<Long, Float> pair : floatPQ.stream()
+            .sorted(Comparator.comparing(p -> p.left))
+            .collect(Collectors.toList())) {
+          collector.putFloat(pair.left, pair.right);
+        }
+        break;
+      case DOUBLE:
+        for (Pair<Long, Double> pair : doublePQ.stream()
+            .sorted(Comparator.comparing(p -> p.left))
+            .collect(Collectors.toList())) {
+          collector.putDouble(pair.left, pair.right);
+        }
+        break;
+      case TEXT:
+        for (Pair<Long, String> pair : stringPQ.stream()
+            .sorted(Comparator.comparing(p -> p.left))
+            .collect(Collectors.toList())) {
+          collector.putString(pair.left, pair.right);
+        }
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE, TSDataType.TEXT);
+    }
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSign.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSign.java
index c8bb083..ea93186 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSign.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFSign extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::signum;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSin.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSin.java
index c8bb083..882daac 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSin.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFSin extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::sin;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSqrt.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSqrt.java
index c8bb083..c246f62 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFSqrt.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFSqrt extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::sqrt;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFTan.java
similarity index 65%
copy from server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFTan.java
index c8bb083..b5f5bf9 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/BuiltinFunction.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFTan.java
@@ -19,25 +19,10 @@
 
 package org.apache.iotdb.db.query.udf.builtin;
 
-/**
- * All built-in UDFs need to register function names and full class names here.
- */
-public enum BuiltinFunction {
-  ;
-
-  private final String functionName;
-  private final String className;
-
-  BuiltinFunction(String functionName, String className) {
-    this.functionName = functionName;
-    this.className = className;
-  }
-
-  public String getFunctionName() {
-    return functionName;
-  }
+public class UDTFTan extends UDTFMath {
 
-  public String getClassName() {
-    return className;
+  @Override
+  protected void setTransformer() {
+    transformer = Math::tan;
   }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFTimeDifference.java
similarity index 68%
copy from server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFTimeDifference.java
index d5d797f..fd128f0 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFTimeDifference.java
@@ -17,8 +17,9 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.query.udf.example;
+package org.apache.iotdb.db.query.udf.builtin;
 
+import java.io.IOException;
 import org.apache.iotdb.db.query.udf.api.UDTF;
 import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
@@ -27,38 +28,29 @@ import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 
-public class TerminateTester implements UDTF {
+public class UDTFTimeDifference implements UDTF {
 
-  private Long maxTime;
-  private int count;
+  private boolean hasPrevious = false;
+
+  private long previousTime = 0;
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("TerminateTester#beforeStart");
     configurations
-        .setOutputDataType(TSDataType.INT32)
-        .setAccessStrategy(new RowByRowAccessStrategy());
-    maxTime = null;
-    count = 0;
+        .setAccessStrategy(new RowByRowAccessStrategy())
+        .setOutputDataType(TSDataType.INT64);
   }
 
   @Override
-  public void transform(Row row, PointCollector collector) throws Exception {
-    maxTime = row.getTime();
-    ++count;
-
-    collector.putInt(maxTime, 1);
-  }
-
-  @Override
-  public void terminate(PointCollector collector) throws Exception {
-    if (maxTime != null) {
-      collector.putInt(maxTime + 1, count);
+  public void transform(Row row, PointCollector collector) throws IOException {
+    if (!hasPrevious) {
+      previousTime = row.getTime();
+      hasPrevious = true;
+      return;
     }
-  }
 
-  @Override
-  public void beforeDestroy() {
-    System.out.println("TerminateTester#beforeDestroy");
+    long currentTime = row.getTime();
+    collector.putLong(currentTime, currentTime - previousTime);
+    previousTime = currentTime;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFTopK.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFTopK.java
new file mode 100644
index 0000000..8a61d9d
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFTopK.java
@@ -0,0 +1,103 @@
+/*
+ * 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.db.query.udf.builtin;
+
+import java.util.Comparator;
+import java.util.PriorityQueue;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+public class UDTFTopK extends UDTFSelectK {
+
+  protected void constructPQ() throws UDFInputSeriesDataTypeNotValidException {
+    switch (dataType) {
+      case INT32:
+        intPQ = new PriorityQueue<>(k, Comparator.comparing(o -> o.right));
+        break;
+      case INT64:
+        longPQ = new PriorityQueue<>(k, Comparator.comparing(o -> o.right));
+        break;
+      case FLOAT:
+        floatPQ = new PriorityQueue<>(k, Comparator.comparing(o -> o.right));
+        break;
+      case DOUBLE:
+        doublePQ = new PriorityQueue<>(k, Comparator.comparing(o -> o.right));
+        break;
+      case TEXT:
+        stringPQ = new PriorityQueue<>(k, Comparator.comparing(o -> o.right));
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE, TSDataType.TEXT);
+    }
+  }
+
+  @Override
+  protected void transformInt(long time, int value) {
+    if (intPQ.size() < k) {
+      intPQ.add(new Pair<>(time, value));
+    } else if (intPQ.peek().right < value) {
+      intPQ.poll();
+      intPQ.add(new Pair<>(time, value));
+    }
+  }
+
+  @Override
+  protected void transformLong(long time, long value) {
+    if (longPQ.size() < k) {
+      longPQ.add(new Pair<>(time, value));
+    } else if (longPQ.peek().right < value) {
+      longPQ.poll();
+      longPQ.add(new Pair<>(time, value));
+    }
+  }
+
+  @Override
+  protected void transformFloat(long time, float value) {
+    if (floatPQ.size() < k) {
+      floatPQ.add(new Pair<>(time, value));
+    } else if (floatPQ.peek().right < value) {
+      floatPQ.poll();
+      floatPQ.add(new Pair<>(time, value));
+    }
+  }
+
+  @Override
+  protected void transformDouble(long time, double value) {
+    if (doublePQ.size() < k) {
+      doublePQ.add(new Pair<>(time, value));
+    } else if (doublePQ.peek().right < value) {
+      doublePQ.poll();
+      doublePQ.add(new Pair<>(time, value));
+    }
+  }
+
+  @Override
+  protected void transformString(long time, String value) {
+    if (stringPQ.size() < k) {
+      stringPQ.add(new Pair<>(time, value));
+    } else if (stringPQ.peek().right.compareTo(value) < 0) {
+      stringPQ.poll();
+      stringPQ.add(new Pair<>(time, value));
+    }
+  }
+}
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFValueDifference.java
similarity index 59%
copy from server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java
copy to server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFValueDifference.java
index d5d797f..cc3cb5e 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFValueDifference.java
@@ -17,48 +17,37 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.query.udf.example;
+package org.apache.iotdb.db.query.udf.builtin;
 
-import org.apache.iotdb.db.query.udf.api.UDTF;
+import java.io.IOException;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.query.udf.api.access.Row;
 import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
 import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations;
 import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters;
 import org.apache.iotdb.db.query.udf.api.customizer.strategy.RowByRowAccessStrategy;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
 
-public class TerminateTester implements UDTF {
-
-  private Long maxTime;
-  private int count;
+public abstract class UDTFValueDifference extends UDTFValueTrend {
 
   @Override
-  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("TerminateTester#beforeStart");
+  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations)
+      throws MetadataException {
+    dataType = parameters.getDataType(0);
     configurations
-        .setOutputDataType(TSDataType.INT32)
-        .setAccessStrategy(new RowByRowAccessStrategy());
-    maxTime = null;
-    count = 0;
+        .setAccessStrategy(new RowByRowAccessStrategy())
+        .setOutputDataType(dataType);
   }
 
   @Override
-  public void transform(Row row, PointCollector collector) throws Exception {
-    maxTime = row.getTime();
-    ++count;
-
-    collector.putInt(maxTime, 1);
-  }
-
-  @Override
-  public void terminate(PointCollector collector) throws Exception {
-    if (maxTime != null) {
-      collector.putInt(maxTime + 1, count);
+  public void transform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException {
+    if (!hasPrevious) {
+      updatePreviousValue(row);
+      hasPrevious = true;
+      return;
     }
-  }
 
-  @Override
-  public void beforeDestroy() {
-    System.out.println("TerminateTester#beforeDestroy");
+    doTransform(row, collector);
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFValueTrend.java b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFValueTrend.java
new file mode 100644
index 0000000..f2af796
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/builtin/UDTFValueTrend.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.query.udf.builtin;
+
+import java.io.IOException;
+import org.apache.iotdb.db.query.udf.api.UDTF;
+import org.apache.iotdb.db.query.udf.api.access.Row;
+import org.apache.iotdb.db.query.udf.api.collector.PointCollector;
+import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator;
+import org.apache.iotdb.db.query.udf.api.exception.UDFException;
+import org.apache.iotdb.db.query.udf.api.exception.UDFInputSeriesDataTypeNotValidException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public abstract class UDTFValueTrend implements UDTF {
+
+  protected boolean hasPrevious = false;
+
+  protected int previousInt = 0;
+  protected long previousLong = 0;
+  protected float previousFloat = 0;
+  protected double previousDouble = 0;
+
+  protected TSDataType dataType;
+
+  @Override
+  public void validate(UDFParameterValidator validator) throws UDFException {
+    validator
+        .validateInputSeriesNumber(1)
+        .validateInputSeriesDataType(0, TSDataType.INT32, TSDataType.INT64, TSDataType.FLOAT,
+            TSDataType.DOUBLE);
+  }
+
+  protected void updatePreviousValue(Row row) throws UDFInputSeriesDataTypeNotValidException {
+    switch (dataType) {
+      case INT32:
+        previousInt = row.getInt(0);
+        break;
+      case INT64:
+        previousLong = row.getLong(0);
+        break;
+      case FLOAT:
+        previousFloat = row.getFloat(0);
+        break;
+      case DOUBLE:
+        previousDouble = row.getDouble(0);
+        break;
+      default:
+        // This will not happen.
+        throw new UDFInputSeriesDataTypeNotValidException(0, dataType, TSDataType.INT32,
+            TSDataType.INT64, TSDataType.FLOAT, TSDataType.DOUBLE);
+    }
+  }
+
+  protected abstract void doTransform(Row row, PointCollector collector)
+      throws UDFInputSeriesDataTypeNotValidException, IOException;
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/service/UDFRegistrationService.java b/server/src/main/java/org/apache/iotdb/db/query/udf/service/UDFRegistrationService.java
index 62e82ec..5e603a1 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/udf/service/UDFRegistrationService.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/udf/service/UDFRegistrationService.java
@@ -78,6 +78,7 @@ public class UDFRegistrationService implements IService {
 
   public void register(String functionName, String className, boolean isTemporary,
       boolean writeToTemporaryLogFile) throws UDFRegistrationException {
+    functionName = functionName.toUpperCase();
     validateFunctionName(functionName, className);
     checkIfRegistered(functionName, className, isTemporary);
     doRegister(functionName, className, isTemporary);
@@ -181,6 +182,7 @@ public class UDFRegistrationService implements IService {
   }
 
   public void deregister(String functionName) throws UDFRegistrationException {
+    functionName = functionName.toUpperCase();
     UDFRegistrationInformation information = registrationInformation.remove(functionName);
     if (information == null) {
       String errorMessage = String.format("UDF %s does not exist.", functionName);
@@ -228,11 +230,12 @@ public class UDFRegistrationService implements IService {
   }
 
   public UDF reflect(UDFContext context) throws QueryProcessException {
-    UDFRegistrationInformation information = registrationInformation.get(context.getName());
+    String functionName = context.getName().toUpperCase();
+    UDFRegistrationInformation information = registrationInformation.get(functionName);
     if (information == null) {
       String errorMessage = String
           .format("Failed to reflect UDF instance, because UDF %s has not been registered.",
-              context.getName());
+              functionName);
       logger.warn(errorMessage);
       throw new QueryProcessException(errorMessage);
     }
@@ -246,7 +249,7 @@ public class UDFRegistrationService implements IService {
       return (UDF) information.getFunctionClass().getDeclaredConstructor().newInstance();
     } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
       String errorMessage = String.format("Failed to reflect UDF %s(%s) instance, because %s",
-          context.getName(), information.getClassName(), e.toString());
+          functionName, information.getClassName(), e.toString());
       logger.warn(errorMessage);
       throw new QueryProcessException(errorMessage);
     }
@@ -268,14 +271,12 @@ public class UDFRegistrationService implements IService {
     }
   }
 
-  private void registerBuiltinFunctions() throws ClassNotFoundException {
-    ClassLoader classLoader = getClass().getClassLoader();
+  private void registerBuiltinFunctions() {
     for (BuiltinFunction builtinFunction : BuiltinFunction.values()) {
       String functionName = builtinFunction.getFunctionName();
-      String className = builtinFunction.getClassName();
-      Class<?> functionClass = Class.forName(className, true, classLoader);
       registrationInformation.put(functionName,
-          new UDFRegistrationInformation(functionName, className, false, true, functionClass));
+          new UDFRegistrationInformation(functionName, builtinFunction.getClassName(), false, true,
+              builtinFunction.getFunctionClass()));
     }
   }
 
@@ -370,13 +371,14 @@ public class UDFRegistrationService implements IService {
       throws ClassNotFoundException {
     ClassLoader classLoader = getClass().getClassLoader();
     Class<?> functionClass = Class.forName(className, true, classLoader);
+    functionName = functionName.toUpperCase();
     registrationInformation.put(functionName,
         new UDFRegistrationInformation(functionName, className, false, true, functionClass));
   }
 
   @TestOnly
   public void deregisterBuiltinFunction(String functionName) {
-    registrationInformation.remove(functionName);
+    registrationInformation.remove(functionName.toUpperCase());
   }
 
   @Override
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDFManagementIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDFManagementIT.java
index 14923bb..bec06ed 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDFManagementIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDFManagementIT.java
@@ -33,6 +33,7 @@ import java.sql.SQLException;
 import java.sql.Statement;
 import org.apache.iotdb.db.metadata.PartialPath;
 import org.apache.iotdb.db.qp.constant.SQLConstant;
+import org.apache.iotdb.db.query.udf.builtin.BuiltinFunction;
 import org.apache.iotdb.db.query.udf.service.UDFRegistrationService;
 import org.apache.iotdb.db.service.IoTDB;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
@@ -48,6 +49,7 @@ import org.junit.Test;
 public class IoTDBUDFManagementIT {
 
   private static final int NATIVE_FUNCTIONS_COUNT = SQLConstant.getNativeFunctionNames().size();
+  private static final int BUILTIN_FUNCTIONS_COUNT = BuiltinFunction.values().length;
 
   @Before
   public void setUp() throws Exception {
@@ -87,12 +89,9 @@ public class IoTDBUDFManagementIT {
         if (result.contains(FUNCTION_TYPE_NATIVE)) {
           continue;
         }
-
-        Assert.assertEquals(String.format("udf,%s,org.apache.iotdb.db.query.udf.example.Adder,",
-            FUNCTION_TYPE_EXTERNAL_UDTF), result);
         ++count;
       }
-      Assert.assertEquals(1, count);
+      Assert.assertEquals(1 + BUILTIN_FUNCTIONS_COUNT, count);
 
       resultSet = statement.executeQuery("show temporary functions");
       count = 0;
@@ -122,7 +121,7 @@ public class IoTDBUDFManagementIT {
       while (resultSet.next()) {
         ++count;
       }
-      Assert.assertEquals(1 + NATIVE_FUNCTIONS_COUNT, count);
+      Assert.assertEquals(1 + NATIVE_FUNCTIONS_COUNT + BUILTIN_FUNCTIONS_COUNT, count);
       assertEquals(3, resultSet.getMetaData().getColumnCount());
 
       resultSet = statement.executeQuery("show temporary functions");
@@ -143,7 +142,7 @@ public class IoTDBUDFManagementIT {
       while (resultSet.next()) {
         ++count;
       }
-      Assert.assertEquals(1 + NATIVE_FUNCTIONS_COUNT, count);
+      Assert.assertEquals(1 + NATIVE_FUNCTIONS_COUNT + BUILTIN_FUNCTIONS_COUNT, count);
       assertEquals(3, resultSet.getMetaData().getColumnCount());
 
       resultSet = statement.executeQuery("show temporary functions");
@@ -163,7 +162,7 @@ public class IoTDBUDFManagementIT {
       while (resultSet.next()) {
         ++count;
       }
-      Assert.assertEquals(1 + NATIVE_FUNCTIONS_COUNT, count);
+      Assert.assertEquals(1 + NATIVE_FUNCTIONS_COUNT + BUILTIN_FUNCTIONS_COUNT, count);
       assertEquals(3, resultSet.getMetaData().getColumnCount());
 
       resultSet = statement.executeQuery("show temporary functions");
@@ -363,7 +362,7 @@ public class IoTDBUDFManagementIT {
     } catch (SQLException throwable) {
       throwable.printStackTrace();
       assertTrue(
-          throwable.getMessage().contains("Built-in function adder can not be deregistered"));
+          throwable.getMessage().contains("Built-in function ADDER can not be deregistered"));
     } finally {
       UDFRegistrationService.getInstance().deregisterBuiltinFunction("adder");
     }
@@ -408,16 +407,14 @@ public class IoTDBUDFManagementIT {
         }
 
         if (result.contains(FUNCTION_TYPE_EXTERNAL_UDTF)) {
-          Assert.assertEquals(String.format("udf,%s,org.apache.iotdb.db.query.udf.example.Adder,",
+          Assert.assertEquals(String.format("UDF,%s,org.apache.iotdb.db.query.udf.example.Adder,",
               FUNCTION_TYPE_EXTERNAL_UDTF), result);
           ++count;
         } else if (result.contains(FUNCTION_TYPE_BUILTIN_UDTF)) {
-          Assert.assertEquals(String.format("adder,%s,org.apache.iotdb.db.query.udf.example.Adder,",
-              FUNCTION_TYPE_BUILTIN_UDTF), result);
           ++count;
         }
       }
-      Assert.assertEquals(2, count);
+      Assert.assertEquals(2 + BUILTIN_FUNCTIONS_COUNT, count);
 
       resultSet = statement.executeQuery("show temporary functions");
       count = 0;
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFBuiltinFunctionIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFBuiltinFunctionIT.java
new file mode 100644
index 0000000..d1160c3
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFBuiltinFunctionIT.java
@@ -0,0 +1,250 @@
+/*
+ * 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.db.integration;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.service.IoTDB;
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.jdbc.Config;
+import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class IoTDBUDTFBuiltinFunctionIT {
+
+  private static final double E = 0.0001;
+
+  private final static String[] INSERTION_SQLS = {
+      "insert into root.sg.d1(time, s1, s2, s3, s4, s5, s6) values (0, 0, 0, 0, 0, true, '0')",
+      "insert into root.sg.d1(time, s1, s2, s3, s4, s5, s6) values (2, 1, 1, 1, 1, false, '1')",
+      "insert into root.sg.d1(time, s1, s2, s3, s4, s5, s6) values (4, 2, 2, 2, 2, false, '2')",
+      "insert into root.sg.d1(time, s1, s2, s3, s4, s5, s6) values (6, 3, 3, 3, 3, true, '3')",
+      "insert into root.sg.d1(time, s1, s2, s3, s4, s5, s6) values (8, 4, 4, 4, 4, true, '4')",
+  };
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvironmentUtils.envSetUp();
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    createTimeSeries();
+    generateData();
+  }
+
+  private static void createTimeSeries() throws MetadataException {
+    IoTDB.metaManager.setStorageGroup(new PartialPath("root.sg"));
+    IoTDB.metaManager
+        .createTimeseries(new PartialPath("root.sg.d1.s1"), TSDataType.INT32, TSEncoding.PLAIN,
+            CompressionType.UNCOMPRESSED, null);
+    IoTDB.metaManager
+        .createTimeseries(new PartialPath("root.sg.d1.s2"), TSDataType.INT64, TSEncoding.PLAIN,
+            CompressionType.UNCOMPRESSED, null);
+    IoTDB.metaManager
+        .createTimeseries(new PartialPath("root.sg.d1.s3"), TSDataType.FLOAT, TSEncoding.PLAIN,
+            CompressionType.UNCOMPRESSED, null);
+    IoTDB.metaManager
+        .createTimeseries(new PartialPath("root.sg.d1.s4"), TSDataType.DOUBLE, TSEncoding.PLAIN,
+            CompressionType.UNCOMPRESSED, null);
+    IoTDB.metaManager
+        .createTimeseries(new PartialPath("root.sg.d1.s5"), TSDataType.BOOLEAN, TSEncoding.PLAIN,
+            CompressionType.UNCOMPRESSED, null);
+    IoTDB.metaManager
+        .createTimeseries(new PartialPath("root.sg.d1.s6"), TSDataType.TEXT, TSEncoding.PLAIN,
+            CompressionType.UNCOMPRESSED, null);
+  }
+
+  private static void generateData() {
+    try (Connection connection = DriverManager.getConnection(
+        Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+      for (String dataGenerationSql : INSERTION_SQLS) {
+        statement.execute(dataGenerationSql);
+      }
+    } catch (SQLException throwable) {
+      fail(throwable.getMessage());
+    }
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvironmentUtils.cleanEnv();
+  }
+
+  @Test
+  public void testMathFunctions() {
+    testMathFunction("sin", Math::sin);
+    testMathFunction("cos", Math::cos);
+    testMathFunction("tan", Math::tan);
+    testMathFunction("asin", Math::asin);
+    testMathFunction("acos", Math::acos);
+    testMathFunction("atan", Math::atan);
+    testMathFunction("degrees", Math::toDegrees);
+    testMathFunction("radians", Math::toRadians);
+    testMathFunction("abs", Math::abs);
+    testMathFunction("sign", Math::signum);
+    testMathFunction("ceil", Math::ceil);
+    testMathFunction("floor", Math::floor);
+    testMathFunction("round", Math::rint);
+    testMathFunction("exp", Math::exp);
+    testMathFunction("ln", Math::log);
+    testMathFunction("log10", Math::log10);
+    testMathFunction("sqrt", Math::sqrt);
+  }
+
+  private interface MathFunctionProxy {
+
+    double invoke(double x);
+  }
+
+  private void testMathFunction(String functionName, MathFunctionProxy functionProxy) {
+    try (Statement statement = DriverManager.getConnection(
+        Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root").createStatement()) {
+      ResultSet resultSet = statement.executeQuery(String
+          .format("select %s(s1), %s(s2), %s(s3), %s(s4) from root.sg.d1", functionName,
+              functionName, functionName, functionName));
+
+      int columnCount = resultSet.getMetaData().getColumnCount();
+      assertEquals(1 + 4, columnCount);
+
+      for (int i = 0; i < INSERTION_SQLS.length; ++i) {
+        resultSet.next();
+        for (int j = 0; j < 4; ++j) {
+          double expected = functionProxy.invoke(i);
+          double actual = Double.parseDouble(resultSet.getString(2 + j));
+          assertEquals(expected, actual, E);
+        }
+      }
+    } catch (SQLException throwable) {
+      fail(throwable.getMessage());
+    }
+  }
+
+  @Test
+  public void testSelectorFunctions() {
+    final String TOP_K = "TOP_K";
+    final String BOTTOM_K = "BOTTOM_K";
+    final String K = "'k'='2'";
+
+    try (Statement statement = DriverManager.getConnection(
+        Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root").createStatement()) {
+      ResultSet resultSet = statement.executeQuery(String.format(
+          "select %s(s1, %s), %s(s2, %s), %s(s3, %s), %s(s4, %s), %s(s6, %s) from root.sg.d1",
+          TOP_K, K, TOP_K, K, TOP_K, K, TOP_K, K, TOP_K, K));
+
+      int columnCount = resultSet.getMetaData().getColumnCount();
+      assertEquals(1 + 5, columnCount);
+
+      for (int i = INSERTION_SQLS.length - 2; i < INSERTION_SQLS.length; ++i) {
+        resultSet.next();
+        for (int j = 0; j < 5; ++j) {
+          assertEquals(i, Double.parseDouble(resultSet.getString(2 + j)), E);
+        }
+      }
+    } catch (SQLException throwable) {
+      fail(throwable.getMessage());
+    }
+
+    try (Statement statement = DriverManager.getConnection(
+        Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root").createStatement()) {
+      ResultSet resultSet = statement.executeQuery(String.format(
+          "select %s(s1, %s), %s(s2, %s), %s(s3, %s), %s(s4, %s), %s(s6, %s) from root.sg.d1",
+          BOTTOM_K, K, BOTTOM_K, K, BOTTOM_K, K, BOTTOM_K, K, BOTTOM_K, K));
+
+      int columnCount = resultSet.getMetaData().getColumnCount();
+      assertEquals(1 + 5, columnCount);
+
+      for (int i = 0; i < 2; ++i) {
+        resultSet.next();
+        for (int j = 0; j < 5; ++j) {
+          assertEquals(i, Double.parseDouble(resultSet.getString(2 + j)), E);
+        }
+      }
+    } catch (SQLException throwable) {
+      fail(throwable.getMessage());
+    }
+  }
+
+  @Test
+  public void testStringProcessingFunctions() {
+    try (Statement statement = DriverManager.getConnection(
+        Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root").createStatement()) {
+      ResultSet resultSet = statement.executeQuery(
+          "select STRING_CONTAINS(s6, 's'='0'), STRING_MATCHES(s6, 'regex'='\\d') from root.sg.d1");
+
+      int columnCount = resultSet.getMetaData().getColumnCount();
+      assertEquals(1 + 2, columnCount);
+
+      for (int i = 0; i < INSERTION_SQLS.length; ++i) {
+        resultSet.next();
+        if (i == 0) {
+          assertTrue(Boolean.parseBoolean(resultSet.getString(2)));
+        } else {
+          assertFalse(Boolean.parseBoolean(resultSet.getString(2)));
+        }
+        assertTrue(Boolean.parseBoolean(resultSet.getString(2 + 1)));
+      }
+    } catch (SQLException throwable) {
+      fail(throwable.getMessage());
+    }
+  }
+
+  @Test
+  public void testVariationTrendCalculationFunctions() {
+    testVariationTrendCalculationFunction("TIME_DIFFERENCE", 2);
+    testVariationTrendCalculationFunction("DIFFERENCE", 1);
+    testVariationTrendCalculationFunction("NON_NEGATIVE_DIFFERENCE", 1);
+    testVariationTrendCalculationFunction("DERIVATIVE", 0.5);
+    testVariationTrendCalculationFunction("NON_NEGATIVE_DERIVATIVE", 0.5);
+  }
+
+  public void testVariationTrendCalculationFunction(String functionName, double expected) {
+    try (Statement statement = DriverManager.getConnection(
+        Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root").createStatement()) {
+      ResultSet resultSet = statement.executeQuery(String
+          .format("select %s(s1), %s(s2), %s(s3), %s(s4) from root.sg.d1", functionName,
+              functionName, functionName, functionName));
+
+      int columnCount = resultSet.getMetaData().getColumnCount();
+      assertEquals(1 + 4, columnCount);
+
+      for (int i = 0; i < INSERTION_SQLS.length - 1; ++i) {
+        resultSet.next();
+        for (int j = 0; j < 4; ++j) {
+          assertEquals(expected, Double.parseDouble(resultSet.getString(2 + j)), E);
+        }
+      }
+    } catch (SQLException throwable) {
+      fail(throwable.getMessage());
+    }
+  }
+}
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Accumulator.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Accumulator.java
index b892e15..e269035 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Accumulator.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Accumulator.java
@@ -46,7 +46,6 @@ public class Accumulator implements UDTF {
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Accumulator#beforeStart");
     configurations.setOutputDataType(TSDataType.INT32);
     switch (parameters.getStringOrDefault(ACCESS_STRATEGY_KEY, ACCESS_STRATEGY_ROW_BY_ROW)) {
       case ACCESS_STRATEGY_SLIDING_SIZE:
@@ -82,9 +81,4 @@ public class Accumulator implements UDTF {
       collector.putInt(rowWindow.getRow(0).getTime(), accumulator);
     }
   }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Accumulator#beforeDestroy");
-  }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java
index 4b46425..3d94fcc 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Adder.java
@@ -45,7 +45,6 @@ public class Adder implements UDTF {
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Adder#beforeStart");
     addend = parameters.getFloatOrDefault("addend", 0);
     configurations
         .setOutputDataType(TSDataType.INT64)
@@ -81,9 +80,4 @@ public class Adder implements UDTF {
     }
     return value;
   }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Adder#beforeDestroy");
-  }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Counter.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Counter.java
index 553d801..cb9e38b 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Counter.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Counter.java
@@ -37,7 +37,6 @@ public class Counter implements UDTF {
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Counter#beforeStart");
     configurations.setOutputDataType(TSDataType.INT32);
     switch (parameters.getStringOrDefault(ACCESS_STRATEGY_KEY, ACCESS_STRATEGY_ROW_BY_ROW)) {
       case ACCESS_STRATEGY_SLIDING_SIZE:
@@ -68,9 +67,4 @@ public class Counter implements UDTF {
       collector.putInt(rowWindow.getRow(0).getTime(), rowWindow.windowSize());
     }
   }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Counter#beforeDestroy");
-  }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java
index eea5abb..9c53e3e 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Max.java
@@ -43,7 +43,6 @@ public class Max implements UDTF {
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Max#beforeStart");
     configurations
         .setOutputDataType(TSDataType.INT32)
         .setAccessStrategy(new RowByRowAccessStrategy());
@@ -64,9 +63,4 @@ public class Max implements UDTF {
       collector.putInt(time, value);
     }
   }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Max#beforeDestroy");
-  }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
index 75b9e21..3b44b83 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/Multiplier.java
@@ -42,7 +42,6 @@ public class Multiplier implements UDTF {
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("Multiplier#beforeStart");
     a = parameters.getLongOrDefault("a", 0);
     b = parameters.getLongOrDefault("b", 0);
     configurations
@@ -54,9 +53,4 @@ public class Multiplier implements UDTF {
   public void transform(Row row, PointCollector collector) throws Exception {
     collector.putLong(row.getTime(), row.getLong(0) * a * b);
   }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("Multiplier#beforeDestroy");
-  }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester0.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester0.java
index 7cfcae1..97fd26c 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester0.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester0.java
@@ -31,7 +31,6 @@ public class SlidingSizeWindowConstructorTester0 implements UDTF {
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("SlidingSizeWindowConstructorTester0#beforeStart");
     int windowSize = parameters.getInt("windowSize");
     int slidingStep = parameters.getInt("slidingStep");
     configurations
@@ -45,9 +44,4 @@ public class SlidingSizeWindowConstructorTester0 implements UDTF {
       collector.putInt(rowWindow.getRow(0).getTime(), rowWindow.windowSize());
     }
   }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("SlidingSizeWindowConstructorTester0#beforeDestroy");
-  }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester1.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester1.java
index 0ec5e3e..e5f10f8 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester1.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingSizeWindowConstructorTester1.java
@@ -41,7 +41,6 @@ public class SlidingSizeWindowConstructorTester1 implements UDTF {
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("SlidingSizeWindowConstructorTester1#beforeStart");
     consumptionPoint = parameters.getInt("consumptionPoint");
     configurations
         .setOutputDataType(TSDataType.INT32)
@@ -54,9 +53,4 @@ public class SlidingSizeWindowConstructorTester1 implements UDTF {
       collector.putInt(row.getTime(), row.getInt(0));
     }
   }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("SlidingSizeWindowConstructorTester1#beforeDestroy");
-  }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingTimeWindowConstructionTester.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingTimeWindowConstructionTester.java
index 49ed420..12c45e5 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingTimeWindowConstructionTester.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/SlidingTimeWindowConstructionTester.java
@@ -43,7 +43,6 @@ public class SlidingTimeWindowConstructionTester implements UDTF {
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("SlidingTimeWindowConstructionTester#beforeStart");
     long timeInterval = parameters.getLong(TIME_INTERVAL_KEY);
     configurations
         .setOutputDataType(TSDataType.INT32)
@@ -61,9 +60,4 @@ public class SlidingTimeWindowConstructionTester implements UDTF {
       collector.putInt(rowWindow.getRow(0).getTime(), accumulator);
     }
   }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("SlidingTimeWindowConstructionTester#beforeDestroy");
-  }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java b/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java
index d5d797f..bdd2d4e 100644
--- a/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java
+++ b/server/src/test/java/org/apache/iotdb/db/query/udf/example/TerminateTester.java
@@ -34,7 +34,6 @@ public class TerminateTester implements UDTF {
 
   @Override
   public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
-    System.out.println("TerminateTester#beforeStart");
     configurations
         .setOutputDataType(TSDataType.INT32)
         .setAccessStrategy(new RowByRowAccessStrategy());
@@ -56,9 +55,4 @@ public class TerminateTester implements UDTF {
       collector.putInt(maxTime + 1, count);
     }
   }
-
-  @Override
-  public void beforeDestroy() {
-    System.out.println("TerminateTester#beforeDestroy");
-  }
 }